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/clang-format.sh b/src/clang-format.sh
new file mode 100644
index 0000000..fbce6b9
--- /dev/null
+++ b/src/clang-format.sh
@@ -0,0 +1,2 @@
+clang-format -i -style=file include/flatbuffers/* src/*.cpp tests/test.cpp samples/*.cpp grpc/src/compiler/schema_interface.h grpc/tests/*.cpp
+git checkout include/flatbuffers/reflection_generated.h
diff --git a/src/code_generators.cpp b/src/code_generators.cpp
new file mode 100644
index 0000000..52ca305
--- /dev/null
+++ b/src/code_generators.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2016 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 "flatbuffers/code_generators.h"
+#include <assert.h>
+#include "flatbuffers/base.h"
+#include "flatbuffers/util.h"
+
+#include <cmath>
+
+#if defined(_MSC_VER)
+#  pragma warning(push)
+#  pragma warning(disable : 4127)  // C4127: conditional expression is constant
+#endif
+
+namespace flatbuffers {
+
+void CodeWriter::operator+=(std::string text) {
+  if (!ignore_ident_ && !text.empty()) AppendIdent(stream_);
+
+  while (true) {
+    auto begin = text.find("{{");
+    if (begin == std::string::npos) { break; }
+
+    auto end = text.find("}}");
+    if (end == std::string::npos || end < begin) { break; }
+
+    // Write all the text before the first {{ into the stream.
+    stream_.write(text.c_str(), begin);
+
+    // The key is between the {{ and }}.
+    const std::string key = text.substr(begin + 2, end - begin - 2);
+
+    // Find the value associated with the key.  If it exists, write the
+    // value into the stream, otherwise write the key itself into the stream.
+    auto iter = value_map_.find(key);
+    if (iter != value_map_.end()) {
+      const std::string &value = iter->second;
+      stream_ << value;
+    } else {
+      FLATBUFFERS_ASSERT(false && "could not find key");
+      stream_ << key;
+    }
+
+    // Update the text to everything after the }}.
+    text = text.substr(end + 2);
+  }
+  if (!text.empty() && string_back(text) == '\\') {
+    text.pop_back();
+    ignore_ident_ = true;
+    stream_ << text;
+  } else {
+    ignore_ident_ = false;
+    stream_ << text << std::endl;
+  }
+}
+
+void CodeWriter::AppendIdent(std::stringstream &stream) {
+  int lvl = cur_ident_lvl_;
+  while (lvl--) {
+    stream.write(pad_.c_str(), static_cast<std::streamsize>(pad_.size()));
+  }
+}
+
+const char *BaseGenerator::FlatBuffersGeneratedWarning() {
+  return "automatically generated by the FlatBuffers compiler,"
+         " do not modify";
+}
+
+std::string BaseGenerator::NamespaceDir(const Parser &parser,
+                                        const std::string &path,
+                                        const Namespace &ns) {
+  EnsureDirExists(path);
+  if (parser.opts.one_file) return path;
+  std::string namespace_dir = path;  // Either empty or ends in separator.
+  auto &namespaces = ns.components;
+  for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+    namespace_dir += *it + kPathSeparator;
+    EnsureDirExists(namespace_dir);
+  }
+  return namespace_dir;
+}
+
+std::string BaseGenerator::NamespaceDir(const Namespace &ns) const {
+  return BaseGenerator::NamespaceDir(parser_, path_, ns);
+}
+
+std::string BaseGenerator::FullNamespace(const char *separator,
+                                         const Namespace &ns) {
+  std::string namespace_name;
+  auto &namespaces = ns.components;
+  for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+    if (namespace_name.length()) namespace_name += separator;
+    namespace_name += *it;
+  }
+  return namespace_name;
+}
+
+std::string BaseGenerator::LastNamespacePart(const Namespace &ns) {
+  if (!ns.components.empty())
+    return ns.components.back();
+  else
+    return std::string("");
+}
+
+// Ensure that a type is prefixed with its namespace.
+std::string BaseGenerator::WrapInNameSpace(const Namespace *ns,
+                                           const std::string &name) const {
+  std::string qualified_name = qualifying_start_;
+  for (auto it = ns->components.begin(); it != ns->components.end(); ++it)
+    qualified_name += *it + qualifying_separator_;
+  return qualified_name + name;
+}
+
+std::string BaseGenerator::WrapInNameSpace(const Definition &def) const {
+  return WrapInNameSpace(def.defined_namespace, def.name);
+}
+
+std::string BaseGenerator::GetNameSpace(const Definition &def) const {
+  const Namespace *ns = def.defined_namespace;
+  if (CurrentNameSpace() == ns) return "";
+  std::string qualified_name = qualifying_start_;
+  for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
+    qualified_name += *it;
+    if ((it + 1) != ns->components.end()) {
+      qualified_name += qualifying_separator_;
+    }
+  }
+
+  return qualified_name;
+}
+
+// Generate a documentation comment, if available.
+void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
+                const CommentConfig *config, const char *prefix) {
+  if (dc.begin() == dc.end()) {
+    // Don't output empty comment blocks with 0 lines of comment content.
+    return;
+  }
+
+  std::string &code = *code_ptr;
+  if (config != nullptr && config->first_line != nullptr) {
+    code += std::string(prefix) + std::string(config->first_line) + "\n";
+  }
+  std::string line_prefix =
+      std::string(prefix) +
+      ((config != nullptr && config->content_line_prefix != nullptr)
+           ? config->content_line_prefix
+           : "///");
+  for (auto it = dc.begin(); it != dc.end(); ++it) {
+    code += line_prefix + *it + "\n";
+  }
+  if (config != nullptr && config->last_line != nullptr) {
+    code += std::string(prefix) + std::string(config->last_line) + "\n";
+  }
+}
+
+template<typename T>
+std::string FloatConstantGenerator::GenFloatConstantImpl(
+    const FieldDef &field) const {
+  const auto &constant = field.value.constant;
+  T v;
+  auto done = StringToNumber(constant.c_str(), &v);
+  FLATBUFFERS_ASSERT(done);
+  if (done) {
+#if (!defined(_MSC_VER) || (_MSC_VER >= 1800))
+    if (std::isnan(v)) return NaN(v);
+    if (std::isinf(v)) return Inf(v);
+#endif
+    return Value(v, constant);
+  }
+  return "#";  // compile time error
+}
+
+std::string FloatConstantGenerator::GenFloatConstant(
+    const FieldDef &field) const {
+  switch (field.value.type.base_type) {
+    case BASE_TYPE_FLOAT: return GenFloatConstantImpl<float>(field);
+    case BASE_TYPE_DOUBLE: return GenFloatConstantImpl<double>(field);
+    default: {
+      FLATBUFFERS_ASSERT(false);
+      return "INVALID_BASE_TYPE";
+    }
+  };
+}
+
+TypedFloatConstantGenerator::TypedFloatConstantGenerator(
+    const char *double_prefix, const char *single_prefix,
+    const char *nan_number, const char *pos_inf_number,
+    const char *neg_inf_number)
+    : double_prefix_(double_prefix),
+      single_prefix_(single_prefix),
+      nan_number_(nan_number),
+      pos_inf_number_(pos_inf_number),
+      neg_inf_number_(neg_inf_number) {}
+
+std::string TypedFloatConstantGenerator::MakeNaN(
+    const std::string &prefix) const {
+  return prefix + nan_number_;
+}
+std::string TypedFloatConstantGenerator::MakeInf(
+    bool neg, const std::string &prefix) const {
+  if (neg)
+    return !neg_inf_number_.empty() ? (prefix + neg_inf_number_)
+                                    : ("-" + prefix + pos_inf_number_);
+  else
+    return prefix + pos_inf_number_;
+}
+
+std::string TypedFloatConstantGenerator::Value(double v,
+                                               const std::string &src) const {
+  (void)v;
+  return src;
+}
+
+std::string TypedFloatConstantGenerator::Inf(double v) const {
+  return MakeInf(v < 0, double_prefix_);
+}
+
+std::string TypedFloatConstantGenerator::NaN(double v) const {
+  (void)v;
+  return MakeNaN(double_prefix_);
+}
+
+std::string TypedFloatConstantGenerator::Value(float v,
+                                               const std::string &src) const {
+  (void)v;
+  return src + "f";
+}
+
+std::string TypedFloatConstantGenerator::Inf(float v) const {
+  return MakeInf(v < 0, single_prefix_);
+}
+
+std::string TypedFloatConstantGenerator::NaN(float v) const {
+  (void)v;
+  return MakeNaN(single_prefix_);
+}
+
+SimpleFloatConstantGenerator::SimpleFloatConstantGenerator(
+    const char *nan_number, const char *pos_inf_number,
+    const char *neg_inf_number)
+    : nan_number_(nan_number),
+      pos_inf_number_(pos_inf_number),
+      neg_inf_number_(neg_inf_number) {}
+
+std::string SimpleFloatConstantGenerator::Value(double v,
+                                                const std::string &src) const {
+  (void)v;
+  return src;
+}
+
+std::string SimpleFloatConstantGenerator::Inf(double v) const {
+  return (v < 0) ? neg_inf_number_ : pos_inf_number_;
+}
+
+std::string SimpleFloatConstantGenerator::NaN(double v) const {
+  (void)v;
+  return nan_number_;
+}
+
+std::string SimpleFloatConstantGenerator::Value(float v,
+                                                const std::string &src) const {
+  return this->Value(static_cast<double>(v), src);
+}
+
+std::string SimpleFloatConstantGenerator::Inf(float v) const {
+  return this->Inf(static_cast<double>(v));
+}
+
+std::string SimpleFloatConstantGenerator::NaN(float v) const {
+  return this->NaN(static_cast<double>(v));
+}
+
+}  // namespace flatbuffers
+
+#if defined(_MSC_VER)
+#  pragma warning(pop)
+#endif
diff --git a/src/flatc.cpp b/src/flatc.cpp
new file mode 100644
index 0000000..e1236bd
--- /dev/null
+++ b/src/flatc.cpp
@@ -0,0 +1,489 @@
+/*
+ * Copyright 2014 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 "flatbuffers/flatc.h"
+
+#include <list>
+
+namespace flatbuffers {
+
+const char *FLATC_VERSION() { return FLATBUFFERS_VERSION(); }
+
+void FlatCompiler::ParseFile(
+    flatbuffers::Parser &parser, const std::string &filename,
+    const std::string &contents,
+    std::vector<const char *> &include_directories) const {
+  auto local_include_directory = flatbuffers::StripFileName(filename);
+  include_directories.push_back(local_include_directory.c_str());
+  include_directories.push_back(nullptr);
+  if (!parser.Parse(contents.c_str(), &include_directories[0],
+                    filename.c_str())) {
+    Error(parser.error_, false, false);
+  }
+  if (!parser.error_.empty()) { Warn(parser.error_, false); }
+  include_directories.pop_back();
+  include_directories.pop_back();
+}
+
+void FlatCompiler::LoadBinarySchema(flatbuffers::Parser &parser,
+                                    const std::string &filename,
+                                    const std::string &contents) {
+  if (!parser.Deserialize(reinterpret_cast<const uint8_t *>(contents.c_str()),
+      contents.size())) {
+    Error("failed to load binary schema: " + filename, false, false);
+  }
+}
+
+void FlatCompiler::Warn(const std::string &warn, bool show_exe_name) const {
+  params_.warn_fn(this, warn, show_exe_name);
+}
+
+void FlatCompiler::Error(const std::string &err, bool usage,
+                         bool show_exe_name) const {
+  params_.error_fn(this, err, usage, show_exe_name);
+}
+
+std::string FlatCompiler::GetUsageString(const char *program_name) const {
+  std::stringstream ss;
+  ss << "Usage: " << program_name << " [OPTION]... FILE... [-- FILE...]\n";
+  for (size_t i = 0; i < params_.num_generators; ++i) {
+    const Generator &g = params_.generators[i];
+
+    std::stringstream full_name;
+    full_name << std::setw(12) << std::left << g.generator_opt_long;
+    const char *name = g.generator_opt_short ? g.generator_opt_short : "  ";
+    const char *help = g.generator_help;
+
+    ss << "  " << full_name.str() << " " << name << "    " << help << ".\n";
+  }
+  // clang-format off
+  ss <<
+    "  -o PATH            Prefix PATH to all generated files.\n"
+    "  -I PATH            Search for includes in the specified path.\n"
+    "  -M                 Print make rules for generated files.\n"
+    "  --version          Print the version number of flatc and exit.\n"
+    "  --strict-json      Strict JSON: field names must be / will be quoted,\n"
+    "                     no trailing commas in tables/vectors.\n"
+    "  --allow-non-utf8   Pass non-UTF-8 input through parser and emit nonstandard\n"
+    "                     \\x escapes in JSON. (Default is to raise parse error on\n"
+    "                     non-UTF-8 input.)\n"
+    "  --natural-utf8     Output strings with UTF-8 as human-readable strings.\n"
+    "                     By default, UTF-8 characters are printed as \\uXXXX escapes.\n"
+    "  --defaults-json    Output fields whose value is the default when\n"
+    "                     writing JSON\n"
+    "  --unknown-json     Allow fields in JSON that are not defined in the\n"
+    "                     schema. These fields will be discared when generating\n"
+    "                     binaries.\n"
+    "  --no-prefix        Don\'t prefix enum values with the enum type in C++.\n"
+    "  --scoped-enums     Use C++11 style scoped and strongly typed enums.\n"
+    "                     also implies --no-prefix.\n"
+    "  --gen-includes     (deprecated), this is the default behavior.\n"
+    "                     If the original behavior is required (no include\n"
+    "                     statements) use --no-includes.\n"
+    "  --no-includes      Don\'t generate include statements for included\n"
+    "                     schemas the generated file depends on (C++).\n"
+    "  --gen-mutable      Generate accessors that can mutate buffers in-place.\n"
+    "  --gen-onefile      Generate single output file for C# and Go.\n"
+    "  --gen-name-strings Generate type name functions for C++.\n"
+    "  --gen-object-api   Generate an additional object-based API.\n"
+    "  --gen-compare      Generate operator== for object-based API types.\n"
+    "  --gen-nullable     Add Clang _Nullable for C++ pointer. or @Nullable for Java\n"
+    "  --gen-generated    Add @Generated annotation for Java\n"
+    "  --gen-all          Generate not just code for the current schema files,\n"
+    "                     but for all files it includes as well.\n"
+    "                     If the language uses a single file for output (by default\n"
+    "                     the case for C++ and JS), all code will end up in this one\n"
+    "                     file.\n"
+    "  --cpp-include      Adds an #include in generated file.\n"
+    "  --cpp-ptr-type T   Set object API pointer type (default std::unique_ptr).\n"
+    "  --cpp-str-type T   Set object API string type (default std::string).\n"
+    "                     T::c_str(), T::length() and T::empty() must be supported.\n"
+    "                     The custom type also needs to be constructible from std::string\n"
+    "                     (see the --cpp-str-flex-ctor option to change this behavior).\n"
+    "  --cpp-str-flex-ctor Don't construct custom string types by passing std::string\n"
+    "                     from Flatbuffers, but (char* + length).\n"
+    "  --object-prefix    Customise class prefix for C++ object-based API.\n"
+    "  --object-suffix    Customise class suffix for C++ object-based API.\n"
+    "                     Default value is \"T\".\n"
+    "  --no-js-exports    Removes Node.js style export lines in JS.\n"
+    "  --goog-js-export   Uses goog.exports* for closure compiler exporting in JS.\n"
+    "  --es6-js-export    Uses ECMAScript 6 export style lines in JS.\n"
+    "  --go-namespace     Generate the overrided namespace in Golang.\n"
+    "  --go-import        Generate the overrided import for flatbuffers in Golang\n"
+    "                     (default is \"github.com/google/flatbuffers/go\").\n"
+    "  --raw-binary       Allow binaries without file_indentifier to be read.\n"
+    "                     This may crash flatc given a mismatched schema.\n"
+    "  --size-prefixed    Input binaries are size prefixed buffers.\n"
+    "  --proto            Input is a .proto, translate to .fbs.\n"
+    "  --oneof-union      Translate .proto oneofs to flatbuffer unions.\n"
+    "  --grpc             Generate GRPC interfaces for the specified languages.\n"
+    "  --schema           Serialize schemas instead of JSON (use with -b).\n"
+    "  --bfbs-comments    Add doc comments to the binary schema files.\n"
+    "  --bfbs-builtins    Add builtin attributes to the binary schema files.\n"
+    "  --conform FILE     Specify a schema the following schemas should be\n"
+    "                     an evolution of. Gives errors if not.\n"
+    "  --conform-includes Include path for the schema given with --conform PATH\n"
+    "  --include-prefix   Prefix this path to any generated include statements.\n"
+    "    PATH\n"
+    "  --keep-prefix      Keep original prefix of schema include statement.\n"
+    "  --no-fb-import     Don't include flatbuffers import statement for TypeScript.\n"
+    "  --no-ts-reexport   Don't re-export imported dependencies for TypeScript.\n"
+    "  --short-names      Use short function names for JS and TypeScript.\n"
+    "  --reflect-types    Add minimal type reflection to code generation.\n"
+    "  --reflect-names    Add minimal type/name reflection.\n"
+    "  --root-type T      Select or override the default root_type\n"
+    "  --force-defaults   Emit default values in binary output from JSON\n"
+    "  --force-empty      When serializing from object API representation,\n"
+    "                     force strings and vectors to empty rather than null.\n"
+    "FILEs may be schemas (must end in .fbs), binary schemas (must end in .bfbs),\n"
+    "or JSON files (conforming to preceding schema). FILEs after the -- must be\n"
+    "binary flatbuffer format files.\n"
+    "Output files are named using the base file name of the input,\n"
+    "and written to the current directory or the path given by -o.\n"
+    "example: " << program_name << " -c -b schema1.fbs schema2.fbs data.json\n";
+  // clang-format on
+  return ss.str();
+}
+
+int FlatCompiler::Compile(int argc, const char **argv) {
+  if (params_.generators == nullptr || params_.num_generators == 0) {
+    return 0;
+  }
+
+  flatbuffers::IDLOptions opts;
+  std::string output_path;
+
+  bool any_generator = false;
+  bool print_make_rules = false;
+  bool raw_binary = false;
+  bool schema_binary = false;
+  bool grpc_enabled = false;
+  std::vector<std::string> filenames;
+  std::list<std::string> include_directories_storage;
+  std::vector<const char *> include_directories;
+  std::vector<const char *> conform_include_directories;
+  std::vector<bool> generator_enabled(params_.num_generators, false);
+  size_t binary_files_from = std::numeric_limits<size_t>::max();
+  std::string conform_to_schema;
+
+  for (int argi = 0; argi < argc; argi++) {
+    std::string arg = argv[argi];
+    if (arg[0] == '-') {
+      if (filenames.size() && arg[1] != '-')
+        Error("invalid option location: " + arg, true);
+      if (arg == "-o") {
+        if (++argi >= argc) Error("missing path following: " + arg, true);
+        output_path = flatbuffers::ConCatPathFileName(
+            flatbuffers::PosixPath(argv[argi]), "");
+      } else if (arg == "-I") {
+        if (++argi >= argc) Error("missing path following" + arg, true);
+        include_directories_storage.push_back(
+            flatbuffers::PosixPath(argv[argi]));
+        include_directories.push_back(
+            include_directories_storage.back().c_str());
+      } else if (arg == "--conform") {
+        if (++argi >= argc) Error("missing path following" + arg, true);
+        conform_to_schema = flatbuffers::PosixPath(argv[argi]);
+      } else if (arg == "--conform-includes") {
+        if (++argi >= argc) Error("missing path following" + arg, true);
+        include_directories_storage.push_back(
+            flatbuffers::PosixPath(argv[argi]));
+        conform_include_directories.push_back(
+            include_directories_storage.back().c_str());
+      } else if (arg == "--include-prefix") {
+        if (++argi >= argc) Error("missing path following" + arg, true);
+        opts.include_prefix = flatbuffers::ConCatPathFileName(
+            flatbuffers::PosixPath(argv[argi]), "");
+      } else if (arg == "--keep-prefix") {
+        opts.keep_include_path = true;
+      } else if (arg == "--strict-json") {
+        opts.strict_json = true;
+      } else if (arg == "--allow-non-utf8") {
+        opts.allow_non_utf8 = true;
+      } else if (arg == "--natural-utf8") {
+        opts.natural_utf8 = true;
+      } else if (arg == "--no-js-exports") {
+        opts.skip_js_exports = true;
+      } else if (arg == "--goog-js-export") {
+        opts.use_goog_js_export_format = true;
+        opts.use_ES6_js_export_format = false;
+      } else if (arg == "--es6-js-export") {
+        opts.use_goog_js_export_format = false;
+        opts.use_ES6_js_export_format = true;
+      } else if (arg == "--go-namespace") {
+        if (++argi >= argc) Error("missing golang namespace" + arg, true);
+        opts.go_namespace = argv[argi];
+      } else if (arg == "--go-import") {
+        if (++argi >= argc) Error("missing golang import" + arg, true);
+        opts.go_import = argv[argi];
+      } else if (arg == "--defaults-json") {
+        opts.output_default_scalars_in_json = true;
+      } else if (arg == "--unknown-json") {
+        opts.skip_unexpected_fields_in_json = true;
+      } else if (arg == "--no-prefix") {
+        opts.prefixed_enums = false;
+      } else if (arg == "--scoped-enums") {
+        opts.prefixed_enums = false;
+        opts.scoped_enums = true;
+      } else if (arg == "--no-union-value-namespacing") {
+        opts.union_value_namespacing = false;
+      } else if (arg == "--gen-mutable") {
+        opts.mutable_buffer = true;
+      } else if (arg == "--gen-name-strings") {
+        opts.generate_name_strings = true;
+      } else if (arg == "--gen-object-api") {
+        opts.generate_object_based_api = true;
+      } else if (arg == "--gen-compare") {
+        opts.gen_compare = true;
+      } else if (arg == "--cpp-include") {
+        if (++argi >= argc) Error("missing include following" + arg, true);
+        opts.cpp_includes.push_back(argv[argi]);
+      } else if (arg == "--cpp-ptr-type") {
+        if (++argi >= argc) Error("missing type following" + arg, true);
+        opts.cpp_object_api_pointer_type = argv[argi];
+      } else if (arg == "--cpp-str-type") {
+        if (++argi >= argc) Error("missing type following" + arg, true);
+        opts.cpp_object_api_string_type = argv[argi];
+      } else if (arg == "--cpp-str-flex-ctor") {
+        opts.cpp_object_api_string_flexible_constructor = true;
+      } else if (arg == "--gen-nullable") {
+        opts.gen_nullable = true;
+      } else if (arg == "--gen-generated") {
+        opts.gen_generated = true;
+      } else if (arg == "--object-prefix") {
+        if (++argi >= argc) Error("missing prefix following" + arg, true);
+        opts.object_prefix = argv[argi];
+      } else if (arg == "--object-suffix") {
+        if (++argi >= argc) Error("missing suffix following" + arg, true);
+        opts.object_suffix = argv[argi];
+      } else if (arg == "--gen-all") {
+        opts.generate_all = true;
+        opts.include_dependence_headers = false;
+      } else if (arg == "--gen-includes") {
+        // Deprecated, remove this option some time in the future.
+        printf("warning: --gen-includes is deprecated (it is now default)\n");
+      } else if (arg == "--no-includes") {
+        opts.include_dependence_headers = false;
+      } else if (arg == "--gen-onefile") {
+        opts.one_file = true;
+      } else if (arg == "--raw-binary") {
+        raw_binary = true;
+      } else if (arg == "--size-prefixed") {
+        opts.size_prefixed = true;
+      } else if (arg == "--") {  // Separator between text and binary inputs.
+        binary_files_from = filenames.size();
+      } else if (arg == "--proto") {
+        opts.proto_mode = true;
+      } else if (arg == "--oneof-union") {
+        opts.proto_oneof_union = true;
+      } else if (arg == "--schema") {
+        schema_binary = true;
+      } else if (arg == "-M") {
+        print_make_rules = true;
+      } else if (arg == "--version") {
+        printf("flatc version %s\n", FLATC_VERSION());
+        exit(0);
+      } else if (arg == "--grpc") {
+        grpc_enabled = true;
+      } else if (arg == "--bfbs-comments") {
+        opts.binary_schema_comments = true;
+      } else if (arg == "--bfbs-builtins") {
+        opts.binary_schema_builtins = true;
+      } else if (arg == "--no-fb-import") {
+        opts.skip_flatbuffers_import = true;
+      } else if (arg == "--no-ts-reexport") {
+        opts.reexport_ts_modules = false;
+      } else if (arg == "--short-names") {
+        opts.js_ts_short_names = true;
+      } else if (arg == "--reflect-types") {
+        opts.mini_reflect = IDLOptions::kTypes;
+      } else if (arg == "--reflect-names") {
+        opts.mini_reflect = IDLOptions::kTypesAndNames;
+      } else if (arg == "--root-type") {
+        if (++argi >= argc) Error("missing type following" + arg, true);
+        opts.root_type = argv[argi];
+      } else if (arg == "--force-defaults") {
+        opts.force_defaults = true;
+      } else if (arg == "--force-empty") {
+        opts.set_empty_to_null = false;
+      } else {
+        for (size_t i = 0; i < params_.num_generators; ++i) {
+          if (arg == params_.generators[i].generator_opt_long ||
+              (params_.generators[i].generator_opt_short &&
+               arg == params_.generators[i].generator_opt_short)) {
+            generator_enabled[i] = true;
+            any_generator = true;
+            opts.lang_to_generate |= params_.generators[i].lang;
+            goto found;
+          }
+        }
+        Error("unknown commandline argument: " + arg, true);
+      found:;
+      }
+    } else {
+      filenames.push_back(flatbuffers::PosixPath(argv[argi]));
+    }
+  }
+
+  if (!filenames.size()) Error("missing input files", false, true);
+
+  if (opts.proto_mode) {
+    if (any_generator)
+      Error("cannot generate code directly from .proto files", true);
+  } else if (!any_generator && conform_to_schema.empty()) {
+    Error("no options: specify at least one generator.", true);
+  }
+
+  flatbuffers::Parser conform_parser;
+  if (!conform_to_schema.empty()) {
+    std::string contents;
+    if (!flatbuffers::LoadFile(conform_to_schema.c_str(), true, &contents))
+      Error("unable to load schema: " + conform_to_schema);
+
+    if (flatbuffers::GetExtension(conform_to_schema) ==
+        reflection::SchemaExtension()) {
+      LoadBinarySchema(conform_parser, conform_to_schema, contents);
+    } else {
+      ParseFile(conform_parser, conform_to_schema, contents,
+                conform_include_directories);
+    }
+  }
+
+  std::unique_ptr<flatbuffers::Parser> parser(new flatbuffers::Parser(opts));
+
+  for (auto file_it = filenames.begin(); file_it != filenames.end();
+       ++file_it) {
+    auto &filename = *file_it;
+    std::string contents;
+    if (!flatbuffers::LoadFile(filename.c_str(), true, &contents))
+      Error("unable to load file: " + filename);
+
+    bool is_binary =
+        static_cast<size_t>(file_it - filenames.begin()) >= binary_files_from;
+    auto ext = flatbuffers::GetExtension(filename);
+    auto is_schema = ext == "fbs" || ext == "proto";
+    auto is_binary_schema = ext == reflection::SchemaExtension();
+    if (is_binary) {
+      parser->builder_.Clear();
+      parser->builder_.PushFlatBuffer(
+          reinterpret_cast<const uint8_t *>(contents.c_str()),
+          contents.length());
+      if (!raw_binary) {
+        // Generally reading binaries that do not correspond to the schema
+        // will crash, and sadly there's no way around that when the binary
+        // does not contain a file identifier.
+        // We'd expect that typically any binary used as a file would have
+        // such an identifier, so by default we require them to match.
+        if (!parser->file_identifier_.length()) {
+          Error("current schema has no file_identifier: cannot test if \"" +
+                filename +
+                "\" matches the schema, use --raw-binary to read this file"
+                " anyway.");
+        } else if (!flatbuffers::BufferHasIdentifier(
+                       contents.c_str(), parser->file_identifier_.c_str(), opts.size_prefixed)) {
+          Error("binary \"" + filename +
+                "\" does not have expected file_identifier \"" +
+                parser->file_identifier_ +
+                "\", use --raw-binary to read this file anyway.");
+        }
+      }
+    } else {
+      // Check if file contains 0 bytes.
+      if (!is_binary_schema && contents.length() != strlen(contents.c_str())) {
+        Error("input file appears to be binary: " + filename, true);
+      }
+      if (is_schema) {
+        // If we're processing multiple schemas, make sure to start each
+        // one from scratch. If it depends on previous schemas it must do
+        // so explicitly using an include.
+        parser.reset(new flatbuffers::Parser(opts));
+      }
+      if (is_binary_schema) {
+        LoadBinarySchema(*parser.get(), filename, contents);
+      } else {
+        ParseFile(*parser.get(), filename, contents, include_directories);
+        if (!is_schema && !parser->builder_.GetSize()) {
+          // If a file doesn't end in .fbs, it must be json/binary. Ensure we
+          // didn't just parse a schema with a different extension.
+          Error("input file is neither json nor a .fbs (schema) file: " +
+                    filename,
+                true);
+        }
+      }
+      if ((is_schema || is_binary_schema) && !conform_to_schema.empty()) {
+        auto err = parser->ConformTo(conform_parser);
+        if (!err.empty()) Error("schemas don\'t conform: " + err);
+      }
+      if (schema_binary) {
+        parser->Serialize();
+        parser->file_extension_ = reflection::SchemaExtension();
+      }
+    }
+
+    std::string filebase =
+        flatbuffers::StripPath(flatbuffers::StripExtension(filename));
+
+    for (size_t i = 0; i < params_.num_generators; ++i) {
+      parser->opts.lang = params_.generators[i].lang;
+      if (generator_enabled[i]) {
+        if (!print_make_rules) {
+          flatbuffers::EnsureDirExists(output_path);
+          if ((!params_.generators[i].schema_only ||
+               (is_schema || is_binary_schema)) &&
+              !params_.generators[i].generate(*parser.get(), output_path,
+                                              filebase)) {
+            Error(std::string("Unable to generate ") +
+                  params_.generators[i].lang_name + " for " + filebase);
+          }
+        } else {
+          std::string make_rule = params_.generators[i].make_rule(
+              *parser.get(), output_path, filename);
+          if (!make_rule.empty())
+            printf("%s\n",
+                   flatbuffers::WordWrap(make_rule, 80, " ", " \\").c_str());
+        }
+        if (grpc_enabled) {
+          if (params_.generators[i].generateGRPC != nullptr) {
+            if (!params_.generators[i].generateGRPC(*parser.get(), output_path,
+                                                    filebase)) {
+              Error(std::string("Unable to generate GRPC interface for") +
+                    params_.generators[i].lang_name);
+            }
+          } else {
+            Warn(std::string("GRPC interface generator not implemented for ") +
+                 params_.generators[i].lang_name);
+          }
+        }
+      }
+    }
+
+    if (!opts.root_type.empty()) {
+      if (!parser->SetRootType(opts.root_type.c_str()))
+        Error("unknown root type: " + opts.root_type);
+      else if (parser->root_struct_def_->fixed)
+        Error("root type must be a table");
+    }
+
+    if (opts.proto_mode) GenerateFBS(*parser.get(), output_path, filebase);
+
+    // We do not want to generate code for the definitions in this file
+    // in any files coming up next.
+    parser->MarkGenerated();
+  }
+  return 0;
+}
+
+}  // namespace flatbuffers
diff --git a/src/flatc_main.cpp b/src/flatc_main.cpp
new file mode 100644
index 0000000..72bb4a2
--- /dev/null
+++ b/src/flatc_main.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2017 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 "flatbuffers/flatc.h"
+#include "flatbuffers/util.h"
+
+static const char *g_program_name = nullptr;
+
+static void Warn(const flatbuffers::FlatCompiler *flatc,
+                 const std::string &warn, bool show_exe_name) {
+  (void)flatc;
+  if (show_exe_name) { printf("%s: ", g_program_name); }
+  printf("warning: %s\n", warn.c_str());
+}
+
+static void Error(const flatbuffers::FlatCompiler *flatc,
+                  const std::string &err, bool usage, bool show_exe_name) {
+  if (show_exe_name) { printf("%s: ", g_program_name); }
+  printf("error: %s\n", err.c_str());
+  if (usage) { printf("%s", flatc->GetUsageString(g_program_name).c_str()); }
+  exit(1);
+}
+
+int main(int argc, const char *argv[]) {
+  // Prevent Appveyor-CI hangs.
+  flatbuffers::SetupDefaultCRTReportMode();
+
+  g_program_name = argv[0];
+
+  const flatbuffers::FlatCompiler::Generator generators[] = {
+    { flatbuffers::GenerateBinary, "-b", "--binary", "binary", false, nullptr,
+      flatbuffers::IDLOptions::kBinary,
+      "Generate wire format binaries for any data definitions",
+      flatbuffers::BinaryMakeRule },
+    { flatbuffers::GenerateTextFile, "-t", "--json", "text", false, nullptr,
+      flatbuffers::IDLOptions::kJson,
+      "Generate text output for any data definitions",
+      flatbuffers::TextMakeRule },
+    { flatbuffers::GenerateCPP, "-c", "--cpp", "C++", true,
+      flatbuffers::GenerateCppGRPC, flatbuffers::IDLOptions::kCpp,
+      "Generate C++ headers for tables/structs", flatbuffers::CPPMakeRule },
+    { flatbuffers::GenerateGo, "-g", "--go", "Go", true,
+      flatbuffers::GenerateGoGRPC, flatbuffers::IDLOptions::kGo,
+      "Generate Go files for tables/structs", flatbuffers::GeneralMakeRule },
+    { flatbuffers::GenerateGeneral, "-j", "--java", "Java", true,
+      flatbuffers::GenerateJavaGRPC, flatbuffers::IDLOptions::kJava,
+      "Generate Java classes for tables/structs",
+      flatbuffers::GeneralMakeRule },
+    { flatbuffers::GenerateJSTS, "-s", "--js", "JavaScript", true, nullptr,
+      flatbuffers::IDLOptions::kJs,
+      "Generate JavaScript code for tables/structs", flatbuffers::JSTSMakeRule },
+    { flatbuffers::GenerateDart, "-d", "--dart", "Dart", true, nullptr,
+      flatbuffers::IDLOptions::kDart,
+      "Generate Dart classes for tables/structs", flatbuffers::DartMakeRule },
+    { flatbuffers::GenerateJSTS, "-T", "--ts", "TypeScript", true, nullptr,
+      flatbuffers::IDLOptions::kTs,
+      "Generate TypeScript code for tables/structs", flatbuffers::JSTSMakeRule },
+    { flatbuffers::GenerateGeneral, "-n", "--csharp", "C#", true, nullptr,
+      flatbuffers::IDLOptions::kCSharp,
+      "Generate C# classes for tables/structs", flatbuffers::GeneralMakeRule },
+    { flatbuffers::GeneratePython, "-p", "--python", "Python", true, nullptr,
+      flatbuffers::IDLOptions::kPython,
+      "Generate Python files for tables/structs",
+      flatbuffers::GeneralMakeRule },
+    { flatbuffers::GenerateLobster, nullptr, "--lobster", "Lobster", true, nullptr,
+      flatbuffers::IDLOptions::kLobster,
+      "Generate Lobster files for tables/structs",
+      flatbuffers::GeneralMakeRule },
+    { flatbuffers::GenerateLua, "-l", "--lua", "Lua", true, nullptr,
+      flatbuffers::IDLOptions::kLua,
+      "Generate Lua files for tables/structs",
+      flatbuffers::GeneralMakeRule },
+    { flatbuffers::GenerateRust, "-r", "--rust", "Rust", true, nullptr,
+      flatbuffers::IDLOptions::kRust,
+      "Generate Rust files for tables/structs",
+      flatbuffers::RustMakeRule },
+    { flatbuffers::GeneratePhp, nullptr, "--php", "PHP", true, nullptr,
+      flatbuffers::IDLOptions::kPhp, "Generate PHP files for tables/structs",
+      flatbuffers::GeneralMakeRule },
+    { flatbuffers::GenerateKotlin, nullptr, "--kotlin", "Kotlin", true, nullptr,
+      flatbuffers::IDLOptions::kKotlin, "Generate Kotlin classes for tables/structs",
+      flatbuffers::GeneralMakeRule },
+    { flatbuffers::GenerateJsonSchema, nullptr, "--jsonschema", "JsonSchema",
+      true, nullptr, flatbuffers::IDLOptions::kJsonSchema,
+      "Generate Json schema", flatbuffers::GeneralMakeRule },
+  };
+
+  flatbuffers::FlatCompiler::InitParams params;
+  params.generators = generators;
+  params.num_generators = sizeof(generators) / sizeof(generators[0]);
+  params.warn_fn = Warn;
+  params.error_fn = Error;
+
+  flatbuffers::FlatCompiler flatc(params);
+  return flatc.Compile(argc - 1, argv + 1);
+}
diff --git a/src/flathash.cpp b/src/flathash.cpp
new file mode 100644
index 0000000..bc3d2df
--- /dev/null
+++ b/src/flathash.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2015 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 <stdio.h>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "flatbuffers/hash.h"
+
+enum OutputFormat { kDecimal, kHexadecimal, kHexadecimal0x };
+
+int main(int argc, char *argv[]) {
+  const char *name = argv[0];
+  if (argc <= 1) {
+    printf("%s HASH [OPTION]... [--] STRING...\n", name);
+    printf("Available hashing algorithms:\n");
+    printf("  16 bit:\n");
+    size_t size = sizeof(flatbuffers::kHashFunctions16) /
+                  sizeof(flatbuffers::kHashFunctions16[0]);
+    for (size_t i = 0; i < size; ++i) {
+      printf("    * %s\n", flatbuffers::kHashFunctions16[i].name);
+    }
+    printf("  32 bit:\n");
+    size = sizeof(flatbuffers::kHashFunctions32) /
+                  sizeof(flatbuffers::kHashFunctions32[0]);
+    for (size_t i = 0; i < size; ++i) {
+      printf("    * %s\n", flatbuffers::kHashFunctions32[i].name);
+    }
+    printf("  64 bit:\n");
+    size = sizeof(flatbuffers::kHashFunctions64) /
+           sizeof(flatbuffers::kHashFunctions64[0]);
+    for (size_t i = 0; i < size; ++i) {
+      printf("    * %s\n", flatbuffers::kHashFunctions64[i].name);
+    }
+    printf(
+        "  -d         Output hash in decimal.\n"
+        "  -x         Output hash in hexadecimal.\n"
+        "  -0x        Output hash in hexadecimal and prefix with 0x.\n"
+        "  -c         Append the string to the output in a c-style comment.\n");
+    return 1;
+  }
+
+  const char *hash_algorithm = argv[1];
+
+  flatbuffers::NamedHashFunction<uint16_t>::HashFunction hash_function16 =
+      flatbuffers::FindHashFunction16(hash_algorithm);
+  flatbuffers::NamedHashFunction<uint32_t>::HashFunction hash_function32 =
+      flatbuffers::FindHashFunction32(hash_algorithm);
+  flatbuffers::NamedHashFunction<uint64_t>::HashFunction hash_function64 =
+      flatbuffers::FindHashFunction64(hash_algorithm);
+
+  if (!hash_function16 && !hash_function32 && !hash_function64) {
+    printf("\"%s\" is not a known hash algorithm.\n", hash_algorithm);
+    return 1;
+  }
+
+  OutputFormat output_format = kHexadecimal;
+  bool annotate = false;
+  bool escape_dash = false;
+  for (int i = 2; i < argc; i++) {
+    const char *arg = argv[i];
+    if (!escape_dash && arg[0] == '-') {
+      std::string opt = arg;
+      if (opt == "-d")
+        output_format = kDecimal;
+      else if (opt == "-x")
+        output_format = kHexadecimal;
+      else if (opt == "-0x")
+        output_format = kHexadecimal0x;
+      else if (opt == "-c")
+        annotate = true;
+      else if (opt == "--")
+        escape_dash = true;
+      else
+        printf("Unrecognized argument: \"%s\"\n", arg);
+    } else {
+      std::stringstream ss;
+      if (output_format == kDecimal) {
+        ss << std::dec;
+      } else if (output_format == kHexadecimal) {
+        ss << std::hex;
+      } else if (output_format == kHexadecimal0x) {
+        ss << std::hex;
+        ss << "0x";
+      }
+      if (hash_function16)
+        ss << hash_function16(arg);
+      else if (hash_function32)
+        ss << hash_function32(arg);
+      else if (hash_function64)
+        ss << hash_function64(arg);
+
+      if (annotate) ss << " /* \"" << arg << "\" */";
+
+      ss << "\n";
+
+      std::cout << ss.str();
+    }
+  }
+  return 0;
+}
diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp
new file mode 100644
index 0000000..b667ea4
--- /dev/null
+++ b/src/idl_gen_cpp.cpp
@@ -0,0 +1,2972 @@
+/*
+ * Copyright 2014 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.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#include <unordered_set>
+
+namespace flatbuffers {
+
+// Pedantic warning free version of toupper().
+inline char ToUpper(char c) { return static_cast<char>(::toupper(c)); }
+
+// Make numerical literal with type-suffix.
+// This function is only needed for C++! Other languages do not need it.
+static inline std::string NumToStringCpp(std::string val, BaseType type) {
+  // Avoid issues with -2147483648, -9223372036854775808.
+  switch (type) {
+    case BASE_TYPE_INT:
+      return (val != "-2147483648") ? val : ("(-2147483647 - 1)");
+    case BASE_TYPE_ULONG: return (val == "0") ? val : (val + "ULL");
+    case BASE_TYPE_LONG:
+      if (val == "-9223372036854775808")
+        return "(-9223372036854775807LL - 1LL)";
+      else
+        return (val == "0") ? val : (val + "LL");
+    default: return val;
+  }
+}
+
+static std::string GeneratedFileName(const std::string &path,
+                                     const std::string &file_name) {
+  return path + file_name + "_generated.h";
+}
+
+namespace cpp {
+class CppGenerator : public BaseGenerator {
+ public:
+  CppGenerator(const Parser &parser, const std::string &path,
+               const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "", "::"),
+        cur_name_space_(nullptr),
+        float_const_gen_("std::numeric_limits<double>::",
+                         "std::numeric_limits<float>::", "quiet_NaN()",
+                         "infinity()") {
+    static const char *const keywords[] = {
+      "alignas",
+      "alignof",
+      "and",
+      "and_eq",
+      "asm",
+      "atomic_cancel",
+      "atomic_commit",
+      "atomic_noexcept",
+      "auto",
+      "bitand",
+      "bitor",
+      "bool",
+      "break",
+      "case",
+      "catch",
+      "char",
+      "char16_t",
+      "char32_t",
+      "class",
+      "compl",
+      "concept",
+      "const",
+      "constexpr",
+      "const_cast",
+      "continue",
+      "co_await",
+      "co_return",
+      "co_yield",
+      "decltype",
+      "default",
+      "delete",
+      "do",
+      "double",
+      "dynamic_cast",
+      "else",
+      "enum",
+      "explicit",
+      "export",
+      "extern",
+      "false",
+      "float",
+      "for",
+      "friend",
+      "goto",
+      "if",
+      "import",
+      "inline",
+      "int",
+      "long",
+      "module",
+      "mutable",
+      "namespace",
+      "new",
+      "noexcept",
+      "not",
+      "not_eq",
+      "nullptr",
+      "operator",
+      "or",
+      "or_eq",
+      "private",
+      "protected",
+      "public",
+      "register",
+      "reinterpret_cast",
+      "requires",
+      "return",
+      "short",
+      "signed",
+      "sizeof",
+      "static",
+      "static_assert",
+      "static_cast",
+      "struct",
+      "switch",
+      "synchronized",
+      "template",
+      "this",
+      "thread_local",
+      "throw",
+      "true",
+      "try",
+      "typedef",
+      "typeid",
+      "typename",
+      "union",
+      "unsigned",
+      "using",
+      "virtual",
+      "void",
+      "volatile",
+      "wchar_t",
+      "while",
+      "xor",
+      "xor_eq",
+      nullptr,
+    };
+    for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+  }
+
+  std::string GenIncludeGuard() const {
+    // Generate include guard.
+    std::string guard = file_name_;
+    // Remove any non-alpha-numeric characters that may appear in a filename.
+    struct IsAlnum {
+      bool operator()(char c) const { return !is_alnum(c); }
+    };
+    guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
+                guard.end());
+    guard = "FLATBUFFERS_GENERATED_" + guard;
+    guard += "_";
+    // For further uniqueness, also add the namespace.
+    auto name_space = parser_.current_namespace_;
+    for (auto it = name_space->components.begin();
+         it != name_space->components.end(); ++it) {
+      guard += *it + "_";
+    }
+    guard += "H_";
+    std::transform(guard.begin(), guard.end(), guard.begin(), ToUpper);
+    return guard;
+  }
+
+  void GenIncludeDependencies() {
+    int num_includes = 0;
+    for (auto it = parser_.native_included_files_.begin();
+         it != parser_.native_included_files_.end(); ++it) {
+      code_ += "#include \"" + *it + "\"";
+      num_includes++;
+    }
+    for (auto it = parser_.included_files_.begin();
+         it != parser_.included_files_.end(); ++it) {
+      if (it->second.empty()) continue;
+      auto noext = flatbuffers::StripExtension(it->second);
+      auto basename = flatbuffers::StripPath(noext);
+
+      code_ += "#include \"" + parser_.opts.include_prefix +
+               (parser_.opts.keep_include_path ? noext : basename) +
+               "_generated.h\"";
+      num_includes++;
+    }
+    if (num_includes) code_ += "";
+  }
+
+  void GenExtraIncludes() {
+    for(std::size_t i = 0; i < parser_.opts.cpp_includes.size(); ++i) {
+      code_ += "#include \"" + parser_.opts.cpp_includes[i] + "\"";
+    }
+    if (!parser_.opts.cpp_includes.empty()) {
+      code_ += "";
+    }
+  }
+
+  std::string EscapeKeyword(const std::string &name) const {
+    return keywords_.find(name) == keywords_.end() ? name : name + "_";
+  }
+
+  std::string Name(const Definition &def) const {
+    return EscapeKeyword(def.name);
+  }
+
+  std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
+
+  // Iterate through all definitions we haven't generate code for (enums,
+  // structs, and tables) and output them to a single file.
+  bool generate() {
+    code_.Clear();
+    code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+    const auto include_guard = GenIncludeGuard();
+    code_ += "#ifndef " + include_guard;
+    code_ += "#define " + include_guard;
+    code_ += "";
+
+    if (parser_.opts.gen_nullable) {
+      code_ += "#pragma clang system_header\n\n";
+    }
+
+    code_ += "#include \"flatbuffers/flatbuffers.h\"";
+    if (parser_.uses_flexbuffers_) {
+      code_ += "#include \"flatbuffers/flexbuffers.h\"";
+    }
+    code_ += "";
+
+    if (parser_.opts.include_dependence_headers) { GenIncludeDependencies(); }
+    GenExtraIncludes();
+
+    FLATBUFFERS_ASSERT(!cur_name_space_);
+
+    // Generate forward declarations for all structs/tables, since they may
+    // have circular references.
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      const auto &struct_def = **it;
+      if (!struct_def.generated) {
+        SetNameSpace(struct_def.defined_namespace);
+        code_ += "struct " + Name(struct_def) + ";";
+        if (parser_.opts.generate_object_based_api) {
+          auto nativeName =
+              NativeName(Name(struct_def), &struct_def, parser_.opts);
+          if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; }
+        }
+        code_ += "";
+      }
+    }
+
+    // Generate forward declarations for all equal operators
+    if (parser_.opts.generate_object_based_api && parser_.opts.gen_compare) {
+      for (auto it = parser_.structs_.vec.begin();
+           it != parser_.structs_.vec.end(); ++it) {
+        const auto &struct_def = **it;
+        if (!struct_def.generated) {
+          SetNameSpace(struct_def.defined_namespace);
+          auto nativeName =
+              NativeName(Name(struct_def), &struct_def, parser_.opts);
+          code_ += "bool operator==(const " + nativeName + " &lhs, const " +
+                   nativeName + " &rhs);";
+          code_ += "bool operator!=(const " + nativeName + " &lhs, const " +
+              nativeName + " &rhs);";
+        }
+      }
+      code_ += "";
+    }
+
+    // Generate preablmle code for mini reflection.
+    if (parser_.opts.mini_reflect != IDLOptions::kNone) {
+      // To break cyclic dependencies, first pre-declare all tables/structs.
+      for (auto it = parser_.structs_.vec.begin();
+           it != parser_.structs_.vec.end(); ++it) {
+        const auto &struct_def = **it;
+        if (!struct_def.generated) {
+          SetNameSpace(struct_def.defined_namespace);
+          GenMiniReflectPre(&struct_def);
+        }
+      }
+    }
+
+    // Generate code for all the enum declarations.
+    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+         ++it) {
+      const auto &enum_def = **it;
+      if (!enum_def.generated) {
+        SetNameSpace(enum_def.defined_namespace);
+        GenEnum(enum_def);
+      }
+    }
+
+    // Generate code for all structs, then all tables.
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      const auto &struct_def = **it;
+      if (struct_def.fixed && !struct_def.generated) {
+        SetNameSpace(struct_def.defined_namespace);
+        GenStruct(struct_def);
+      }
+    }
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      const auto &struct_def = **it;
+      if (!struct_def.fixed && !struct_def.generated) {
+        SetNameSpace(struct_def.defined_namespace);
+        GenTable(struct_def);
+      }
+    }
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      const auto &struct_def = **it;
+      if (!struct_def.fixed && !struct_def.generated) {
+        SetNameSpace(struct_def.defined_namespace);
+        GenTablePost(struct_def);
+      }
+    }
+
+    // Generate code for union verifiers.
+    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+         ++it) {
+      const auto &enum_def = **it;
+      if (enum_def.is_union && !enum_def.generated) {
+        SetNameSpace(enum_def.defined_namespace);
+        GenUnionPost(enum_def);
+      }
+    }
+
+    // Generate code for mini reflection.
+    if (parser_.opts.mini_reflect != IDLOptions::kNone) {
+      // Then the unions/enums that may refer to them.
+      for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+           ++it) {
+        const auto &enum_def = **it;
+        if (!enum_def.generated) {
+          SetNameSpace(enum_def.defined_namespace);
+          GenMiniReflect(nullptr, &enum_def);
+        }
+      }
+      // Then the full tables/structs.
+      for (auto it = parser_.structs_.vec.begin();
+           it != parser_.structs_.vec.end(); ++it) {
+        const auto &struct_def = **it;
+        if (!struct_def.generated) {
+          SetNameSpace(struct_def.defined_namespace);
+          GenMiniReflect(&struct_def, nullptr);
+        }
+      }
+    }
+
+    // Generate convenient global helper functions:
+    if (parser_.root_struct_def_) {
+      auto &struct_def = *parser_.root_struct_def_;
+      SetNameSpace(struct_def.defined_namespace);
+      auto name = Name(struct_def);
+      auto qualified_name = cur_name_space_->GetFullyQualifiedName(name);
+      auto cpp_name = TranslateNameSpace(qualified_name);
+
+      code_.SetValue("STRUCT_NAME", name);
+      code_.SetValue("CPP_NAME", cpp_name);
+      code_.SetValue("NULLABLE_EXT", NullableExtension());
+
+      // The root datatype accessor:
+      code_ += "inline \\";
+      code_ +=
+          "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void "
+          "*buf) {";
+      code_ += "  return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
+      code_ += "}";
+      code_ += "";
+
+      code_ += "inline \\";
+      code_ +=
+          "const {{CPP_NAME}} "
+          "*{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void "
+          "*buf) {";
+      code_ += "  return flatbuffers::GetSizePrefixedRoot<{{CPP_NAME}}>(buf);";
+      code_ += "}";
+      code_ += "";
+
+      if (parser_.opts.mutable_buffer) {
+        code_ += "inline \\";
+        code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
+        code_ += "  return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
+        code_ += "}";
+        code_ += "";
+      }
+
+      if (parser_.file_identifier_.length()) {
+        // Return the identifier
+        code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
+        code_ += "  return \"" + parser_.file_identifier_ + "\";";
+        code_ += "}";
+        code_ += "";
+
+        // Check if a buffer has the identifier.
+        code_ += "inline \\";
+        code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {";
+        code_ += "  return flatbuffers::BufferHasIdentifier(";
+        code_ += "      buf, {{STRUCT_NAME}}Identifier());";
+        code_ += "}";
+        code_ += "";
+      }
+
+      // The root verifier.
+      if (parser_.file_identifier_.length()) {
+        code_.SetValue("ID", name + "Identifier()");
+      } else {
+        code_.SetValue("ID", "nullptr");
+      }
+
+      code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
+      code_ += "    flatbuffers::Verifier &verifier) {";
+      code_ += "  return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});";
+      code_ += "}";
+      code_ += "";
+
+      code_ += "inline bool VerifySizePrefixed{{STRUCT_NAME}}Buffer(";
+      code_ += "    flatbuffers::Verifier &verifier) {";
+      code_ +=
+          "  return verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}>({{ID}});";
+      code_ += "}";
+      code_ += "";
+
+      if (parser_.file_extension_.length()) {
+        // Return the extension
+        code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
+        code_ += "  return \"" + parser_.file_extension_ + "\";";
+        code_ += "}";
+        code_ += "";
+      }
+
+      // Finish a buffer with a given root object:
+      code_ += "inline void Finish{{STRUCT_NAME}}Buffer(";
+      code_ += "    flatbuffers::FlatBufferBuilder &fbb,";
+      code_ += "    flatbuffers::Offset<{{CPP_NAME}}> root) {";
+      if (parser_.file_identifier_.length())
+        code_ += "  fbb.Finish(root, {{STRUCT_NAME}}Identifier());";
+      else
+        code_ += "  fbb.Finish(root);";
+      code_ += "}";
+      code_ += "";
+
+      code_ += "inline void FinishSizePrefixed{{STRUCT_NAME}}Buffer(";
+      code_ += "    flatbuffers::FlatBufferBuilder &fbb,";
+      code_ += "    flatbuffers::Offset<{{CPP_NAME}}> root) {";
+      if (parser_.file_identifier_.length())
+        code_ += "  fbb.FinishSizePrefixed(root, {{STRUCT_NAME}}Identifier());";
+      else
+        code_ += "  fbb.FinishSizePrefixed(root);";
+      code_ += "}";
+      code_ += "";
+
+      if (parser_.opts.generate_object_based_api) {
+        // A convenient root unpack function.
+        auto native_name =
+            NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts);
+        code_.SetValue("UNPACK_RETURN",
+                       GenTypeNativePtr(native_name, nullptr, false));
+        code_.SetValue("UNPACK_TYPE",
+                       GenTypeNativePtr(native_name, nullptr, true));
+
+        code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}(";
+        code_ += "    const void *buf,";
+        code_ += "    const flatbuffers::resolver_function_t *res = nullptr) {";
+        code_ += "  return {{UNPACK_TYPE}}\\";
+        code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));";
+        code_ += "}";
+        code_ += "";
+
+        code_ += "inline {{UNPACK_RETURN}} UnPackSizePrefixed{{STRUCT_NAME}}(";
+        code_ += "    const void *buf,";
+        code_ += "    const flatbuffers::resolver_function_t *res = nullptr) {";
+        code_ += "  return {{UNPACK_TYPE}}\\";
+        code_ += "(GetSizePrefixed{{STRUCT_NAME}}(buf)->UnPack(res));";
+        code_ += "}";
+        code_ += "";
+      }
+    }
+
+    if (cur_name_space_) SetNameSpace(nullptr);
+
+    // Close the include guard.
+    code_ += "#endif  // " + include_guard;
+
+    const auto file_path = GeneratedFileName(path_, file_name_);
+    const auto final_code = code_.ToString();
+    return SaveFile(file_path.c_str(), final_code, false);
+  }
+
+ private:
+  CodeWriter code_;
+
+  std::unordered_set<std::string> keywords_;
+
+  // This tracks the current namespace so we can insert namespace declarations.
+  const Namespace *cur_name_space_;
+
+  const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+  // Translates a qualified name in flatbuffer text format to the same name in
+  // the equivalent C++ namespace.
+  static std::string TranslateNameSpace(const std::string &qualified_name) {
+    std::string cpp_qualified_name = qualified_name;
+    size_t start_pos = 0;
+    while ((start_pos = cpp_qualified_name.find('.', start_pos)) !=
+           std::string::npos) {
+      cpp_qualified_name.replace(start_pos, 1, "::");
+    }
+    return cpp_qualified_name;
+  }
+
+  void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
+    std::string text;
+    ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
+    code_ += text + "\\";
+  }
+
+  // Return a C++ type from the table in idl.h
+  std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
+    // clang-format off
+    static const char *const ctypename[] = {
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
+                           RTYPE, KTYPE) \
+            #CTYPE,
+        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+    #undef FLATBUFFERS_TD
+    };
+    // clang-format on
+    if (user_facing_type) {
+      if (type.enum_def) return WrapInNameSpace(*type.enum_def);
+      if (type.base_type == BASE_TYPE_BOOL) return "bool";
+    }
+    return ctypename[type.base_type];
+  }
+
+  // Return a C++ pointer type, specialized to the actual struct/table types,
+  // and vector element types.
+  std::string GenTypePointer(const Type &type) const {
+    switch (type.base_type) {
+      case BASE_TYPE_STRING: {
+        return "flatbuffers::String";
+      }
+      case BASE_TYPE_VECTOR: {
+        const auto type_name = GenTypeWire(type.VectorType(), "", false);
+        return "flatbuffers::Vector<" + type_name + ">";
+      }
+      case BASE_TYPE_STRUCT: {
+        return WrapInNameSpace(*type.struct_def);
+      }
+      case BASE_TYPE_UNION:
+      // fall through
+      default: { return "void"; }
+    }
+  }
+
+  // Return a C++ type for any type (scalar/pointer) specifically for
+  // building a flatbuffer.
+  std::string GenTypeWire(const Type &type, const char *postfix,
+                          bool user_facing_type) const {
+    if (IsScalar(type.base_type)) {
+      return GenTypeBasic(type, user_facing_type) + postfix;
+    } else if (IsStruct(type)) {
+      return "const " + GenTypePointer(type) + " *";
+    } else {
+      return "flatbuffers::Offset<" + GenTypePointer(type) + ">" + postfix;
+    }
+  }
+
+  // Return a C++ type for any type (scalar/pointer) that reflects its
+  // serialized size.
+  std::string GenTypeSize(const Type &type) const {
+    if (IsScalar(type.base_type)) {
+      return GenTypeBasic(type, false);
+    } else if (IsStruct(type)) {
+      return GenTypePointer(type);
+    } else {
+      return "flatbuffers::uoffset_t";
+    }
+  }
+
+  std::string NullableExtension() {
+    return parser_.opts.gen_nullable ? " _Nullable " : "";
+  }
+
+  static std::string NativeName(const std::string &name, const StructDef *sd,
+                                const IDLOptions &opts) {
+    return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix
+                            : name;
+  }
+
+  const std::string &PtrType(const FieldDef *field) {
+    auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
+    return attr ? attr->constant : parser_.opts.cpp_object_api_pointer_type;
+  }
+
+  const std::string NativeString(const FieldDef *field) {
+    auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
+    auto &ret = attr ? attr->constant : parser_.opts.cpp_object_api_string_type;
+    if (ret.empty()) { return "std::string"; }
+    return ret;
+  }
+
+  bool FlexibleStringConstructor(const FieldDef *field) {
+    auto attr = field
+                    ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr)
+                    : false;
+    auto ret =
+        attr ? attr : parser_.opts.cpp_object_api_string_flexible_constructor;
+    return ret && NativeString(field) !=
+                      "std::string";  // Only for custom string types.
+  }
+
+  std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
+                               bool is_constructor) {
+    auto &ptr_type = PtrType(field);
+    if (ptr_type != "naked") {
+      return (ptr_type != "default_ptr_type"
+                  ? ptr_type
+                  : parser_.opts.cpp_object_api_pointer_type) +
+             "<" + type + ">";
+    } else if (is_constructor) {
+      return "";
+    } else {
+      return type + " *";
+    }
+  }
+
+  std::string GenPtrGet(const FieldDef &field) {
+    auto cpp_ptr_type_get = field.attributes.Lookup("cpp_ptr_type_get");
+    if (cpp_ptr_type_get) return cpp_ptr_type_get->constant;
+    auto &ptr_type = PtrType(&field);
+    return ptr_type == "naked" ? "" : ".get()";
+  }
+
+  std::string GenTypeNative(const Type &type, bool invector,
+                            const FieldDef &field) {
+    switch (type.base_type) {
+      case BASE_TYPE_STRING: {
+        return NativeString(&field);
+      }
+      case BASE_TYPE_VECTOR: {
+        const auto type_name = GenTypeNative(type.VectorType(), true, field);
+        if (type.struct_def &&
+            type.struct_def->attributes.Lookup("native_custom_alloc")) {
+          auto native_custom_alloc =
+              type.struct_def->attributes.Lookup("native_custom_alloc");
+          return "std::vector<" + type_name + "," +
+                 native_custom_alloc->constant + "<" + type_name + ">>";
+        } else
+          return "std::vector<" + type_name + ">";
+      }
+      case BASE_TYPE_STRUCT: {
+        auto type_name = WrapInNameSpace(*type.struct_def);
+        if (IsStruct(type)) {
+          auto native_type = type.struct_def->attributes.Lookup("native_type");
+          if (native_type) { type_name = native_type->constant; }
+          if (invector || field.native_inline) {
+            return type_name;
+          } else {
+            return GenTypeNativePtr(type_name, &field, false);
+          }
+        } else {
+          return GenTypeNativePtr(
+              NativeName(type_name, type.struct_def, parser_.opts), &field,
+              false);
+        }
+      }
+      case BASE_TYPE_UNION: {
+        return type.enum_def->name + "Union";
+      }
+      default: { return GenTypeBasic(type, true); }
+    }
+  }
+
+  // Return a C++ type for any type (scalar/pointer) specifically for
+  // using a flatbuffer.
+  std::string GenTypeGet(const Type &type, const char *afterbasic,
+                         const char *beforeptr, const char *afterptr,
+                         bool user_facing_type) {
+    if (IsScalar(type.base_type)) {
+      return GenTypeBasic(type, user_facing_type) + afterbasic;
+    } else if (IsArray(type)) {
+      auto element_type = type.VectorType();
+      return beforeptr +
+             (IsScalar(element_type.base_type)
+                  ? GenTypeBasic(element_type, user_facing_type)
+                  : GenTypePointer(element_type)) +
+             afterptr;
+    } else {
+      return beforeptr + GenTypePointer(type) + afterptr;
+    }
+  }
+
+  std::string GenEnumDecl(const EnumDef &enum_def) const {
+    const IDLOptions &opts = parser_.opts;
+    return (opts.scoped_enums ? "enum class " : "enum ") + Name(enum_def);
+  }
+
+  std::string GenEnumValDecl(const EnumDef &enum_def,
+                             const std::string &enum_val) const {
+    const IDLOptions &opts = parser_.opts;
+    return opts.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
+  }
+
+  std::string GetEnumValUse(const EnumDef &enum_def,
+                            const EnumVal &enum_val) const {
+    const IDLOptions &opts = parser_.opts;
+    if (opts.scoped_enums) {
+      return Name(enum_def) + "::" + Name(enum_val);
+    } else if (opts.prefixed_enums) {
+      return Name(enum_def) + "_" + Name(enum_val);
+    } else {
+      return Name(enum_val);
+    }
+  }
+
+  std::string StripUnionType(const std::string &name) {
+    return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
+  }
+
+  std::string GetUnionElement(const EnumVal &ev, bool wrap, bool actual_type,
+                              bool native_type = false) {
+    if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+      auto name = actual_type ? ev.union_type.struct_def->name : Name(ev);
+      return wrap ? WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
+                                    name)
+                  : name;
+    } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+      return actual_type ? (native_type ? "std::string" : "flatbuffers::String")
+                         : Name(ev);
+    } else {
+      FLATBUFFERS_ASSERT(false);
+      return Name(ev);
+    }
+  }
+
+  std::string UnionVerifySignature(const EnumDef &enum_def) {
+    return "bool Verify" + Name(enum_def) +
+           "(flatbuffers::Verifier &verifier, const void *obj, " +
+           Name(enum_def) + " type)";
+  }
+
+  std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
+    return "bool Verify" + Name(enum_def) + "Vector" +
+           "(flatbuffers::Verifier &verifier, " +
+           "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
+           "const flatbuffers::Vector<uint8_t> *types)";
+  }
+
+  std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) {
+    return (inclass ? "static " : "") + std::string("void *") +
+           (inclass ? "" : Name(enum_def) + "Union::") +
+           "UnPack(const void *obj, " + Name(enum_def) +
+           " type, const flatbuffers::resolver_function_t *resolver)";
+  }
+
+  std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
+    return "flatbuffers::Offset<void> " +
+           (inclass ? "" : Name(enum_def) + "Union::") +
+           "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
+           "const flatbuffers::rehasher_function_t *_rehasher" +
+           (inclass ? " = nullptr" : "") + ") const";
+  }
+
+  std::string TableCreateSignature(const StructDef &struct_def, bool predecl,
+                                   const IDLOptions &opts) {
+    return "flatbuffers::Offset<" + Name(struct_def) + "> Create" +
+           Name(struct_def) + "(flatbuffers::FlatBufferBuilder &_fbb, const " +
+           NativeName(Name(struct_def), &struct_def, opts) +
+           " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
+           (predecl ? " = nullptr" : "") + ")";
+  }
+
+  std::string TablePackSignature(const StructDef &struct_def, bool inclass,
+                                 const IDLOptions &opts) {
+    return std::string(inclass ? "static " : "") + "flatbuffers::Offset<" +
+           Name(struct_def) + "> " + (inclass ? "" : Name(struct_def) + "::") +
+           "Pack(flatbuffers::FlatBufferBuilder &_fbb, " + "const " +
+           NativeName(Name(struct_def), &struct_def, opts) + "* _o, " +
+           "const flatbuffers::rehasher_function_t *_rehasher" +
+           (inclass ? " = nullptr" : "") + ")";
+  }
+
+  std::string TableUnPackSignature(const StructDef &struct_def, bool inclass,
+                                   const IDLOptions &opts) {
+    return NativeName(Name(struct_def), &struct_def, opts) + " *" +
+           (inclass ? "" : Name(struct_def) + "::") +
+           "UnPack(const flatbuffers::resolver_function_t *_resolver" +
+           (inclass ? " = nullptr" : "") + ") const";
+  }
+
+  std::string TableUnPackToSignature(const StructDef &struct_def, bool inclass,
+                                     const IDLOptions &opts) {
+    return "void " + (inclass ? "" : Name(struct_def) + "::") + "UnPackTo(" +
+           NativeName(Name(struct_def), &struct_def, opts) + " *" +
+           "_o, const flatbuffers::resolver_function_t *_resolver" +
+           (inclass ? " = nullptr" : "") + ") const";
+  }
+
+  void GenMiniReflectPre(const StructDef *struct_def) {
+    code_.SetValue("NAME", struct_def->name);
+    code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable();";
+    code_ += "";
+  }
+
+  void GenMiniReflect(const StructDef *struct_def, const EnumDef *enum_def) {
+    code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name);
+    code_.SetValue("SEQ_TYPE",
+                   struct_def ? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE")
+                              : (enum_def->is_union ? "ST_UNION" : "ST_ENUM"));
+    auto num_fields =
+        struct_def ? struct_def->fields.vec.size() : enum_def->size();
+    code_.SetValue("NUM_FIELDS", NumToString(num_fields));
+    std::vector<std::string> names;
+    std::vector<Type> types;
+
+    if (struct_def) {
+      for (auto it = struct_def->fields.vec.begin();
+           it != struct_def->fields.vec.end(); ++it) {
+        const auto &field = **it;
+        names.push_back(Name(field));
+        types.push_back(field.value.type);
+      }
+    } else {
+      for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
+           ++it) {
+        const auto &ev = **it;
+        names.push_back(Name(ev));
+        types.push_back(enum_def->is_union ? ev.union_type
+                                           : Type(enum_def->underlying_type));
+      }
+    }
+    std::string ts;
+    std::vector<std::string> type_refs;
+    for (auto it = types.begin(); it != types.end(); ++it) {
+      auto &type = *it;
+      if (!ts.empty()) ts += ",\n    ";
+      auto is_vector = type.base_type == BASE_TYPE_VECTOR;
+      auto bt = is_vector ? type.element : type.base_type;
+      auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
+                    ? bt - BASE_TYPE_UTYPE + ET_UTYPE
+                    : ET_SEQUENCE;
+      int ref_idx = -1;
+      std::string ref_name =
+          type.struct_def
+              ? WrapInNameSpace(*type.struct_def)
+              : type.enum_def ? WrapInNameSpace(*type.enum_def) : "";
+      if (!ref_name.empty()) {
+        auto rit = type_refs.begin();
+        for (; rit != type_refs.end(); ++rit) {
+          if (*rit == ref_name) {
+            ref_idx = static_cast<int>(rit - type_refs.begin());
+            break;
+          }
+        }
+        if (rit == type_refs.end()) {
+          ref_idx = static_cast<int>(type_refs.size());
+          type_refs.push_back(ref_name);
+        }
+      }
+      ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " +
+            NumToString(is_vector) + ", " + NumToString(ref_idx) + " }";
+    }
+    std::string rs;
+    for (auto it = type_refs.begin(); it != type_refs.end(); ++it) {
+      if (!rs.empty()) rs += ",\n    ";
+      rs += *it + "TypeTable";
+    }
+    std::string ns;
+    for (auto it = names.begin(); it != names.end(); ++it) {
+      if (!ns.empty()) ns += ",\n    ";
+      ns += "\"" + *it + "\"";
+    }
+    std::string vs;
+    const auto consecutive_enum_from_zero =
+        enum_def && enum_def->MinValue()->IsZero() &&
+        ((enum_def->size() - 1) == enum_def->Distance());
+    if (enum_def && !consecutive_enum_from_zero) {
+      for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
+           ++it) {
+        const auto &ev = **it;
+        if (!vs.empty()) vs += ", ";
+        vs += NumToStringCpp(enum_def->ToString(ev),
+                             enum_def->underlying_type.base_type);
+      }
+    } else if (struct_def && struct_def->fixed) {
+      for (auto it = struct_def->fields.vec.begin();
+           it != struct_def->fields.vec.end(); ++it) {
+        const auto &field = **it;
+        vs += NumToString(field.value.offset);
+        vs += ", ";
+      }
+      vs += NumToString(struct_def->bytesize);
+    }
+    code_.SetValue("TYPES", ts);
+    code_.SetValue("REFS", rs);
+    code_.SetValue("NAMES", ns);
+    code_.SetValue("VALUES", vs);
+    code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable() {";
+    if (num_fields) {
+      code_ += "  static const flatbuffers::TypeCode type_codes[] = {";
+      code_ += "    {{TYPES}}";
+      code_ += "  };";
+    }
+    if (!type_refs.empty()) {
+      code_ += "  static const flatbuffers::TypeFunction type_refs[] = {";
+      code_ += "    {{REFS}}";
+      code_ += "  };";
+    }
+    if (!vs.empty()) {
+      // Problem with uint64_t values greater than 9223372036854775807ULL.
+      code_ += "  static const int64_t values[] = { {{VALUES}} };";
+    }
+    auto has_names =
+        num_fields && parser_.opts.mini_reflect == IDLOptions::kTypesAndNames;
+    if (has_names) {
+      code_ += "  static const char * const names[] = {";
+      code_ += "    {{NAMES}}";
+      code_ += "  };";
+    }
+    code_ += "  static const flatbuffers::TypeTable tt = {";
+    code_ += std::string("    flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
+             (num_fields ? "type_codes, " : "nullptr, ") +
+             (!type_refs.empty() ? "type_refs, " : "nullptr, ") +
+             (!vs.empty() ? "values, " : "nullptr, ") +
+             (has_names ? "names" : "nullptr");
+    code_ += "  };";
+    code_ += "  return &tt;";
+    code_ += "}";
+    code_ += "";
+  }
+
+  // Generate an enum declaration,
+  // an enum string lookup table,
+  // and an enum array of values
+
+  void GenEnum(const EnumDef &enum_def) {
+    code_.SetValue("ENUM_NAME", Name(enum_def));
+    code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
+
+    GenComment(enum_def.doc_comment);
+    code_ += GenEnumDecl(enum_def) + "\\";
+    // MSVC doesn't support int64/uint64 enum without explicitly declared enum
+    // type. The value 4611686018427387904ULL is truncated to zero with warning:
+    // "warning C4309: 'initializing': truncation of constant value".
+    auto add_type = parser_.opts.scoped_enums;
+    add_type |= (enum_def.underlying_type.base_type == BASE_TYPE_LONG);
+    add_type |= (enum_def.underlying_type.base_type == BASE_TYPE_ULONG);
+    if (add_type) code_ += " : {{BASE_TYPE}}\\";
+    code_ += " {";
+
+    code_.SetValue("SEP", ",");
+    auto add_sep = false;
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      const auto &ev = **it;
+      if (add_sep) code_ += "{{SEP}}";
+      GenComment(ev.doc_comment, "  ");
+      code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev)));
+      code_.SetValue("VALUE",
+                     NumToStringCpp(enum_def.ToString(ev),
+                                    enum_def.underlying_type.base_type));
+      code_ += "  {{KEY}} = {{VALUE}}\\";
+      add_sep = true;
+    }
+    const EnumVal *minv = enum_def.MinValue();
+    const EnumVal *maxv = enum_def.MaxValue();
+
+    if (parser_.opts.scoped_enums || parser_.opts.prefixed_enums) {
+      FLATBUFFERS_ASSERT(minv && maxv);
+
+      code_.SetValue("SEP", ",\n");
+      if (enum_def.attributes.Lookup("bit_flags")) {
+        code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE"));
+        code_.SetValue("VALUE", "0");
+        code_ += "{{SEP}}  {{KEY}} = {{VALUE}}\\";
+
+        code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY"));
+        code_.SetValue("VALUE",
+                       NumToStringCpp(enum_def.AllFlags(),
+                                      enum_def.underlying_type.base_type));
+        code_ += "{{SEP}}  {{KEY}} = {{VALUE}}\\";
+      } else {  // MIN & MAX are useless for bit_flags
+        code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN"));
+        code_.SetValue("VALUE", GenEnumValDecl(enum_def, minv->name));
+        code_ += "{{SEP}}  {{KEY}} = {{VALUE}}\\";
+
+        code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX"));
+        code_.SetValue("VALUE", GenEnumValDecl(enum_def, maxv->name));
+        code_ += "{{SEP}}  {{KEY}} = {{VALUE}}\\";
+      }
+    }
+    code_ += "";
+    code_ += "};";
+
+    if (parser_.opts.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
+      code_ +=
+          "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
+    }
+    code_ += "";
+
+    // Generate an array of all enumeration values
+    auto num_fields = NumToString(enum_def.size());
+    code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" +
+             num_fields + "] {";
+    code_ += "  static const {{ENUM_NAME}} values[] = {";
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      const auto &ev = **it;
+      auto value = GetEnumValUse(enum_def, ev);
+      auto suffix = *it != enum_def.Vals().back() ? "," : "";
+      code_ += "    " + value + suffix;
+    }
+    code_ += "  };";
+    code_ += "  return values;";
+    code_ += "}";
+    code_ += "";
+
+    // Generate a generate string table for enum values.
+    // Problem is, if values are very sparse that could generate really big
+    // tables. Ideally in that case we generate a map lookup instead, but for
+    // the moment we simply don't output a table at all.
+    auto range = enum_def.Distance();
+    // Average distance between values above which we consider a table
+    // "too sparse". Change at will.
+    static const uint64_t kMaxSparseness = 5;
+    if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
+      code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {";
+      code_ += "  static const char * const names[" +
+               NumToString(range + 1 + 1) + "] = {";
+
+      auto val = enum_def.Vals().front();
+      for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+           ++it) {
+        auto ev = *it;
+        for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
+          code_ += "    \"\",";
+        }
+        val = ev;
+        code_ += "    \"" + Name(*ev) + "\",";
+      }
+      code_ += "    nullptr";
+      code_ += "  };";
+
+      code_ += "  return names;";
+      code_ += "}";
+      code_ += "";
+
+      code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
+
+      code_ += "  if (e < " + GetEnumValUse(enum_def, *enum_def.MinValue()) +
+               " || e > " + GetEnumValUse(enum_def, *enum_def.MaxValue()) +
+               ") return \"\";";
+
+      code_ += "  const size_t index = static_cast<size_t>(e)\\";
+      if (enum_def.MinValue()->IsNonZero()) {
+        auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
+        code_ += " - static_cast<size_t>(" + vals + ")\\";
+      }
+      code_ += ";";
+
+      code_ += "  return EnumNames{{ENUM_NAME}}()[index];";
+      code_ += "}";
+      code_ += "";
+    } else {
+      code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
+
+      code_ += "  switch (e) {";
+
+      for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+           ++it) {
+        const auto &ev = **it;
+        code_ += "    case " + GetEnumValUse(enum_def, ev) + ": return \"" +
+                 Name(ev) + "\";";
+      }
+
+      code_ += "    default: return \"\";";
+      code_ += "  }";
+
+      code_ += "}";
+      code_ += "";
+    }
+
+    // Generate type traits for unions to map from a type to union enum value.
+    if (enum_def.is_union && !enum_def.uses_multiple_type_instances) {
+      for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+           ++it) {
+        const auto &ev = **it;
+
+        if (it == enum_def.Vals().begin()) {
+          code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
+        } else {
+          auto name = GetUnionElement(ev, true, true);
+          code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
+        }
+
+        auto value = GetEnumValUse(enum_def, ev);
+        code_ += "  static const {{ENUM_NAME}} enum_value = " + value + ";";
+        code_ += "};";
+        code_ += "";
+      }
+    }
+
+    if (parser_.opts.generate_object_based_api && enum_def.is_union) {
+      // Generate a union type
+      code_.SetValue("NAME", Name(enum_def));
+      FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
+      code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
+
+      code_ += "struct {{NAME}}Union {";
+      code_ += "  {{NAME}} type;";
+      code_ += "  void *value;";
+      code_ += "";
+      code_ += "  {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
+      code_ += "  {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
+      code_ += "    type({{NONE}}), value(nullptr)";
+      code_ += "    { std::swap(type, u.type); std::swap(value, u.value); }";
+      code_ += "  {{NAME}}Union(const {{NAME}}Union &) FLATBUFFERS_NOEXCEPT;";
+      code_ +=
+          "  {{NAME}}Union &operator=(const {{NAME}}Union &u) "
+          "FLATBUFFERS_NOEXCEPT";
+      code_ +=
+          "    { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, "
+          "t.value); return *this; }";
+      code_ +=
+          "  {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
+      code_ +=
+          "    { std::swap(type, u.type); std::swap(value, u.value); return "
+          "*this; }";
+      code_ += "  ~{{NAME}}Union() { Reset(); }";
+      code_ += "";
+      code_ += "  void Reset();";
+      code_ += "";
+      if (!enum_def.uses_multiple_type_instances) {
+        code_ += "#ifndef FLATBUFFERS_CPP98_STL";
+        code_ += "  template <typename T>";
+        code_ += "  void Set(T&& val) {";
+        code_ += "    using RT = typename std::remove_reference<T>::type;";
+        code_ += "    Reset();";
+        code_ += "    type = {{NAME}}Traits<typename RT::TableType>::enum_value;";
+        code_ += "    if (type != {{NONE}}) {";
+        code_ += "      value = new RT(std::forward<T>(val));";
+        code_ += "    }";
+        code_ += "  }";
+        code_ += "#endif  // FLATBUFFERS_CPP98_STL";
+        code_ += "";
+      }
+      code_ += "  " + UnionUnPackSignature(enum_def, true) + ";";
+      code_ += "  " + UnionPackSignature(enum_def, true) + ";";
+      code_ += "";
+
+      for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+           ++it) {
+        const auto &ev = **it;
+        if (ev.IsZero()) { continue; }
+
+        const auto native_type =
+            NativeName(GetUnionElement(ev, true, true, true),
+                       ev.union_type.struct_def, parser_.opts);
+        code_.SetValue("NATIVE_TYPE", native_type);
+        code_.SetValue("NATIVE_NAME", Name(ev));
+        code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
+
+        code_ += "  {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
+        code_ += "    return type == {{NATIVE_ID}} ?";
+        code_ += "      reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
+        code_ += "  }";
+
+        code_ += "  const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {";
+        code_ += "    return type == {{NATIVE_ID}} ?";
+        code_ +=
+            "      reinterpret_cast<const {{NATIVE_TYPE}} *>(value) : nullptr;";
+        code_ += "  }";
+      }
+      code_ += "};";
+      code_ += "";
+
+      if (parser_.opts.gen_compare) {
+        code_ += "";
+        code_ +=
+            "inline bool operator==(const {{NAME}}Union &lhs, const "
+            "{{NAME}}Union &rhs) {";
+        code_ += "  if (lhs.type != rhs.type) return false;";
+        code_ += "  switch (lhs.type) {";
+
+        for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+             ++it) {
+          const auto &ev = **it;
+          code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
+          if (ev.IsNonZero()) {
+            const auto native_type =
+                NativeName(GetUnionElement(ev, true, true, true),
+                           ev.union_type.struct_def, parser_.opts);
+            code_.SetValue("NATIVE_TYPE", native_type);
+            code_ += "    case {{NATIVE_ID}}: {";
+            code_ +=
+                "      return *(reinterpret_cast<const {{NATIVE_TYPE}} "
+                "*>(lhs.value)) ==";
+            code_ +=
+                "             *(reinterpret_cast<const {{NATIVE_TYPE}} "
+                "*>(rhs.value));";
+            code_ += "    }";
+          } else {
+            code_ += "    case {{NATIVE_ID}}: {";
+            code_ += "      return true;";  // "NONE" enum value.
+            code_ += "    }";
+          }
+        }
+        code_ += "    default: {";
+        code_ += "      return false;";
+        code_ += "    }";
+        code_ += "  }";
+        code_ += "}";
+
+        code_ += "";
+        code_ +=
+            "inline bool operator!=(const {{NAME}}Union &lhs, const "
+            "{{NAME}}Union &rhs) {";
+        code_ += "    return !(lhs == rhs);";
+        code_ += "}";
+        code_ += "";
+      }
+    }
+
+    if (enum_def.is_union) {
+      code_ += UnionVerifySignature(enum_def) + ";";
+      code_ += UnionVectorVerifySignature(enum_def) + ";";
+      code_ += "";
+    }
+  }
+
+  void GenUnionPost(const EnumDef &enum_def) {
+    // Generate a verifier function for this union that can be called by the
+    // table verifier functions. It uses a switch case to select a specific
+    // verifier function to call, this should be safe even if the union type
+    // has been corrupted, since the verifiers will simply fail when called
+    // on the wrong type.
+    code_.SetValue("ENUM_NAME", Name(enum_def));
+
+    code_ += "inline " + UnionVerifySignature(enum_def) + " {";
+    code_ += "  switch (type) {";
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      const auto &ev = **it;
+      code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+
+      if (ev.IsNonZero()) {
+        code_.SetValue("TYPE", GetUnionElement(ev, true, true));
+        code_ += "    case {{LABEL}}: {";
+        auto getptr =
+            "      auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
+        if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+          if (ev.union_type.struct_def->fixed) {
+            code_ += "      return verifier.Verify<{{TYPE}}>(static_cast<const "
+                     "uint8_t *>(obj), 0);";
+          } else {
+            code_ += getptr;
+            code_ += "      return verifier.VerifyTable(ptr);";
+          }
+        } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+          code_ += getptr;
+          code_ += "      return verifier.VerifyString(ptr);";
+        } else {
+          FLATBUFFERS_ASSERT(false);
+        }
+        code_ += "    }";
+      } else {
+        code_ += "    case {{LABEL}}: {";
+        code_ += "      return true;";  // "NONE" enum value.
+        code_ += "    }";
+      }
+    }
+    code_ += "    default: return false;";
+    code_ += "  }";
+    code_ += "}";
+    code_ += "";
+
+    code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
+    code_ += "  if (!values || !types) return !values && !types;";
+    code_ += "  if (values->size() != types->size()) return false;";
+    code_ += "  for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
+    code_ += "    if (!Verify" + Name(enum_def) + "(";
+    code_ += "        verifier,  values->Get(i), types->GetEnum<" +
+             Name(enum_def) + ">(i))) {";
+    code_ += "      return false;";
+    code_ += "    }";
+    code_ += "  }";
+    code_ += "  return true;";
+    code_ += "}";
+    code_ += "";
+
+    if (parser_.opts.generate_object_based_api) {
+      // Generate union Unpack() and Pack() functions.
+      code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
+      code_ += "  switch (type) {";
+      for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+           ++it) {
+        const auto &ev = **it;
+        if (ev.IsZero()) { continue; }
+
+        code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+        code_.SetValue("TYPE", GetUnionElement(ev, true, true));
+        code_ += "    case {{LABEL}}: {";
+        code_ += "      auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
+        if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+          if (ev.union_type.struct_def->fixed) {
+            code_ += "      return new " +
+                     WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
+          } else {
+            code_ += "      return ptr->UnPack(resolver);";
+          }
+        } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+          code_ += "      return new std::string(ptr->c_str(), ptr->size());";
+        } else {
+          FLATBUFFERS_ASSERT(false);
+        }
+        code_ += "    }";
+      }
+      code_ += "    default: return nullptr;";
+      code_ += "  }";
+      code_ += "}";
+      code_ += "";
+
+      code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
+      code_ += "  switch (type) {";
+      for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+           ++it) {
+        auto &ev = **it;
+        if (ev.IsZero()) { continue; }
+
+        code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+        code_.SetValue("TYPE",
+                       NativeName(GetUnionElement(ev, true, true, true),
+                                  ev.union_type.struct_def, parser_.opts));
+        code_.SetValue("NAME", GetUnionElement(ev, false, true));
+        code_ += "    case {{LABEL}}: {";
+        code_ += "      auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
+        if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+          if (ev.union_type.struct_def->fixed) {
+            code_ += "      return _fbb.CreateStruct(*ptr).Union();";
+          } else {
+            code_ +=
+                "      return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
+          }
+        } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+          code_ += "      return _fbb.CreateString(*ptr).Union();";
+        } else {
+          FLATBUFFERS_ASSERT(false);
+        }
+        code_ += "    }";
+      }
+      code_ += "    default: return 0;";
+      code_ += "  }";
+      code_ += "}";
+      code_ += "";
+
+      // Union copy constructor
+      code_ +=
+          "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
+          "{{ENUM_NAME}}Union &u) FLATBUFFERS_NOEXCEPT : type(u.type), "
+          "value(nullptr) {";
+      code_ += "  switch (type) {";
+      for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+           ++it) {
+        const auto &ev = **it;
+        if (ev.IsZero()) { continue; }
+        code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+        code_.SetValue("TYPE",
+                       NativeName(GetUnionElement(ev, true, true, true),
+                                  ev.union_type.struct_def, parser_.opts));
+        code_ += "    case {{LABEL}}: {";
+        bool copyable = true;
+        if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+          // Don't generate code to copy if table is not copyable.
+          // TODO(wvo): make tables copyable instead.
+          for (auto fit = ev.union_type.struct_def->fields.vec.begin();
+               fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
+            const auto &field = **fit;
+            if (!field.deprecated && field.value.type.struct_def &&
+                !field.native_inline) {
+              copyable = false;
+              break;
+            }
+          }
+        }
+        if (copyable) {
+          code_ +=
+              "      value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
+              "(u.value));";
+        } else {
+          code_ +=
+              "      FLATBUFFERS_ASSERT(false);  // {{TYPE}} not copyable.";
+        }
+        code_ += "      break;";
+        code_ += "    }";
+      }
+      code_ += "    default:";
+      code_ += "      break;";
+      code_ += "  }";
+      code_ += "}";
+      code_ += "";
+
+      // Union Reset() function.
+      FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
+      code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
+
+      code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
+      code_ += "  switch (type) {";
+      for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+           ++it) {
+        const auto &ev = **it;
+        if (ev.IsZero()) { continue; }
+        code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+        code_.SetValue("TYPE",
+                       NativeName(GetUnionElement(ev, true, true, true),
+                                  ev.union_type.struct_def, parser_.opts));
+        code_ += "    case {{LABEL}}: {";
+        code_ += "      auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
+        code_ += "      delete ptr;";
+        code_ += "      break;";
+        code_ += "    }";
+      }
+      code_ += "    default: break;";
+      code_ += "  }";
+      code_ += "  value = nullptr;";
+      code_ += "  type = {{NONE}};";
+      code_ += "}";
+      code_ += "";
+    }
+  }
+
+  // Generates a value with optionally a cast applied if the field has a
+  // different underlying type from its interface type (currently only the
+  // case for enums. "from" specify the direction, true meaning from the
+  // underlying type to the interface type.
+  std::string GenUnderlyingCast(const FieldDef &field, bool from,
+                                const std::string &val) {
+    if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
+      return val + " != 0";
+    } else if ((field.value.type.enum_def &&
+                IsScalar(field.value.type.base_type)) ||
+               field.value.type.base_type == BASE_TYPE_BOOL) {
+      return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
+             val + ")";
+    } else {
+      return val;
+    }
+  }
+
+  std::string GenFieldOffsetName(const FieldDef &field) {
+    std::string uname = Name(field);
+    std::transform(uname.begin(), uname.end(), uname.begin(), ToUpper);
+    return "VT_" + uname;
+  }
+
+  void GenFullyQualifiedNameGetter(const StructDef &struct_def,
+                                   const std::string &name) {
+    if (!parser_.opts.generate_name_strings) { return; }
+    auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
+    code_.SetValue("NAME", fullname);
+    code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
+    code_ += "  static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
+    code_ += "    return \"{{NAME}}\";";
+    code_ += "  }";
+  }
+
+  std::string GenDefaultConstant(const FieldDef &field) {
+    if (IsFloat(field.value.type.base_type))
+      return float_const_gen_.GenFloatConstant(field);
+    else
+      return NumToStringCpp(field.value.constant, field.value.type.base_type);
+  }
+
+  std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
+    if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) {
+      auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
+      if (ev) {
+        return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
+                               GetEnumValUse(*field.value.type.enum_def, *ev));
+      } else {
+        return GenUnderlyingCast(
+            field, true,
+            NumToStringCpp(field.value.constant, field.value.type.base_type));
+      }
+    } else if (field.value.type.base_type == BASE_TYPE_BOOL) {
+      return field.value.constant == "0" ? "false" : "true";
+    } else if (field.attributes.Lookup("cpp_type")) {
+      if (is_ctor) {
+        if (PtrType(&field) == "naked") {
+          return "nullptr";
+        } else {
+          return "";
+        }
+      } else {
+        return "0";
+      }
+    } else {
+      return GenDefaultConstant(field);
+    }
+  }
+
+  void GenParam(const FieldDef &field, bool direct, const char *prefix) {
+    code_.SetValue("PRE", prefix);
+    code_.SetValue("PARAM_NAME", Name(field));
+    if (direct && field.value.type.base_type == BASE_TYPE_STRING) {
+      code_.SetValue("PARAM_TYPE", "const char *");
+      code_.SetValue("PARAM_VALUE", "nullptr");
+    } else if (direct && field.value.type.base_type == BASE_TYPE_VECTOR) {
+      const auto vtype = field.value.type.VectorType();
+      std::string type;
+      if (IsStruct(vtype)) {
+        type = WrapInNameSpace(*vtype.struct_def);
+      } else {
+        type = GenTypeWire(vtype, "", false);
+      }
+      code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
+      code_.SetValue("PARAM_VALUE", "nullptr");
+    } else {
+      code_.SetValue("PARAM_TYPE", GenTypeWire(field.value.type, " ", true));
+      code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
+    }
+    code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
+  }
+
+  // Generate a member, including a default value for scalars and raw pointers.
+  void GenMember(const FieldDef &field) {
+    if (!field.deprecated &&  // Deprecated fields won't be accessible.
+        field.value.type.base_type != BASE_TYPE_UTYPE &&
+        (field.value.type.base_type != BASE_TYPE_VECTOR ||
+         field.value.type.element != BASE_TYPE_UTYPE)) {
+      auto type = GenTypeNative(field.value.type, false, field);
+      auto cpp_type = field.attributes.Lookup("cpp_type");
+      auto full_type =
+          (cpp_type
+               ? (field.value.type.base_type == BASE_TYPE_VECTOR
+                      ? "std::vector<" +
+                            GenTypeNativePtr(cpp_type->constant, &field,
+                                             false) +
+                            "> "
+                      : GenTypeNativePtr(cpp_type->constant, &field, false))
+               : type + " ");
+      code_.SetValue("FIELD_TYPE", full_type);
+      code_.SetValue("FIELD_NAME", Name(field));
+      code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}};";
+    }
+  }
+
+  // Generate the default constructor for this struct. Properly initialize all
+  // scalar members with default values.
+  void GenDefaultConstructor(const StructDef &struct_def) {
+    std::string initializer_list;
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (!field.deprecated &&  // Deprecated fields won't be accessible.
+          field.value.type.base_type != BASE_TYPE_UTYPE) {
+        auto cpp_type = field.attributes.Lookup("cpp_type");
+        auto native_default = field.attributes.Lookup("native_default");
+        // Scalar types get parsed defaults, raw pointers get nullptrs.
+        if (IsScalar(field.value.type.base_type)) {
+          if (!initializer_list.empty()) { initializer_list += ",\n        "; }
+          initializer_list += Name(field);
+          initializer_list +=
+              "(" +
+              (native_default ? std::string(native_default->constant)
+                              : GetDefaultScalarValue(field, true)) +
+              ")";
+        } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+          if (IsStruct(field.value.type)) {
+            if (native_default) {
+              if (!initializer_list.empty()) {
+                initializer_list += ",\n        ";
+              }
+              initializer_list +=
+                  Name(field) + "(" + native_default->constant + ")";
+            }
+          }
+        } else if (cpp_type && field.value.type.base_type != BASE_TYPE_VECTOR) {
+          if (!initializer_list.empty()) { initializer_list += ",\n        "; }
+          initializer_list += Name(field) + "(0)";
+        }
+      }
+    }
+    if (!initializer_list.empty()) {
+      initializer_list = "\n      : " + initializer_list;
+    }
+
+    code_.SetValue("NATIVE_NAME",
+                   NativeName(Name(struct_def), &struct_def, parser_.opts));
+    code_.SetValue("INIT_LIST", initializer_list);
+
+    code_ += "  {{NATIVE_NAME}}(){{INIT_LIST}} {";
+    code_ += "  }";
+  }
+
+  void GenCompareOperator(const StructDef &struct_def,
+                          std::string accessSuffix = "") {
+    std::string compare_op;
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (!field.deprecated &&  // Deprecated fields won't be accessible.
+          field.value.type.base_type != BASE_TYPE_UTYPE &&
+          (field.value.type.base_type != BASE_TYPE_VECTOR ||
+           field.value.type.element != BASE_TYPE_UTYPE)) {
+        if (!compare_op.empty()) { compare_op += " &&\n      "; }
+        auto accessor = Name(field) + accessSuffix;
+        compare_op += "(lhs." + accessor + " == rhs." + accessor + ")";
+      }
+    }
+
+    std::string cmp_lhs;
+    std::string cmp_rhs;
+    if (compare_op.empty()) {
+      cmp_lhs = "";
+      cmp_rhs = "";
+      compare_op = "  return true;";
+    } else {
+      cmp_lhs = "lhs";
+      cmp_rhs = "rhs";
+      compare_op = "  return\n      " + compare_op + ";";
+    }
+
+    code_.SetValue("CMP_OP", compare_op);
+    code_.SetValue("CMP_LHS", cmp_lhs);
+    code_.SetValue("CMP_RHS", cmp_rhs);
+    code_ += "";
+    code_ +=
+        "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const "
+        "{{NATIVE_NAME}} &{{CMP_RHS}}) {";
+    code_ += "{{CMP_OP}}";
+    code_ += "}";
+
+    code_ += "";
+    code_ +=
+        "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const "
+        "{{NATIVE_NAME}} &rhs) {";
+    code_ += "    return !(lhs == rhs);";
+    code_ += "}";
+    code_ += "";
+  }
+
+  void GenOperatorNewDelete(const StructDef &struct_def) {
+    if (auto native_custom_alloc =
+            struct_def.attributes.Lookup("native_custom_alloc")) {
+      code_ += "  inline void *operator new (std::size_t count) {";
+      code_ += "    return " + native_custom_alloc->constant +
+               "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
+      code_ += "  }";
+      code_ += "  inline void operator delete (void *ptr) {";
+      code_ += "    return " + native_custom_alloc->constant +
+               "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>("
+               "ptr),1);";
+      code_ += "  }";
+    }
+  }
+
+  void GenNativeTable(const StructDef &struct_def) {
+    const auto native_name =
+        NativeName(Name(struct_def), &struct_def, parser_.opts);
+    code_.SetValue("STRUCT_NAME", Name(struct_def));
+    code_.SetValue("NATIVE_NAME", native_name);
+
+    // Generate a C++ object that can hold an unpacked version of this table.
+    code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
+    code_ += "  typedef {{STRUCT_NAME}} TableType;";
+    GenFullyQualifiedNameGetter(struct_def, native_name);
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      GenMember(**it);
+    }
+    GenOperatorNewDelete(struct_def);
+    GenDefaultConstructor(struct_def);
+    code_ += "};";
+    if (parser_.opts.gen_compare) GenCompareOperator(struct_def);
+    code_ += "";
+  }
+
+  // Generate the code to call the appropriate Verify function(s) for a field.
+  void GenVerifyCall(const FieldDef &field, const char *prefix) {
+    code_.SetValue("PRE", prefix);
+    code_.SetValue("NAME", Name(field));
+    code_.SetValue("REQUIRED", field.required ? "Required" : "");
+    code_.SetValue("SIZE", GenTypeSize(field.value.type));
+    code_.SetValue("OFFSET", GenFieldOffsetName(field));
+    if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
+      code_ +=
+          "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
+    } else {
+      code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
+    }
+
+    switch (field.value.type.base_type) {
+      case BASE_TYPE_UNION: {
+        code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
+        code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
+        code_ +=
+            "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
+            "{{NAME}}{{SUFFIX}}())\\";
+        break;
+      }
+      case BASE_TYPE_STRUCT: {
+        if (!field.value.type.struct_def->fixed) {
+          code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
+        }
+        break;
+      }
+      case BASE_TYPE_STRING: {
+        code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
+        break;
+      }
+      case BASE_TYPE_VECTOR: {
+        code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
+
+        switch (field.value.type.element) {
+          case BASE_TYPE_STRING: {
+            code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
+            break;
+          }
+          case BASE_TYPE_STRUCT: {
+            if (!field.value.type.struct_def->fixed) {
+              code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
+            }
+            break;
+          }
+          case BASE_TYPE_UNION: {
+            code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
+            code_ +=
+                "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
+                "{{NAME}}_type())\\";
+            break;
+          }
+          default: break;
+        }
+        break;
+      }
+      default: { break; }
+    }
+  }
+
+  // Generate CompareWithValue method for a key field.
+  void GenKeyFieldMethods(const FieldDef &field) {
+    FLATBUFFERS_ASSERT(field.key);
+    const bool is_string = (field.value.type.base_type == BASE_TYPE_STRING);
+
+    code_ += "  bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
+    if (is_string) {
+      // use operator< of flatbuffers::String
+      code_ += "    return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
+    } else {
+      code_ += "    return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
+    }
+    code_ += "  }";
+
+    if (is_string) {
+      code_ += "  int KeyCompareWithValue(const char *val) const {";
+      code_ += "    return strcmp({{FIELD_NAME}}()->c_str(), val);";
+      code_ += "  }";
+    } else {
+      FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
+      auto type = GenTypeBasic(field.value.type, false);
+      if (parser_.opts.scoped_enums && field.value.type.enum_def &&
+          IsScalar(field.value.type.base_type)) {
+        type = GenTypeGet(field.value.type, " ", "const ", " *", true);
+      }
+      // Returns {field<val: -1, field==val: 0, field>val: +1}.
+      code_.SetValue("KEY_TYPE", type);
+      code_ += "  int KeyCompareWithValue({{KEY_TYPE}} val) const {";
+      code_ +=
+          "    return static_cast<int>({{FIELD_NAME}}() > val) - "
+          "static_cast<int>({{FIELD_NAME}}() < val);";
+      code_ += "  }";
+    }
+  }
+
+  // Generate an accessor struct, builder structs & function for a table.
+  void GenTable(const StructDef &struct_def) {
+    if (parser_.opts.generate_object_based_api) { GenNativeTable(struct_def); }
+
+    // Generate an accessor struct, with methods of the form:
+    // type name() const { return GetField<type>(offset, defaultval); }
+    GenComment(struct_def.doc_comment);
+
+    code_.SetValue("STRUCT_NAME", Name(struct_def));
+    code_ +=
+        "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
+        " : private flatbuffers::Table {";
+    if (parser_.opts.generate_object_based_api) {
+      code_ += "  typedef {{NATIVE_NAME}} NativeTableType;";
+    }
+    if (parser_.opts.mini_reflect != IDLOptions::kNone) {
+      code_ +=
+          "  static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
+      code_ += "    return {{STRUCT_NAME}}TypeTable();";
+      code_ += "  }";
+    }
+
+    GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
+
+    // Generate field id constants.
+    if (struct_def.fields.vec.size() > 0) {
+      // We need to add a trailing comma to all elements except the last one as
+      // older versions of gcc complain about this.
+      code_.SetValue("SEP", "");
+      code_ +=
+          "  enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {";
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        const auto &field = **it;
+        if (field.deprecated) {
+          // Deprecated fields won't be accessible.
+          continue;
+        }
+
+        code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
+        code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
+        code_ += "{{SEP}}    {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
+        code_.SetValue("SEP", ",\n");
+      }
+      code_ += "";
+      code_ += "  };";
+    }
+
+    // Generate the accessors.
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (field.deprecated) {
+        // Deprecated fields won't be accessible.
+        continue;
+      }
+
+      const bool is_struct = IsStruct(field.value.type);
+      const bool is_scalar = IsScalar(field.value.type.base_type);
+      code_.SetValue("FIELD_NAME", Name(field));
+
+      // Call a different accessor for pointers, that indirects.
+      std::string accessor = "";
+      if (is_scalar) {
+        accessor = "GetField<";
+      } else if (is_struct) {
+        accessor = "GetStruct<";
+      } else {
+        accessor = "GetPointer<";
+      }
+      auto offset_str = GenFieldOffsetName(field);
+      auto offset_type =
+          GenTypeGet(field.value.type, "", "const ", " *", false);
+
+      auto call = accessor + offset_type + ">(" + offset_str;
+      // Default value as second arg for non-pointer types.
+      if (is_scalar) { call += ", " + GenDefaultConstant(field); }
+      call += ")";
+
+      std::string afterptr = " *" + NullableExtension();
+      GenComment(field.doc_comment, "  ");
+      code_.SetValue("FIELD_TYPE", GenTypeGet(field.value.type, " ", "const ",
+                                              afterptr.c_str(), true));
+      code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
+      code_.SetValue("NULLABLE_EXT", NullableExtension());
+
+      code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
+      code_ += "    return {{FIELD_VALUE}};";
+      code_ += "  }";
+
+      if (field.value.type.base_type == BASE_TYPE_UNION) {
+        auto u = field.value.type.enum_def;
+
+        if (!field.value.type.enum_def->uses_multiple_type_instances)
+          code_ +=
+              "  template<typename T> "
+              "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
+
+        for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
+          auto &ev = **u_it;
+          if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
+          auto full_struct_name = GetUnionElement(ev, true, true);
+
+          // @TODO: Mby make this decisions more universal? How?
+          code_.SetValue("U_GET_TYPE",
+                         EscapeKeyword(field.name + UnionTypeFieldSuffix()));
+          code_.SetValue(
+              "U_ELEMENT_TYPE",
+              WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
+          code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
+          code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
+          code_.SetValue("U_NULLABLE", NullableExtension());
+
+          // `const Type *union_name_asType() const` accessor.
+          code_ += "  {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
+          code_ +=
+              "    return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
+              "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
+              ": nullptr;";
+          code_ += "  }";
+        }
+      }
+
+      if (parser_.opts.mutable_buffer) {
+        if (is_scalar) {
+          const auto type = GenTypeWire(field.value.type, "", false);
+          code_.SetValue("SET_FN", "SetField<" + type + ">");
+          code_.SetValue("OFFSET_NAME", offset_str);
+          code_.SetValue("FIELD_TYPE", GenTypeBasic(field.value.type, true));
+          code_.SetValue("FIELD_VALUE",
+                         GenUnderlyingCast(field, false, "_" + Name(field)));
+          code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
+
+          code_ +=
+              "  bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
+              "_{{FIELD_NAME}}) {";
+          code_ +=
+              "    return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
+              "{{DEFAULT_VALUE}});";
+          code_ += "  }";
+        } else {
+          auto postptr = " *" + NullableExtension();
+          auto type =
+              GenTypeGet(field.value.type, " ", "", postptr.c_str(), true);
+          auto underlying = accessor + type + ">(" + offset_str + ")";
+          code_.SetValue("FIELD_TYPE", type);
+          code_.SetValue("FIELD_VALUE",
+                         GenUnderlyingCast(field, true, underlying));
+
+          code_ += "  {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
+          code_ += "    return {{FIELD_VALUE}};";
+          code_ += "  }";
+        }
+      }
+
+      auto nested = field.attributes.Lookup("nested_flatbuffer");
+      if (nested) {
+        std::string qualified_name = nested->constant;
+        auto nested_root = parser_.LookupStruct(nested->constant);
+        if (nested_root == nullptr) {
+          qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
+              nested->constant);
+          nested_root = parser_.LookupStruct(qualified_name);
+        }
+        FLATBUFFERS_ASSERT(nested_root);  // Guaranteed to exist by parser.
+        (void)nested_root;
+        code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
+
+        code_ += "  const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
+        code_ +=
+            "    return "
+            "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());";
+        code_ += "  }";
+      }
+
+      if (field.flexbuffer) {
+        code_ +=
+            "  flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
+            " const {";
+        // Both Data() and size() are const-methods, therefore call order
+        // doesn't matter.
+        code_ +=
+            "    return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), "
+            "{{FIELD_NAME}}()->size());";
+        code_ += "  }";
+      }
+
+      // Generate a comparison function for this field if it is a key.
+      if (field.key) { GenKeyFieldMethods(field); }
+    }
+
+    // Generate a verifier function that can check a buffer from an untrusted
+    // source will never cause reads outside the buffer.
+    code_ += "  bool Verify(flatbuffers::Verifier &verifier) const {";
+    code_ += "    return VerifyTableStart(verifier)\\";
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (field.deprecated) { continue; }
+      GenVerifyCall(field, " &&\n           ");
+    }
+
+    code_ += " &&\n           verifier.EndTable();";
+    code_ += "  }";
+
+    if (parser_.opts.generate_object_based_api) {
+      // Generate the UnPack() pre declaration.
+      code_ +=
+          "  " + TableUnPackSignature(struct_def, true, parser_.opts) + ";";
+      code_ +=
+          "  " + TableUnPackToSignature(struct_def, true, parser_.opts) + ";";
+      code_ += "  " + TablePackSignature(struct_def, true, parser_.opts) + ";";
+    }
+
+    code_ += "};";  // End of table.
+    code_ += "";
+
+    // Explicit specializations for union accessors
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
+        continue;
+      }
+
+      auto u = field.value.type.enum_def;
+      if (u->uses_multiple_type_instances) continue;
+
+      code_.SetValue("FIELD_NAME", Name(field));
+
+      for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
+        auto &ev = **u_it;
+        if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
+
+        auto full_struct_name = GetUnionElement(ev, true, true);
+
+        code_.SetValue(
+            "U_ELEMENT_TYPE",
+            WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
+        code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
+        code_.SetValue("U_ELEMENT_NAME", full_struct_name);
+        code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
+
+        // `template<> const T *union_name_as<T>() const` accessor.
+        code_ +=
+            "template<> "
+            "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
+            "<{{U_ELEMENT_NAME}}>() const {";
+        code_ += "  return {{U_FIELD_NAME}}();";
+        code_ += "}";
+        code_ += "";
+      }
+    }
+
+    GenBuilders(struct_def);
+
+    if (parser_.opts.generate_object_based_api) {
+      // Generate a pre-declaration for a CreateX method that works with an
+      // unpacked C++ object.
+      code_ += TableCreateSignature(struct_def, true, parser_.opts) + ";";
+      code_ += "";
+    }
+  }
+
+  void GenBuilders(const StructDef &struct_def) {
+    code_.SetValue("STRUCT_NAME", Name(struct_def));
+
+    // Generate a builder struct:
+    code_ += "struct {{STRUCT_NAME}}Builder {";
+    code_ += "  flatbuffers::FlatBufferBuilder &fbb_;";
+    code_ += "  flatbuffers::uoffset_t start_;";
+
+    bool has_string_or_vector_fields = false;
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (!field.deprecated) {
+        const bool is_scalar = IsScalar(field.value.type.base_type);
+        const bool is_string = field.value.type.base_type == BASE_TYPE_STRING;
+        const bool is_vector = field.value.type.base_type == BASE_TYPE_VECTOR;
+        if (is_string || is_vector) { has_string_or_vector_fields = true; }
+
+        std::string offset = GenFieldOffsetName(field);
+        std::string name = GenUnderlyingCast(field, false, Name(field));
+        std::string value = is_scalar ? GenDefaultConstant(field) : "";
+
+        // Generate accessor functions of the form:
+        // void add_name(type name) {
+        //   fbb_.AddElement<type>(offset, name, default);
+        // }
+        code_.SetValue("FIELD_NAME", Name(field));
+        code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
+        code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
+        code_.SetValue("ADD_NAME", name);
+        code_.SetValue("ADD_VALUE", value);
+        if (is_scalar) {
+          const auto type = GenTypeWire(field.value.type, "", false);
+          code_.SetValue("ADD_FN", "AddElement<" + type + ">");
+        } else if (IsStruct(field.value.type)) {
+          code_.SetValue("ADD_FN", "AddStruct");
+        } else {
+          code_.SetValue("ADD_FN", "AddOffset");
+        }
+
+        code_ += "  void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
+        code_ += "    fbb_.{{ADD_FN}}(\\";
+        if (is_scalar) {
+          code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
+        } else {
+          code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
+        }
+        code_ += "  }";
+      }
+    }
+
+    // Builder constructor
+    code_ +=
+        "  explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder "
+        "&_fbb)";
+    code_ += "        : fbb_(_fbb) {";
+    code_ += "    start_ = fbb_.StartTable();";
+    code_ += "  }";
+
+    // Assignment operator;
+    code_ +=
+        "  {{STRUCT_NAME}}Builder &operator="
+        "(const {{STRUCT_NAME}}Builder &);";
+
+    // Finish() function.
+    code_ += "  flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
+    code_ += "    const auto end = fbb_.EndTable(start_);";
+    code_ += "    auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
+
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (!field.deprecated && field.required) {
+        code_.SetValue("FIELD_NAME", Name(field));
+        code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
+        code_ += "    fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
+      }
+    }
+    code_ += "    return o;";
+    code_ += "  }";
+    code_ += "};";
+    code_ += "";
+
+    // Generate a convenient CreateX function that uses the above builder
+    // to create a table in one go.
+    code_ +=
+        "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
+        "Create{{STRUCT_NAME}}(";
+    code_ += "    flatbuffers::FlatBufferBuilder &_fbb\\";
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (!field.deprecated) { GenParam(field, false, ",\n    "); }
+    }
+    code_ += ") {";
+
+    code_ += "  {{STRUCT_NAME}}Builder builder_(_fbb);";
+    for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
+         size; size /= 2) {
+      for (auto it = struct_def.fields.vec.rbegin();
+           it != struct_def.fields.vec.rend(); ++it) {
+        const auto &field = **it;
+        if (!field.deprecated && (!struct_def.sortbysize ||
+                                  size == SizeOf(field.value.type.base_type))) {
+          code_.SetValue("FIELD_NAME", Name(field));
+          code_ += "  builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
+        }
+      }
+    }
+    code_ += "  return builder_.Finish();";
+    code_ += "}";
+    code_ += "";
+
+    // Generate a CreateXDirect function with vector types as parameters
+    if (has_string_or_vector_fields) {
+      code_ +=
+          "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
+          "Create{{STRUCT_NAME}}Direct(";
+      code_ += "    flatbuffers::FlatBufferBuilder &_fbb\\";
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        const auto &field = **it;
+        if (!field.deprecated) { GenParam(field, true, ",\n    "); }
+      }
+      // Need to call "Create" with the struct namespace.
+      const auto qualified_create_name =
+          struct_def.defined_namespace->GetFullyQualifiedName("Create");
+      code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
+      code_ += ") {";
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        const auto &field = **it;
+        if (!field.deprecated) {
+          code_.SetValue("FIELD_NAME", Name(field));
+          if (field.value.type.base_type == BASE_TYPE_STRING) {
+            if (!field.shared) {
+              code_.SetValue("CREATE_STRING", "CreateString");
+            } else {
+              code_.SetValue("CREATE_STRING", "CreateSharedString");
+            }
+            code_ +=
+                "  auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
+                "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
+          } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+            code_ += "  auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
+            const auto vtype = field.value.type.VectorType();
+            if (IsStruct(vtype)) {
+              const auto type = WrapInNameSpace(*vtype.struct_def);
+              code_ += "_fbb.CreateVectorOfStructs<" + type + ">\\";
+            } else {
+              const auto type = GenTypeWire(vtype, "", false);
+              code_ += "_fbb.CreateVector<" + type + ">\\";
+            }
+            code_ += "(*{{FIELD_NAME}}) : 0;";
+          }
+        }
+      }
+      code_ += "  return {{CREATE_NAME}}{{STRUCT_NAME}}(";
+      code_ += "      _fbb\\";
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        const auto &field = **it;
+        if (!field.deprecated) {
+          code_.SetValue("FIELD_NAME", Name(field));
+          code_ += ",\n      {{FIELD_NAME}}\\";
+          if (field.value.type.base_type == BASE_TYPE_STRING ||
+              field.value.type.base_type == BASE_TYPE_VECTOR) {
+            code_ += "__\\";
+          }
+        }
+      }
+      code_ += ");";
+      code_ += "}";
+      code_ += "";
+    }
+  }
+
+  std::string GenUnionUnpackVal(const FieldDef &afield,
+                                const char *vec_elem_access,
+                                const char *vec_type_access) {
+    return afield.value.type.enum_def->name + "Union::UnPack(" + "_e" +
+           vec_elem_access + ", " +
+           EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
+           vec_type_access + ", _resolver)";
+  }
+
+  std::string GenUnpackVal(const Type &type, const std::string &val,
+                           bool invector, const FieldDef &afield) {
+    switch (type.base_type) {
+      case BASE_TYPE_STRING: {
+        if (FlexibleStringConstructor(&afield)) {
+          return NativeString(&afield) + "(" + val + "->c_str(), " + val +
+                 "->size())";
+        } else {
+          return val + "->str()";
+        }
+      }
+      case BASE_TYPE_STRUCT: {
+        const auto name = WrapInNameSpace(*type.struct_def);
+        if (IsStruct(type)) {
+          auto native_type = type.struct_def->attributes.Lookup("native_type");
+          if (native_type) {
+            return "flatbuffers::UnPack(*" + val + ")";
+          } else if (invector || afield.native_inline) {
+            return "*" + val;
+          } else {
+            const auto ptype = GenTypeNativePtr(name, &afield, true);
+            return ptype + "(new " + name + "(*" + val + "))";
+          }
+        } else {
+          const auto ptype = GenTypeNativePtr(
+              NativeName(name, type.struct_def, parser_.opts), &afield, true);
+          return ptype + "(" + val + "->UnPack(_resolver))";
+        }
+      }
+      case BASE_TYPE_UNION: {
+        return GenUnionUnpackVal(
+            afield, invector ? "->Get(_i)" : "",
+            invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str()
+                     : "");
+      }
+      default: {
+        return val;
+        break;
+      }
+    }
+  }
+
+  std::string GenUnpackFieldStatement(const FieldDef &field,
+                                      const FieldDef *union_field) {
+    std::string code;
+    switch (field.value.type.base_type) {
+      case BASE_TYPE_VECTOR: {
+        auto cpp_type = field.attributes.Lookup("cpp_type");
+        std::string indexing;
+        if (field.value.type.enum_def) {
+          indexing += "static_cast<" +
+                      WrapInNameSpace(*field.value.type.enum_def) + ">(";
+        }
+        indexing += "_e->Get(_i)";
+        if (field.value.type.enum_def) { indexing += ")"; }
+        if (field.value.type.element == BASE_TYPE_BOOL) { indexing += " != 0"; }
+
+        // Generate code that pushes data from _e to _o in the form:
+        //   for (uoffset_t i = 0; i < _e->size(); ++i) {
+        //     _o->field.push_back(_e->Get(_i));
+        //   }
+        auto name = Name(field);
+        if (field.value.type.element == BASE_TYPE_UTYPE) {
+          name = StripUnionType(Name(field));
+        }
+        auto access =
+            field.value.type.element == BASE_TYPE_UTYPE
+                ? ".type"
+                : (field.value.type.element == BASE_TYPE_UNION ? ".value" : "");
+        code += "{ _o->" + name + ".resize(_e->size()); ";
+        code += "for (flatbuffers::uoffset_t _i = 0;";
+        code += " _i < _e->size(); _i++) { ";
+        if (cpp_type) {
+          // Generate code that resolves the cpp pointer type, of the form:
+          //  if (resolver)
+          //    (*resolver)(&_o->field, (hash_value_t)(_e));
+          //  else
+          //    _o->field = nullptr;
+          code += "//vector resolver, " + PtrType(&field) + "\n";
+          code += "if (_resolver) ";
+          code += "(*_resolver)";
+          code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" + access +
+                  "), ";
+          code += "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
+          if (PtrType(&field) == "naked") {
+            code += " else ";
+            code += "_o->" + name + "[_i]" + access + " = nullptr";
+          } else {
+            // code += " else ";
+            // code += "_o->" + name + "[_i]" + access + " = " +
+            // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
+            code += "/* else do nothing */";
+          }
+        } else {
+          code += "_o->" + name + "[_i]" + access + " = ";
+          code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
+                               field);
+        }
+        code += "; } }";
+        break;
+      }
+      case BASE_TYPE_UTYPE: {
+        FLATBUFFERS_ASSERT(union_field->value.type.base_type ==
+                           BASE_TYPE_UNION);
+        // Generate code that sets the union type, of the form:
+        //   _o->field.type = _e;
+        code += "_o->" + union_field->name + ".type = _e;";
+        break;
+      }
+      case BASE_TYPE_UNION: {
+        // Generate code that sets the union value, of the form:
+        //   _o->field.value = Union::Unpack(_e, field_type(), resolver);
+        code += "_o->" + Name(field) + ".value = ";
+        code += GenUnionUnpackVal(field, "", "");
+        code += ";";
+        break;
+      }
+      default: {
+        auto cpp_type = field.attributes.Lookup("cpp_type");
+        if (cpp_type) {
+          // Generate code that resolves the cpp pointer type, of the form:
+          //  if (resolver)
+          //    (*resolver)(&_o->field, (hash_value_t)(_e));
+          //  else
+          //    _o->field = nullptr;
+          code += "//scalar resolver, " + PtrType(&field) + " \n";
+          code += "if (_resolver) ";
+          code += "(*_resolver)";
+          code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
+          code += "static_cast<flatbuffers::hash_value_t>(_e));";
+          if (PtrType(&field) == "naked") {
+            code += " else ";
+            code += "_o->" + Name(field) + " = nullptr;";
+          } else {
+            // code += " else ";
+            // code += "_o->" + Name(field) + " = " +
+            // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
+            code += "/* else do nothing */;";
+          }
+        } else {
+          // Generate code for assigning the value, of the form:
+          //  _o->field = value;
+          code += "_o->" + Name(field) + " = ";
+          code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
+        }
+        break;
+      }
+    }
+    return code;
+  }
+
+  std::string GenCreateParam(const FieldDef &field) {
+    const IDLOptions &opts = parser_.opts;
+
+    std::string value = "_o->";
+    if (field.value.type.base_type == BASE_TYPE_UTYPE) {
+      value += StripUnionType(Name(field));
+      value += ".type";
+    } else {
+      value += Name(field);
+    }
+    if (field.value.type.base_type != BASE_TYPE_VECTOR &&
+        field.attributes.Lookup("cpp_type")) {
+      auto type = GenTypeBasic(field.value.type, false);
+      value =
+          "_rehasher ? "
+          "static_cast<" +
+          type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0";
+    }
+
+    std::string code;
+    switch (field.value.type.base_type) {
+      // String fields are of the form:
+      //   _fbb.CreateString(_o->field)
+      // or
+      //   _fbb.CreateSharedString(_o->field)
+      case BASE_TYPE_STRING: {
+        if (!field.shared) {
+          code += "_fbb.CreateString(";
+        } else {
+          code += "_fbb.CreateSharedString(";
+        }
+        code += value;
+        code.push_back(')');
+
+        // For optional fields, check to see if there actually is any data
+        // in _o->field before attempting to access it. If there isn't,
+        // depending on set_empty_to_null either set it to 0 or an empty string.
+        if (!field.required) {
+          auto empty_value =
+              opts.set_empty_to_null ? "0" : "_fbb.CreateSharedString(\"\")";
+          code = value + ".empty() ? " + empty_value + " : " + code;
+        }
+        break;
+      }
+      // Vector fields come in several flavours, of the forms:
+      //   _fbb.CreateVector(_o->field);
+      //   _fbb.CreateVector((const utype*)_o->field.data(), _o->field.size());
+      //   _fbb.CreateVectorOfStrings(_o->field)
+      //   _fbb.CreateVectorOfStructs(_o->field)
+      //   _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
+      //     return CreateT(_fbb, _o->Get(i), rehasher);
+      //   });
+      case BASE_TYPE_VECTOR: {
+        auto vector_type = field.value.type.VectorType();
+        switch (vector_type.base_type) {
+          case BASE_TYPE_STRING: {
+            if (NativeString(&field) == "std::string") {
+              code += "_fbb.CreateVectorOfStrings(" + value + ")";
+            } else {
+              // Use by-function serialization to emulate
+              // CreateVectorOfStrings(); this works also with non-std strings.
+              code +=
+                  "_fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>"
+                  " ";
+              code += "(" + value + ".size(), ";
+              code += "[](size_t i, _VectorArgs *__va) { ";
+              code +=
+                  "return __va->__fbb->CreateString(__va->_" + value + "[i]);";
+              code += " }, &_va )";
+            }
+            break;
+          }
+          case BASE_TYPE_STRUCT: {
+            if (IsStruct(vector_type)) {
+              auto native_type =
+                  field.value.type.struct_def->attributes.Lookup("native_type");
+              if (native_type) {
+                code += "_fbb.CreateVectorOfNativeStructs<";
+                code += WrapInNameSpace(*vector_type.struct_def) + ">";
+              } else {
+                code += "_fbb.CreateVectorOfStructs";
+              }
+              code += "(" + value + ")";
+            } else {
+              code += "_fbb.CreateVector<flatbuffers::Offset<";
+              code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
+              code += "(" + value + ".size(), ";
+              code += "[](size_t i, _VectorArgs *__va) { ";
+              code += "return Create" + vector_type.struct_def->name;
+              code += "(*__va->__fbb, __va->_" + value + "[i]" +
+                      GenPtrGet(field) + ", ";
+              code += "__va->__rehasher); }, &_va )";
+            }
+            break;
+          }
+          case BASE_TYPE_BOOL: {
+            code += "_fbb.CreateVector(" + value + ")";
+            break;
+          }
+          case BASE_TYPE_UNION: {
+            code +=
+                "_fbb.CreateVector<flatbuffers::"
+                "Offset<void>>(" +
+                value +
+                ".size(), [](size_t i, _VectorArgs *__va) { "
+                "return __va->_" +
+                value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
+            break;
+          }
+          case BASE_TYPE_UTYPE: {
+            value = StripUnionType(value);
+            code += "_fbb.CreateVector<uint8_t>(" + value +
+                    ".size(), [](size_t i, _VectorArgs *__va) { "
+                    "return static_cast<uint8_t>(__va->_" +
+                    value + "[i].type); }, &_va)";
+            break;
+          }
+          default: {
+            if (field.value.type.enum_def) {
+              // For enumerations, we need to get access to the array data for
+              // the underlying storage type (eg. uint8_t).
+              const auto basetype = GenTypeBasic(
+                  field.value.type.enum_def->underlying_type, false);
+              code += "_fbb.CreateVectorScalarCast<" + basetype +
+                      ">(flatbuffers::data(" + value + "), " + value +
+                      ".size())";
+            } else if (field.attributes.Lookup("cpp_type")) {
+              auto type = GenTypeBasic(vector_type, false);
+              code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
+              code += "[](size_t i, _VectorArgs *__va) { ";
+              code += "return __va->__rehasher ? ";
+              code += "static_cast<" + type + ">((*__va->__rehasher)";
+              code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
+              code += "; }, &_va )";
+            } else {
+              code += "_fbb.CreateVector(" + value + ")";
+            }
+            break;
+          }
+        }
+
+        // If set_empty_to_null option is enabled, for optional fields, check to
+        // see if there actually is any data in _o->field before attempting to
+        // access it.
+        if (opts.set_empty_to_null && !field.required) {
+          code = value + ".size() ? " + code + " : 0";
+        }
+        break;
+      }
+      case BASE_TYPE_UNION: {
+        // _o->field.Pack(_fbb);
+        code += value + ".Pack(_fbb)";
+        break;
+      }
+      case BASE_TYPE_STRUCT: {
+        if (IsStruct(field.value.type)) {
+          auto native_type =
+              field.value.type.struct_def->attributes.Lookup("native_type");
+          if (native_type) {
+            code += "flatbuffers::Pack(" + value + ")";
+          } else if (field.native_inline) {
+            code += "&" + value;
+          } else {
+            code += value + " ? " + value + GenPtrGet(field) + " : 0";
+          }
+        } else {
+          // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
+          const auto type = field.value.type.struct_def->name;
+          code += value + " ? Create" + type;
+          code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
+          code += " : 0";
+        }
+        break;
+      }
+      default: {
+        code += value;
+        break;
+      }
+    }
+    return code;
+  }
+
+  // Generate code for tables that needs to come after the regular definition.
+  void GenTablePost(const StructDef &struct_def) {
+    code_.SetValue("STRUCT_NAME", Name(struct_def));
+    code_.SetValue("NATIVE_NAME",
+                   NativeName(Name(struct_def), &struct_def, parser_.opts));
+
+    if (parser_.opts.generate_object_based_api) {
+      // Generate the X::UnPack() method.
+      code_ += "inline " +
+               TableUnPackSignature(struct_def, false, parser_.opts) + " {";
+      code_ += "  auto _o = new {{NATIVE_NAME}}();";
+      code_ += "  UnPackTo(_o, _resolver);";
+      code_ += "  return _o;";
+      code_ += "}";
+      code_ += "";
+
+      code_ += "inline " +
+               TableUnPackToSignature(struct_def, false, parser_.opts) + " {";
+      code_ += "  (void)_o;";
+      code_ += "  (void)_resolver;";
+
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        const auto &field = **it;
+        if (field.deprecated) { continue; }
+
+        // Assign a value from |this| to |_o|.   Values from |this| are stored
+        // in a variable |_e| by calling this->field_type().  The value is then
+        // assigned to |_o| using the GenUnpackFieldStatement.
+        const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
+        const auto statement =
+            GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
+
+        code_.SetValue("FIELD_NAME", Name(field));
+        auto prefix = "  { auto _e = {{FIELD_NAME}}(); ";
+        auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
+        auto postfix = " };";
+        code_ += std::string(prefix) + check + statement + postfix;
+      }
+      code_ += "}";
+      code_ += "";
+
+      // Generate the X::Pack member function that simply calls the global
+      // CreateX function.
+      code_ += "inline " + TablePackSignature(struct_def, false, parser_.opts) +
+               " {";
+      code_ += "  return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
+      code_ += "}";
+      code_ += "";
+
+      // Generate a CreateX method that works with an unpacked C++ object.
+      code_ += "inline " +
+               TableCreateSignature(struct_def, false, parser_.opts) + " {";
+      code_ += "  (void)_rehasher;";
+      code_ += "  (void)_o;";
+
+      code_ +=
+          "  struct _VectorArgs "
+          "{ flatbuffers::FlatBufferBuilder *__fbb; "
+          "const " +
+          NativeName(Name(struct_def), &struct_def, parser_.opts) +
+          "* __o; "
+          "const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
+          "&_fbb, _o, _rehasher}; (void)_va;";
+
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        auto &field = **it;
+        if (field.deprecated) { continue; }
+        code_ += "  auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
+      }
+      // Need to call "Create" with the struct namespace.
+      const auto qualified_create_name =
+          struct_def.defined_namespace->GetFullyQualifiedName("Create");
+      code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
+
+      code_ += "  return {{CREATE_NAME}}{{STRUCT_NAME}}(";
+      code_ += "      _fbb\\";
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        auto &field = **it;
+        if (field.deprecated) { continue; }
+
+        bool pass_by_address = false;
+        if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+          if (IsStruct(field.value.type)) {
+            auto native_type =
+                field.value.type.struct_def->attributes.Lookup("native_type");
+            if (native_type) { pass_by_address = true; }
+          }
+        }
+
+        // Call the CreateX function using values from |_o|.
+        if (pass_by_address) {
+          code_ += ",\n      &_" + Name(field) + "\\";
+        } else {
+          code_ += ",\n      _" + Name(field) + "\\";
+        }
+      }
+      code_ += ");";
+      code_ += "}";
+      code_ += "";
+    }
+  }
+
+  static void GenPadding(
+      const FieldDef &field, std::string *code_ptr, int *id,
+      const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
+    if (field.padding) {
+      for (int i = 0; i < 4; i++) {
+        if (static_cast<int>(field.padding) & (1 << i)) {
+          f((1 << i) * 8, code_ptr, id);
+        }
+      }
+      FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
+    }
+  }
+
+  static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
+    *code_ptr += "  int" + NumToString(bits) + "_t padding" +
+                 NumToString((*id)++) + "__;";
+  }
+
+  static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
+    (void)bits;
+    if (*code_ptr != "") *code_ptr += ",\n        ";
+    *code_ptr += "padding" + NumToString((*id)++) + "__(0)";
+  }
+
+  static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
+    (void)bits;
+    *code_ptr += "    (void)padding" + NumToString((*id)++) + "__;";
+  }
+
+  // Generate an accessor struct with constructor for a flatbuffers struct.
+  void GenStruct(const StructDef &struct_def) {
+    // Generate an accessor struct, with private variables of the form:
+    // type name_;
+    // Generates manual padding and alignment.
+    // Variables are private because they contain little endian data on all
+    // platforms.
+    GenComment(struct_def.doc_comment);
+    code_.SetValue("ALIGN", NumToString(struct_def.minalign));
+    code_.SetValue("STRUCT_NAME", Name(struct_def));
+
+    code_ +=
+        "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
+        "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
+    code_ += " private:";
+
+    int padding_id = 0;
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      const auto &field_type = field.value.type;
+      code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false));
+      code_.SetValue("FIELD_NAME", Name(field));
+      code_.SetValue("ARRAY",
+                     IsArray(field_type)
+                         ? "[" + NumToString(field_type.fixed_length) + "]"
+                         : "");
+      code_ += ("  {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};");
+
+      if (field.padding) {
+        std::string padding;
+        GenPadding(field, &padding, &padding_id, PaddingDefinition);
+        code_ += padding;
+      }
+    }
+
+    // Generate GetFullyQualifiedName
+    code_ += "";
+    code_ += " public:";
+
+    // Make TypeTable accessible via the generated struct.
+    if (parser_.opts.mini_reflect != IDLOptions::kNone) {
+      code_ +=
+          "  static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
+      code_ += "    return {{STRUCT_NAME}}TypeTable();";
+      code_ += "  }";
+    }
+
+    GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
+
+    // Generate a default constructor.
+    code_ += "  {{STRUCT_NAME}}() {";
+    code_ +=
+        "    memset(static_cast<void *>(this), 0, sizeof({{STRUCT_NAME}}));";
+    code_ += "  }";
+
+    // Generate a constructor that takes all fields as arguments,
+    // excluding arrays
+    std::string arg_list;
+    std::string init_list;
+    padding_id = 0;
+    auto first = struct_def.fields.vec.begin();
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (IsArray(field.value.type)) {
+        first++;
+        continue;
+      }
+      const auto member_name = Name(field) + "_";
+      const auto arg_name = "_" + Name(field);
+      const auto arg_type =
+          GenTypeGet(field.value.type, " ", "const ", " &", true);
+
+      if (it != first) { arg_list += ", "; }
+      arg_list += arg_type;
+      arg_list += arg_name;
+      if (!IsArray(field.value.type)) {
+        if (it != first && init_list != "") { init_list += ",\n        "; }
+        init_list += member_name;
+        if (IsScalar(field.value.type.base_type)) {
+          auto type = GenUnderlyingCast(field, false, arg_name);
+          init_list += "(flatbuffers::EndianScalar(" + type + "))";
+        } else {
+          init_list += "(" + arg_name + ")";
+        }
+      }
+      if (field.padding) {
+        GenPadding(field, &init_list, &padding_id, PaddingInitializer);
+      }
+    }
+
+    if (!arg_list.empty()) {
+      code_.SetValue("ARG_LIST", arg_list);
+      code_.SetValue("INIT_LIST", init_list);
+      if (!init_list.empty()) {
+        code_ += "  {{STRUCT_NAME}}({{ARG_LIST}})";
+        code_ += "      : {{INIT_LIST}} {";
+      } else {
+        code_ += "  {{STRUCT_NAME}}({{ARG_LIST}}) {";
+      }
+      padding_id = 0;
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        const auto &field = **it;
+        if (IsArray(field.value.type)) {
+          const auto &member = Name(field) + "_";
+          code_ +=
+              "    std::memset(" + member + ", 0, sizeof(" + member + "));";
+        }
+        if (field.padding) {
+          std::string padding;
+          GenPadding(field, &padding, &padding_id, PaddingNoop);
+          code_ += padding;
+        }
+      }
+      code_ += "  }";
+    }
+
+    // Generate accessor methods of the form:
+    // type name() const { return flatbuffers::EndianScalar(name_); }
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+
+      auto field_type = GenTypeGet(field.value.type, " ",
+                                   IsArray(field.value.type) ? "" : "const ",
+                                   IsArray(field.value.type) ? "" : " &", true);
+      auto is_scalar = IsScalar(field.value.type.base_type);
+      auto member = Name(field) + "_";
+      auto value =
+          is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
+
+      code_.SetValue("FIELD_NAME", Name(field));
+      code_.SetValue("FIELD_TYPE", field_type);
+      code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
+
+      GenComment(field.doc_comment, "  ");
+
+      // Generate a const accessor function.
+      if (IsArray(field.value.type)) {
+        auto underlying = GenTypeGet(field.value.type, "", "", "", false);
+        code_ += "  const flatbuffers::Array<" + field_type + ", " +
+                 NumToString(field.value.type.fixed_length) + "> *" +
+                 "{{FIELD_NAME}}() const {";
+        code_ += "    return reinterpret_cast<const flatbuffers::Array<" +
+                 field_type + ", " +
+                 NumToString(field.value.type.fixed_length) +
+                 "> *>({{FIELD_VALUE}});";
+        code_ += "  }";
+      } else {
+        code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
+        code_ += "    return {{FIELD_VALUE}};";
+        code_ += "  }";
+      }
+
+      // Generate a mutable accessor function.
+      if (parser_.opts.mutable_buffer) {
+        auto mut_field_type =
+            GenTypeGet(field.value.type, " ", "",
+                       IsArray(field.value.type) ? "" : " &", true);
+        code_.SetValue("FIELD_TYPE", mut_field_type);
+        if (is_scalar) {
+          code_.SetValue("ARG", GenTypeBasic(field.value.type, true));
+          code_.SetValue("FIELD_VALUE",
+                         GenUnderlyingCast(field, false, "_" + Name(field)));
+
+          code_ += "  void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
+          code_ +=
+              "    flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
+              "{{FIELD_VALUE}});";
+          code_ += "  }";
+        } else if (IsArray(field.value.type)) {
+          auto underlying = GenTypeGet(field.value.type, "", "", "", false);
+          code_ += "  flatbuffers::Array<" + mut_field_type + ", " +
+                   NumToString(field.value.type.fixed_length) +
+                   "> *" + "mutable_{{FIELD_NAME}}() {";
+          code_ += "    return reinterpret_cast<flatbuffers::Array<" +
+                   mut_field_type + ", " +
+                   NumToString(field.value.type.fixed_length) +
+                   "> *>({{FIELD_VALUE}});";
+          code_ += "  }";
+        } else {
+          code_ += "  {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
+          code_ += "    return {{FIELD_VALUE}};";
+          code_ += "  }";
+        }
+      }
+
+      // Generate a comparison function for this field if it is a key.
+      if (field.key) { GenKeyFieldMethods(field); }
+    }
+    code_.SetValue("NATIVE_NAME", Name(struct_def));
+    GenOperatorNewDelete(struct_def);
+    code_ += "};";
+
+    code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
+    code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
+    if (parser_.opts.gen_compare) GenCompareOperator(struct_def, "()");
+    code_ += "";
+  }
+
+  // Set up the correct namespace. Only open a namespace if the existing one is
+  // different (closing/opening only what is necessary).
+  //
+  // The file must start and end with an empty (or null) namespace so that
+  // namespaces are properly opened and closed.
+  void SetNameSpace(const Namespace *ns) {
+    if (cur_name_space_ == ns) { return; }
+
+    // Compute the size of the longest common namespace prefix.
+    // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
+    // the common prefix is A::B:: and we have old_size = 4, new_size = 5
+    // and common_prefix_size = 2
+    size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
+    size_t new_size = ns ? ns->components.size() : 0;
+
+    size_t common_prefix_size = 0;
+    while (common_prefix_size < old_size && common_prefix_size < new_size &&
+           ns->components[common_prefix_size] ==
+               cur_name_space_->components[common_prefix_size]) {
+      common_prefix_size++;
+    }
+
+    // Close cur_name_space in reverse order to reach the common prefix.
+    // In the previous example, D then C are closed.
+    for (size_t j = old_size; j > common_prefix_size; --j) {
+      code_ += "}  // namespace " + cur_name_space_->components[j - 1];
+    }
+    if (old_size != common_prefix_size) { code_ += ""; }
+
+    // open namespace parts to reach the ns namespace
+    // in the previous example, E, then F, then G are opened
+    for (auto j = common_prefix_size; j != new_size; ++j) {
+      code_ += "namespace " + ns->components[j] + " {";
+    }
+    if (new_size != common_prefix_size) { code_ += ""; }
+
+    cur_name_space_ = ns;
+  }
+
+  const TypedFloatConstantGenerator float_const_gen_;
+};
+
+}  // namespace cpp
+
+bool GenerateCPP(const Parser &parser, const std::string &path,
+                 const std::string &file_name) {
+  cpp::CppGenerator generator(parser, path, file_name);
+  return generator.generate();
+}
+
+std::string CPPMakeRule(const Parser &parser, const std::string &path,
+                        const std::string &file_name) {
+  const auto filebase =
+      flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+  const auto included_files = parser.GetIncludedFilesRecursive(file_name);
+  std::string make_rule = GeneratedFileName(path, filebase) + ": ";
+  for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+    make_rule += " " + *it;
+  }
+  return make_rule;
+}
+
+}  // namespace flatbuffers
diff --git a/src/idl_gen_dart.cpp b/src/idl_gen_dart.cpp
new file mode 100644
index 0000000..2346a85
--- /dev/null
+++ b/src/idl_gen_dart.cpp
@@ -0,0 +1,914 @@
+/*
+ * Copyright 2018 Dan Field
+ *
+ * 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.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+#include <cassert>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+static std::string GeneratedFileName(const std::string &path,
+                                     const std::string &file_name) {
+  return path + file_name + "_generated.dart";
+}
+
+namespace dart {
+
+const std::string _kFb = "fb";
+// see https://www.dartlang.org/guides/language/language-tour#keywords
+// yeild*, async*, and sync* shouldn't be problems anyway but keeping them in
+static const char *keywords[] = {
+  "abstract",   "deferred", "if",       "super",   "as",       "do",
+  "implements", "switch",   "assert",   "dynamic", "import",   "sync*",
+  "async",      "else",     "in",       "this",    "async*",   "enum",
+  "is",         "throw",    "await",    "export",  "library",  "true",
+  "break",      "external", "new",      "try",     "case",     "extends",
+  "null",       "typedef",  "catch",    "factory", "operator", "var",
+  "class",      "false",    "part",     "void",    "const",    "final",
+  "rethrow",    "while",    "continue", "finally", "return",   "with",
+  "covariant",  "for",      "set",      "yield",   "default",  "get",
+  "static",     "yield*"
+};
+
+// Iterate through all definitions we haven't generate code for (enums, structs,
+// and tables) and output them to a single file.
+class DartGenerator : public BaseGenerator {
+ public:
+  typedef std::map<std::string, std::string> namespace_code_map;
+
+  DartGenerator(const Parser &parser, const std::string &path,
+                const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "", ".") {}
+  // Iterate through all definitions we haven't generate code for (enums,
+  // structs, and tables) and output them to a single file.
+  bool generate() {
+    std::string code;
+    namespace_code_map namespace_code;
+    GenerateEnums(&namespace_code);
+    GenerateStructs(&namespace_code);
+
+    for (auto kv = namespace_code.begin(); kv != namespace_code.end(); ++kv) {
+      code.clear();
+      code = code + "// " + FlatBuffersGeneratedWarning() + "\n";
+      code = code +
+             "// ignore_for_file: unused_import, unused_field, "
+             "unused_local_variable\n\n";
+
+      code += "library " + kv->first + ";\n\n";
+
+      code += "import 'dart:typed_data' show Uint8List;\n";
+      code += "import 'package:flat_buffers/flat_buffers.dart' as " + _kFb +
+              ";\n\n";
+
+      if (parser_.opts.include_dependence_headers) {
+        GenIncludeDependencies(&code, kv->first);
+      }
+
+      for (auto kv2 = namespace_code.begin(); kv2 != namespace_code.end();
+           ++kv2) {
+        if (kv2->first != kv->first) {
+          code += "import '" +
+                  GeneratedFileName("./", file_name_ + "_" + kv2->first) +
+                  "' as " + ImportAliasName(kv2->first) + ";\n";
+        }
+      }
+      code += "\n";
+      code += kv->second;
+
+      if (!SaveFile(
+              GeneratedFileName(path_, file_name_ + "_" + kv->first).c_str(),
+              code, false)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  static std::string ImportAliasName(const std::string &ns) {
+    std::string ret;
+    ret.assign(ns);
+    size_t pos = ret.find('.');
+    while (pos != std::string::npos) {
+      ret.replace(pos, 1, "_");
+      pos = ret.find('.', pos + 1);
+    }
+
+    return ret;
+  }
+
+  static std::string BuildNamespaceName(const Namespace &ns) {
+    std::stringstream sstream;
+    std::copy(ns.components.begin(), ns.components.end() - 1,
+              std::ostream_iterator<std::string>(sstream, "."));
+
+    auto ret = sstream.str() + ns.components.back();
+    for (size_t i = 0; i < ret.size(); i++) {
+      auto lower = tolower(ret[i]);
+      if (lower != ret[i]) {
+        ret[i] = static_cast<char>(lower);
+        if (i != 0 && ret[i - 1] != '.') {
+          ret.insert(i, "_");
+          i++;
+        }
+      }
+    }
+    // std::transform(ret.begin(), ret.end(), ret.begin(), ::tolower);
+    return ret;
+  }
+
+  void GenIncludeDependencies(std::string* code, const std::string& the_namespace) {
+    for (auto it = parser_.included_files_.begin();
+         it != parser_.included_files_.end(); ++it) {
+      if (it->second.empty()) continue;
+
+      auto noext = flatbuffers::StripExtension(it->second);
+      auto basename = flatbuffers::StripPath(noext);
+
+      *code += "import '" + GeneratedFileName("", basename + "_" + the_namespace) + "';\n";
+    }
+  }
+
+  static std::string EscapeKeyword(const std::string &name) {
+    for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
+      if (name == keywords[i]) { return MakeCamel(name + "_", false); }
+    }
+
+    return MakeCamel(name, false);
+  }
+
+  void GenerateEnums(namespace_code_map *namespace_code) {
+    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+         ++it) {
+      auto &enum_def = **it;
+      GenEnum(enum_def, namespace_code);  // enum_code_ptr);
+    }
+  }
+
+  void GenerateStructs(namespace_code_map *namespace_code) {
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      auto &struct_def = **it;
+      GenStruct(struct_def, namespace_code);
+    }
+  }
+
+  // Generate a documentation comment, if available.
+  static void GenDocComment(const std::vector<std::string> &dc,
+                            std::string *code_ptr,
+                            const std::string &extra_lines,
+                            const char *indent = nullptr) {
+    if (dc.empty() && extra_lines.empty()) {
+      // Don't output empty comment blocks with 0 lines of comment content.
+      return;
+    }
+
+    auto &code = *code_ptr;
+
+    for (auto it = dc.begin(); it != dc.end(); ++it) {
+      if (indent) code += indent;
+      code += "/// " + *it + "\n";
+    }
+    if (!extra_lines.empty()) {
+      if (!dc.empty()) {
+        if (indent) code += indent;
+        code += "///\n";
+      }
+      if (indent) code += indent;
+      std::string::size_type start = 0;
+      for (;;) {
+        auto end = extra_lines.find('\n', start);
+        if (end != std::string::npos) {
+          code += "/// " + extra_lines.substr(start, end - start) + "\n";
+          start = end + 1;
+        } else {
+          code += "/// " + extra_lines.substr(start) + "\n";
+          break;
+        }
+      }
+    }
+  }
+
+  static void GenDocComment(std::string *code_ptr,
+                            const std::string &extra_lines) {
+    GenDocComment(std::vector<std::string>(), code_ptr, extra_lines);
+  }
+
+  // Generate an enum declaration and an enum string lookup table.
+  void GenEnum(EnumDef &enum_def, namespace_code_map *namespace_code) {
+    if (enum_def.generated) return;
+    auto ns = BuildNamespaceName(*enum_def.defined_namespace);
+    std::string code;
+    GenDocComment(enum_def.doc_comment, &code, "");
+
+    auto name = enum_def.is_union ? enum_def.name + "TypeId" : enum_def.name;
+    auto is_bit_flags = enum_def.attributes.Lookup("bit_flags");
+
+    code += "class " + name + " {\n";
+    code += "  final int value;\n";
+    code += "  const " + name + "._(this.value);\n\n";
+    code += "  factory " + name + ".fromValue(int value) {\n";
+    code += "    if (value == null) value = 0;\n";
+
+    code += "    if (!values.containsKey(value)) {\n";
+    code +=
+        "      throw new StateError('Invalid value $value for bit flag enum ";
+    code += name + "');\n";
+    code += "    }\n";
+
+    code += "    return values[value];\n";
+    code += "  }\n\n";
+
+    // this is meaningless for bit_flags
+    // however, note that unlike "regular" dart enums this enum can still have
+    // holes.
+    if (!is_bit_flags) {
+      code += "  static const int minValue = " +
+              enum_def.ToString(*enum_def.MinValue()) + ";\n";
+      code += "  static const int maxValue = " +
+              enum_def.ToString(*enum_def.MaxValue()) + ";\n";
+    }
+
+    code +=
+        "  static bool containsValue(int value) =>"
+        " values.containsKey(value);\n\n";
+
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      auto &ev = **it;
+
+      if (!ev.doc_comment.empty()) {
+        if (it != enum_def.Vals().begin()) { code += '\n'; }
+        GenDocComment(ev.doc_comment, &code, "", "  ");
+      }
+      code += "  static const " + name + " " + ev.name + " = ";
+      code += "const " + name + "._(" + enum_def.ToString(ev) + ");\n";
+    }
+
+    code += "  static get values => {";
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      auto &ev = **it;
+      code += enum_def.ToString(ev) + ": " + ev.name + ",";
+    }
+    code += "};\n\n";
+
+    code += "  static const " + _kFb + ".Reader<" + name +
+            "> reader = const _" + name + "Reader();\n\n";
+    code += "  @override\n";
+    code += "  String toString() {\n";
+    code += "    return '" + name + "{value: $value}';\n";
+    code += "  }\n";
+    code += "}\n\n";
+
+    GenEnumReader(enum_def, name, &code);
+    (*namespace_code)[ns] += code;
+  }
+
+  void GenEnumReader(EnumDef &enum_def, const std::string &name,
+                     std::string *code_ptr) {
+    auto &code = *code_ptr;
+
+    code += "class _" + name + "Reader extends " + _kFb + ".Reader<" + name +
+            "> {\n";
+    code += "  const _" + name + "Reader();\n\n";
+    code += "  @override\n";
+    code += "  int get size => 1;\n\n";
+    code += "  @override\n";
+    code +=
+        "  " + name + " read(" + _kFb + ".BufferContext bc, int offset) =>\n";
+    code += "      new " + name + ".fromValue(const " + _kFb + "." +
+            GenType(enum_def.underlying_type) + "Reader().read(bc, offset));\n";
+    code += "}\n\n";
+  }
+
+  static std::string GenType(const Type &type) {
+    switch (type.base_type) {
+      case BASE_TYPE_BOOL: return "Bool";
+      case BASE_TYPE_CHAR: return "Int8";
+      case BASE_TYPE_UTYPE:
+      case BASE_TYPE_UCHAR: return "Uint8";
+      case BASE_TYPE_SHORT: return "Int16";
+      case BASE_TYPE_USHORT: return "Uint16";
+      case BASE_TYPE_INT: return "Int32";
+      case BASE_TYPE_UINT: return "Uint32";
+      case BASE_TYPE_LONG: return "Int64";
+      case BASE_TYPE_ULONG: return "Uint64";
+      case BASE_TYPE_FLOAT: return "Float32";
+      case BASE_TYPE_DOUBLE: return "Float64";
+      case BASE_TYPE_STRING: return "String";
+      case BASE_TYPE_VECTOR: return GenType(type.VectorType());
+      case BASE_TYPE_STRUCT: return type.struct_def->name;
+      case BASE_TYPE_UNION: return type.enum_def->name + "TypeId";
+      default: return "Table";
+    }
+  }
+
+  std::string GenReaderTypeName(const Type &type, Namespace *current_namespace,
+                                const FieldDef &def,
+                                bool parent_is_vector = false) {
+    if (type.base_type == BASE_TYPE_BOOL) {
+      return "const " + _kFb + ".BoolReader()";
+    } else if (type.base_type == BASE_TYPE_VECTOR) {
+      return "const " + _kFb + ".ListReader<" +
+             GenDartTypeName(type.VectorType(), current_namespace, def) + ">(" +
+             GenReaderTypeName(type.VectorType(), current_namespace, def,
+                               true) +
+             ")";
+    } else if (type.base_type == BASE_TYPE_STRING) {
+      return "const " + _kFb + ".StringReader()";
+    }
+    if (IsScalar(type.base_type)) {
+      if (type.enum_def && parent_is_vector) {
+        return GenDartTypeName(type, current_namespace, def) + ".reader";
+      }
+      return "const " + _kFb + "." + GenType(type) + "Reader()";
+    } else {
+      return GenDartTypeName(type, current_namespace, def) + ".reader";
+    }
+  }
+
+  std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
+                              const FieldDef &def, bool addBuilder = false) {
+    if (type.enum_def) {
+      if (type.enum_def->is_union && type.base_type != BASE_TYPE_UNION) {
+        return type.enum_def->name + "TypeId";
+      } else if (type.enum_def->is_union) {
+        return "dynamic";
+      } else if (type.base_type != BASE_TYPE_VECTOR) {
+        return type.enum_def->name;
+      }
+    }
+
+    switch (type.base_type) {
+      case BASE_TYPE_BOOL: return "bool";
+      case BASE_TYPE_LONG:
+      case BASE_TYPE_ULONG:
+      case BASE_TYPE_INT:
+      case BASE_TYPE_UINT:
+      case BASE_TYPE_SHORT:
+      case BASE_TYPE_USHORT:
+      case BASE_TYPE_CHAR:
+      case BASE_TYPE_UCHAR: return "int";
+      case BASE_TYPE_FLOAT:
+      case BASE_TYPE_DOUBLE: return "double";
+      case BASE_TYPE_STRING: return "String";
+      case BASE_TYPE_STRUCT:
+        return MaybeWrapNamespace(
+            type.struct_def->name + (addBuilder ? "ObjectBuilder" : ""),
+            current_namespace, def);
+      case BASE_TYPE_VECTOR:
+        return "List<" +
+               GenDartTypeName(type.VectorType(), current_namespace, def,
+                               addBuilder) +
+               ">";
+      default: assert(0); return "dynamic";
+    }
+  }
+
+  static const std::string MaybeWrapNamespace(const std::string &type_name,
+                                              Namespace *current_ns,
+                                              const FieldDef &field) {
+    auto curr_ns_str = BuildNamespaceName(*current_ns);
+    std::string field_ns_str = "";
+    if (field.value.type.struct_def) {
+      field_ns_str +=
+          BuildNamespaceName(*field.value.type.struct_def->defined_namespace);
+    } else if (field.value.type.enum_def) {
+      field_ns_str +=
+          BuildNamespaceName(*field.value.type.enum_def->defined_namespace);
+    }
+
+    if (field_ns_str != "" && field_ns_str != curr_ns_str) {
+      return ImportAliasName(field_ns_str) + "." + type_name;
+    } else {
+      return type_name;
+    }
+  }
+
+  // Generate an accessor struct with constructor for a flatbuffers struct.
+  void GenStruct(const StructDef &struct_def,
+                 namespace_code_map *namespace_code) {
+    if (struct_def.generated) return;
+
+    auto object_namespace = BuildNamespaceName(*struct_def.defined_namespace);
+    std::string code;
+
+    const auto &object_name = struct_def.name;
+
+    // Emit constructor
+
+    GenDocComment(struct_def.doc_comment, &code, "");
+
+    auto reader_name = "_" + object_name + "Reader";
+    auto builder_name = object_name + "Builder";
+    auto object_builder_name = object_name + "ObjectBuilder";
+
+    std::string reader_code, builder_code;
+
+    code += "class " + object_name + " {\n";
+
+    code += "  " + object_name + "._(this._bc, this._bcOffset);\n";
+    if (!struct_def.fixed) {
+      code += "  factory " + object_name + "(List<int> bytes) {\n";
+      code += "    " + _kFb + ".BufferContext rootRef = new " + _kFb +
+              ".BufferContext.fromBytes(bytes);\n";
+      code += "    return reader.read(rootRef, 0);\n";
+      code += "  }\n";
+    }
+
+    code += "\n";
+    code += "  static const " + _kFb + ".Reader<" + object_name +
+            "> reader = const " + reader_name + "();\n\n";
+
+    code += "  final " + _kFb + ".BufferContext _bc;\n";
+    code += "  final int _bcOffset;\n\n";
+
+    GenImplementationGetters(struct_def, &code);
+
+    code += "}\n\n";
+
+    GenReader(struct_def, &reader_name, &reader_code);
+    GenBuilder(struct_def, &builder_name, &builder_code);
+    GenObjectBuilder(struct_def, &object_builder_name, &builder_code);
+
+    code += reader_code;
+    code += builder_code;
+
+    (*namespace_code)[object_namespace] += code;
+  }
+
+  std::string NamespaceAliasFromUnionType(const std::string &in) {
+    if (in.find('_') == std::string::npos) { return in; }
+
+    std::stringstream ss(in);
+    std::string item;
+    std::vector<std::string> parts;
+    std::string ns;
+
+    while (std::getline(ss, item, '_')) { parts.push_back(item); }
+
+    for (auto it = parts.begin(); it != parts.end() - 1; ++it) {
+      auto &part = *it;
+
+      for (size_t i = 0; i < part.length(); i++) {
+        if (i && !isdigit(part[i]) &&
+            part[i] == static_cast<char>(toupper(part[i]))) {
+          ns += "_";
+          ns += static_cast<char>(tolower(part[i]));
+        } else {
+          ns += static_cast<char>(tolower(part[i]));
+        }
+      }
+      if (it != parts.end() - 2) { ns += "_"; }
+    }
+
+    return ns + "." + parts.back();
+  }
+
+  void GenImplementationGetters(const StructDef &struct_def,
+                                std::string *code_ptr) {
+    auto &code = *code_ptr;
+
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (field.deprecated) continue;
+
+      std::string field_name = MakeCamel(field.name, false);
+      std::string type_name = GenDartTypeName(
+          field.value.type, struct_def.defined_namespace, field, false);
+
+      GenDocComment(field.doc_comment, &code, "", "  ");
+
+      code += "  " + type_name + " get " + field_name;
+      if (field.value.type.base_type == BASE_TYPE_UNION) {
+        code += " {\n";
+        code += "    switch (" + field_name + "Type?.value) {\n";
+        auto &enum_def = *field.value.type.enum_def;
+        for (auto en_it = enum_def.Vals().begin() + 1;
+             en_it != enum_def.Vals().end(); ++en_it) {
+          auto &ev = **en_it;
+
+          auto enum_name = NamespaceAliasFromUnionType(ev.name);
+          code += "      case " + enum_def.ToString(ev) + ": return " +
+                  enum_name + ".reader.vTableGet(_bc, _bcOffset, " +
+                  NumToString(field.value.offset) + ", null);\n";
+        }
+        code += "      default: return null;\n";
+        code += "    }\n";
+        code += "  }\n";
+      } else {
+        code += " => ";
+        if (field.value.type.enum_def &&
+            field.value.type.base_type != BASE_TYPE_VECTOR) {
+          code += "new " +
+                  GenDartTypeName(field.value.type,
+                                  struct_def.defined_namespace, field) +
+                  ".fromValue(";
+        }
+
+        code += GenReaderTypeName(field.value.type,
+                                  struct_def.defined_namespace, field);
+        if (struct_def.fixed) {
+          code +=
+              ".read(_bc, _bcOffset + " + NumToString(field.value.offset) + ")";
+        } else {
+          code += ".vTableGet(_bc, _bcOffset, " +
+                  NumToString(field.value.offset) + ", ";
+          if (!field.value.constant.empty() && field.value.constant != "0") {
+            if (IsBool(field.value.type.base_type)) {
+              code += "true";
+            } else {
+              code += field.value.constant;
+            }
+          } else {
+            if (IsBool(field.value.type.base_type)) {
+              code += "false";
+            } else if (IsScalar(field.value.type.base_type)) {
+              code += "0";
+            } else {
+              code += "null";
+            }
+          }
+          code += ")";
+        }
+        if (field.value.type.enum_def &&
+            field.value.type.base_type != BASE_TYPE_VECTOR) {
+          code += ")";
+        }
+        code += ";\n";
+      }
+    }
+
+    code += "\n";
+
+    code += "  @override\n";
+    code += "  String toString() {\n";
+    code += "    return '" + struct_def.name + "{";
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (field.deprecated) continue;
+      code +=
+          MakeCamel(field.name, false) + ": $" + MakeCamel(field.name, false);
+      if (it != struct_def.fields.vec.end() - 1) { code += ", "; }
+    }
+    code += "}';\n";
+    code += "  }\n";
+  }
+
+  void GenReader(const StructDef &struct_def, std::string *reader_name_ptr,
+                 std::string *code_ptr) {
+    auto &code = *code_ptr;
+    auto &reader_name = *reader_name_ptr;
+    auto &impl_name = struct_def.name;
+
+    code += "class " + reader_name + " extends " + _kFb;
+    if (struct_def.fixed) {
+      code += ".StructReader<";
+    } else {
+      code += ".TableReader<";
+    }
+    code += impl_name + "> {\n";
+    code += "  const " + reader_name + "();\n\n";
+
+    if (struct_def.fixed) {
+      code += "  @override\n";
+      code += "  int get size => " + NumToString(struct_def.bytesize) + ";\n\n";
+    }
+    code += "  @override\n";
+    code += "  " + impl_name +
+            " createObject(fb.BufferContext bc, int offset) => \n    new " +
+            impl_name + "._(bc, offset);\n";
+    code += "}\n\n";
+  }
+
+  void GenBuilder(const StructDef &struct_def, std::string *builder_name_ptr,
+                  std::string *code_ptr) {
+    if (struct_def.fields.vec.size() == 0) { return; }
+    auto &code = *code_ptr;
+    auto &builder_name = *builder_name_ptr;
+
+    code += "class " + builder_name + " {\n";
+    code += "  " + builder_name + "(this.fbBuilder) {\n";
+    code += "    assert(fbBuilder != null);\n";
+    code += "  }\n\n";
+    code += "  final " + _kFb + ".Builder fbBuilder;\n\n";
+
+    if (struct_def.fixed) {
+      StructBuilderBody(struct_def, code_ptr);
+    } else {
+      TableBuilderBody(struct_def, code_ptr);
+    }
+
+    code += "}\n\n";
+  }
+
+  void StructBuilderBody(const StructDef &struct_def, std::string *code_ptr) {
+    auto &code = *code_ptr;
+
+    code += "  int finish(";
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (field.deprecated) continue;
+
+      if (IsStruct(field.value.type)) {
+        code += "fb.StructBuilder";
+      } else {
+        code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
+                                field);
+      }
+      code += " " + field.name;
+      if (it != struct_def.fields.vec.end() - 1) { code += ", "; }
+    }
+    code += ") {\n";
+
+    for (auto it = struct_def.fields.vec.rbegin();
+         it != struct_def.fields.vec.rend(); ++it) {
+      auto &field = **it;
+
+      if (field.deprecated) continue;
+
+      if (field.padding) {
+        code += "    fbBuilder.pad(" + NumToString(field.padding) + ");\n";
+      }
+
+      if (IsStruct(field.value.type)) {
+        code += "    " + field.name + "();\n";
+      } else {
+        code += "    fbBuilder.put" + GenType(field.value.type) + "(";
+        code += field.name;
+        if (field.value.type.enum_def) { code += "?.value"; }
+        code += ");\n";
+      }
+    }
+    code += "    return fbBuilder.offset;\n";
+    code += "  }\n\n";
+  }
+
+  void TableBuilderBody(const StructDef &struct_def, std::string *code_ptr) {
+    auto &code = *code_ptr;
+
+    code += "  void begin() {\n";
+    code += "    fbBuilder.startTable();\n";
+    code += "  }\n\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();
+
+      if (IsScalar(field.value.type.base_type)) {
+        code += "  int add" + MakeCamel(field.name) + "(";
+        code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
+                                field);
+        code += " " + MakeCamel(field.name, false) + ") {\n";
+        code += "    fbBuilder.add" + GenType(field.value.type) + "(" +
+                NumToString(offset) + ", ";
+        code += MakeCamel(field.name, false);
+        if (field.value.type.enum_def) { code += "?.value"; }
+        code += ");\n";
+      } else if (IsStruct(field.value.type)) {
+        code += "  int add" + MakeCamel(field.name) + "(int offset) {\n";
+        code +=
+            "    fbBuilder.addStruct(" + NumToString(offset) + ", offset);\n";
+      } else {
+        code += "  int add" + MakeCamel(field.name) + "Offset(int offset) {\n";
+        code +=
+            "    fbBuilder.addOffset(" + NumToString(offset) + ", offset);\n";
+      }
+      code += "    return fbBuilder.offset;\n";
+      code += "  }\n";
+    }
+
+    code += "\n";
+    code += "  int finish() {\n";
+    code += "    return fbBuilder.endTable();\n";
+    code += "  }\n";
+  }
+
+  void GenObjectBuilder(const StructDef &struct_def,
+                        std::string *builder_name_ptr, std::string *code_ptr) {
+    auto &code = *code_ptr;
+    auto &builder_name = *builder_name_ptr;
+
+    code += "class " + builder_name + " extends " + _kFb + ".ObjectBuilder {\n";
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (field.deprecated) continue;
+      code += "  final " +
+              GenDartTypeName(field.value.type, struct_def.defined_namespace,
+                              field, true) +
+              " _" + MakeCamel(field.name, false) + ";\n";
+    }
+    code += "\n";
+    code += "  " + builder_name + "(";
+    if (struct_def.fields.vec.size() != 0) {
+      code +=
+
+          "{\n";
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        auto &field = **it;
+        if (field.deprecated) continue;
+        code += "    " +
+                GenDartTypeName(field.value.type, struct_def.defined_namespace,
+                                field, true) +
+                " " + MakeCamel(field.name, false) + ",\n";
+      }
+      code += "  })\n";
+      code += "      : ";
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        auto &field = **it;
+        if (field.deprecated) continue;
+        code += "_" + MakeCamel(field.name, false) + " = " +
+                MakeCamel(field.name, false);
+        if (it == struct_def.fields.vec.end() - 1) {
+          code += ";\n\n";
+        } else {
+          code += ",\n        ";
+        }
+      }
+    } else {
+      code += ");\n\n";
+    }
+
+    code += "  /// Finish building, and store into the [fbBuilder].\n";
+    code += "  @override\n";
+    code += "  int finish(\n";
+    code += "    " + _kFb + ".Builder fbBuilder) {\n";
+    code += "    assert(fbBuilder != null);\n";
+
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (field.deprecated) continue;
+      if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type))
+        continue;
+
+      code += "    final int " + MakeCamel(field.name, false) + "Offset";
+      if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+        code +=
+            " = _" + MakeCamel(field.name, false) + "?.isNotEmpty == true\n";
+        code += "        ? fbBuilder.writeList";
+        switch (field.value.type.VectorType().base_type) {
+          case BASE_TYPE_STRING:
+            code += "(_" + MakeCamel(field.name, false) +
+                    ".map((b) => fbBuilder.writeString(b)).toList())";
+            break;
+          case BASE_TYPE_STRUCT:
+            if (field.value.type.struct_def->fixed) {
+              code += "OfStructs(_" + MakeCamel(field.name, false) + ")";
+            } else {
+              code += "(_" + MakeCamel(field.name, false) +
+                      ".map((b) => b.getOrCreateOffset(fbBuilder)).toList())";
+            }
+            break;
+          default:
+            code += GenType(field.value.type.VectorType()) + "(_" +
+                    MakeCamel(field.name, false);
+            if (field.value.type.enum_def) { code += ".map((f) => f.value)"; }
+            code += ")";
+        }
+        code += "\n        : null;\n";
+      } else if (field.value.type.base_type == BASE_TYPE_STRING) {
+        code += " = fbBuilder.writeString(_" + MakeCamel(field.name, false) + ");\n";
+      } else {
+        code += " = _" + MakeCamel(field.name, false) +
+                "?.getOrCreateOffset(fbBuilder);\n";
+      }
+    }
+
+    code += "\n";
+    if (struct_def.fixed) {
+      StructObjectBuilderBody(struct_def, code_ptr);
+    } else {
+      TableObjectBuilderBody(struct_def, code_ptr);
+    }
+    code += "  }\n\n";
+
+    code += "  /// Convenience method to serialize to byte list.\n";
+    code += "  @override\n";
+    code += "  Uint8List toBytes([String fileIdentifier]) {\n";
+    code += "    " + _kFb + ".Builder fbBuilder = new ";
+    code += _kFb + ".Builder();\n";
+    code += "    int offset = finish(fbBuilder);\n";
+    code += "    return fbBuilder.finish(offset, fileIdentifier);\n";
+    code += "  }\n";
+    code += "}\n";
+  }
+
+  void StructObjectBuilderBody(const StructDef &struct_def,
+                               std::string *code_ptr,
+                               bool prependUnderscore = true) {
+    auto &code = *code_ptr;
+
+    for (auto it = struct_def.fields.vec.rbegin();
+         it != struct_def.fields.vec.rend(); ++it) {
+      auto &field = **it;
+
+      if (field.deprecated) continue;
+
+      if (field.padding) {
+        code += "    fbBuilder.pad(" + NumToString(field.padding) + ");\n";
+      }
+
+      if (IsStruct(field.value.type)) {
+        code += "    ";
+        if (prependUnderscore) { code += "_"; }
+        code += field.name + ".finish(fbBuilder);\n";
+      } else {
+        code += "    fbBuilder.put" + GenType(field.value.type) + "(";
+        if (prependUnderscore) { code += "_"; }
+        code += field.name;
+        if (field.value.type.enum_def) { code += "?.value"; }
+        code += ");\n";
+      }
+    }
+
+    code += "    return fbBuilder.offset;\n";
+  }
+
+  void TableObjectBuilderBody(const StructDef &struct_def,
+                              std::string *code_ptr,
+                              bool prependUnderscore = true) {
+    std::string &code = *code_ptr;
+    code += "    fbBuilder.startTable();\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();
+      if (IsScalar(field.value.type.base_type)) {
+        code += "    fbBuilder.add" + GenType(field.value.type) + "(" +
+                NumToString(offset) + ", ";
+        if (prependUnderscore) { code += "_"; }
+        code += MakeCamel(field.name, false);
+        if (field.value.type.enum_def) { code += "?.value"; }
+        code += ");\n";
+      } else if (IsStruct(field.value.type)) {
+        code += "    if (";
+        if (prependUnderscore) { code += "_"; }
+        code += MakeCamel(field.name, false) + " != null) {\n";
+        code += "      fbBuilder.addStruct(" + NumToString(offset) + ", ";
+        code += "_" + MakeCamel(field.name, false) + ".finish(fbBuilder));\n";
+        code += "    }\n";
+      } else {
+        code +=
+            "    if (" + MakeCamel(field.name, false) + "Offset != null) {\n";
+        code += "      fbBuilder.addOffset(" + NumToString(offset) + ", " +
+                MakeCamel(field.name, false) + "Offset);\n";
+        code += "    }\n";
+      }
+    }
+    code += "    return fbBuilder.endTable();\n";
+  }
+};
+}  // namespace dart
+
+bool GenerateDart(const Parser &parser, const std::string &path,
+                  const std::string &file_name) {
+  dart::DartGenerator generator(parser, path, file_name);
+  return generator.generate();
+}
+
+std::string DartMakeRule(const Parser &parser, const std::string &path,
+                         const std::string &file_name) {
+  assert(parser.opts.lang <= IDLOptions::kMAX);
+
+  auto filebase =
+      flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+  auto make_rule = GeneratedFileName(path, filebase) + ": ";
+
+  auto included_files = parser.GetIncludedFilesRecursive(file_name);
+  for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+    make_rule += " " + *it;
+  }
+  return make_rule;
+}
+
+}  // namespace flatbuffers
diff --git a/src/idl_gen_fbs.cpp b/src/idl_gen_fbs.cpp
new file mode 100644
index 0000000..e5f3723
--- /dev/null
+++ b/src/idl_gen_fbs.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2014 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.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+static std::string GenType(const Type &type, bool underlying = false) {
+  switch (type.base_type) {
+    case BASE_TYPE_STRUCT:
+      return type.struct_def->defined_namespace->GetFullyQualifiedName(
+          type.struct_def->name);
+    case BASE_TYPE_VECTOR: return "[" + GenType(type.VectorType()) + "]";
+    default:
+      if (type.enum_def && !underlying) {
+        return type.enum_def->defined_namespace->GetFullyQualifiedName(
+            type.enum_def->name);
+      } else {
+        return kTypeNames[type.base_type];
+      }
+  }
+}
+
+static void GenNameSpace(const Namespace &name_space, std::string *_schema,
+                         const Namespace **last_namespace) {
+  if (*last_namespace == &name_space) return;
+  *last_namespace = &name_space;
+  auto &schema = *_schema;
+  schema += "namespace ";
+  for (auto it = name_space.components.begin();
+       it != name_space.components.end(); ++it) {
+    if (it != name_space.components.begin()) schema += ".";
+    schema += *it;
+  }
+  schema += ";\n\n";
+}
+
+// Generate a flatbuffer schema from the Parser's internal representation.
+std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
+  // Proto namespaces may clash with table names, escape the ones that were
+  // generated from a table:
+  for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end();
+       ++it) {
+    auto &ns = **it;
+    for (size_t i = 0; i < ns.from_table; i++) {
+      ns.components[ns.components.size() - 1 - i] += "_";
+    }
+  }
+
+  std::string schema;
+  schema += "// Generated from " + file_name + ".proto\n\n";
+  if (parser.opts.include_dependence_headers) {
+    // clang-format off
+    #ifdef FBS_GEN_INCLUDES  // TODO: currently all in one file.
+    int num_includes = 0;
+    for (auto it = parser.included_files_.begin();
+         it != parser.included_files_.end(); ++it) {
+      if (it->second.empty())
+        continue;
+      auto basename = flatbuffers::StripPath(
+                        flatbuffers::StripExtension(it->second));
+      schema += "include \"" + basename + ".fbs\";\n";
+      num_includes++;
+    }
+    if (num_includes) schema += "\n";
+    #endif
+    // clang-format on
+  }
+  // Generate code for all the enum declarations.
+  const Namespace *last_namespace = nullptr;
+  for (auto enum_def_it = parser.enums_.vec.begin();
+       enum_def_it != parser.enums_.vec.end(); ++enum_def_it) {
+    EnumDef &enum_def = **enum_def_it;
+    GenNameSpace(*enum_def.defined_namespace, &schema, &last_namespace);
+    GenComment(enum_def.doc_comment, &schema, nullptr);
+    if (enum_def.is_union)
+      schema += "union " + enum_def.name;
+    else
+      schema += "enum " + enum_def.name + " : ";
+    schema += GenType(enum_def.underlying_type, true) + " {\n";
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      auto &ev = **it;
+      GenComment(ev.doc_comment, &schema, nullptr, "  ");
+      if (enum_def.is_union)
+        schema += "  " + GenType(ev.union_type) + ",\n";
+      else
+        schema += "  " + ev.name + " = " + enum_def.ToString(ev) + ",\n";
+    }
+    schema += "}\n\n";
+  }
+  // Generate code for all structs/tables.
+  for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
+       ++it) {
+    StructDef &struct_def = **it;
+    GenNameSpace(*struct_def.defined_namespace, &schema, &last_namespace);
+    GenComment(struct_def.doc_comment, &schema, nullptr);
+    schema += "table " + struct_def.name + " {\n";
+    for (auto field_it = struct_def.fields.vec.begin();
+         field_it != struct_def.fields.vec.end(); ++field_it) {
+      auto &field = **field_it;
+      if (field.value.type.base_type != BASE_TYPE_UTYPE) {
+        GenComment(field.doc_comment, &schema, nullptr, "  ");
+        schema += "  " + field.name + ":" + GenType(field.value.type);
+        if (field.value.constant != "0") schema += " = " + field.value.constant;
+        if (field.required) schema += " (required)";
+        schema += ";\n";
+      }
+    }
+    schema += "}\n\n";
+  }
+  return schema;
+}
+
+bool GenerateFBS(const Parser &parser, const std::string &path,
+                 const std::string &file_name) {
+  return SaveFile((path + file_name + ".fbs").c_str(),
+                  GenerateFBS(parser, file_name), false);
+}
+
+}  // namespace flatbuffers
diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp
new file mode 100644
index 0000000..8dca792
--- /dev/null
+++ b/src/idl_gen_general.cpp
@@ -0,0 +1,1667 @@
+/*
+ * Copyright 2014 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.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#if defined(FLATBUFFERS_CPP98_STL)
+#  include <cctype>
+#endif  // defined(FLATBUFFERS_CPP98_STL)
+
+namespace flatbuffers {
+
+// These arrays need to correspond to the IDLOptions::k enum.
+
+struct LanguageParameters {
+  IDLOptions::Language language;
+  // Whether function names in the language typically start with uppercase.
+  bool first_camel_upper;
+  std::string file_extension;
+  std::string string_type;
+  std::string bool_type;
+  std::string open_curly;
+  std::string accessor_type;
+  std::string const_decl;
+  std::string unsubclassable_decl;
+  std::string enum_decl;
+  std::string enum_separator;
+  std::string getter_prefix;
+  std::string getter_suffix;
+  std::string inheritance_marker;
+  std::string namespace_ident;
+  std::string namespace_begin;
+  std::string namespace_end;
+  std::string set_bb_byteorder;
+  std::string get_bb_position;
+  std::string get_fbb_offset;
+  std::string accessor_prefix;
+  std::string accessor_prefix_static;
+  std::string optional_suffix;
+  std::string includes;
+  std::string class_annotation;
+  std::string generated_type_annotation;
+  CommentConfig comment_config;
+  const FloatConstantGenerator *float_gen;
+};
+
+const LanguageParameters &GetLangParams(IDLOptions::Language lang) {
+  static TypedFloatConstantGenerator CSharpFloatGen(
+      "Double.", "Single.", "NaN", "PositiveInfinity", "NegativeInfinity");
+
+  static TypedFloatConstantGenerator JavaFloatGen(
+      "Double.", "Float.", "NaN", "POSITIVE_INFINITY", "NEGATIVE_INFINITY");
+
+  static const LanguageParameters language_parameters[] = {
+    {
+        IDLOptions::kJava,
+        false,
+        ".java",
+        "String",
+        "boolean ",
+        " {\n",
+        "class ",
+        " final ",
+        "final ",
+        "final class ",
+        ";\n",
+        "()",
+        "",
+        " extends ",
+        "package ",
+        ";",
+        "",
+        "_bb.order(ByteOrder.LITTLE_ENDIAN); ",
+        "position()",
+        "offset()",
+        "",
+        "",
+        "",
+        "import java.nio.*;\nimport java.lang.*;\nimport "
+        "java.util.*;\nimport com.google.flatbuffers.*;\n",
+        "\n@SuppressWarnings(\"unused\")\n",
+        "\n@javax.annotation.Generated(value=\"flatc\")\n",
+        {
+            "/**",
+            " *",
+            " */",
+        },
+        &JavaFloatGen
+    },
+    {
+        IDLOptions::kCSharp,
+        true,
+        ".cs",
+        "string",
+        "bool ",
+        "\n{\n",
+        "struct ",
+        " readonly ",
+        "",
+        "enum ",
+        ",\n",
+        " { get",
+        "} ",
+        " : ",
+        "namespace ",
+        "\n{",
+        "\n}\n",
+        "",
+        "Position",
+        "Offset",
+        "__p.",
+        "Table.",
+        "?",
+        "using global::System;\nusing global::FlatBuffers;\n\n",
+        "",
+        "",
+        {
+            nullptr,
+            "///",
+            nullptr,
+        },
+        &CSharpFloatGen
+    },
+  };
+
+  if (lang == IDLOptions::kJava) {
+    return language_parameters[0];
+  } else {
+    FLATBUFFERS_ASSERT(lang == IDLOptions::kCSharp);
+    return language_parameters[1];
+  }
+}
+
+namespace general {
+class GeneralGenerator : public BaseGenerator {
+ public:
+  GeneralGenerator(const Parser &parser, const std::string &path,
+                   const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "", "."),
+        lang_(GetLangParams(parser_.opts.lang)),
+        cur_name_space_(nullptr) {}
+
+  GeneralGenerator &operator=(const GeneralGenerator &);
+  bool generate() {
+    std::string one_file_code;
+    cur_name_space_ = parser_.current_namespace_;
+
+    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+         ++it) {
+      std::string enumcode;
+      auto &enum_def = **it;
+      if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
+      GenEnum(enum_def, &enumcode);
+      if (parser_.opts.one_file) {
+        one_file_code += enumcode;
+      } else {
+        if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode,
+                      false))
+          return false;
+      }
+    }
+
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      std::string declcode;
+      auto &struct_def = **it;
+      if (!parser_.opts.one_file)
+        cur_name_space_ = struct_def.defined_namespace;
+      GenStruct(struct_def, &declcode);
+      if (parser_.opts.one_file) {
+        one_file_code += declcode;
+      } else {
+        if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode,
+                      true))
+          return false;
+      }
+    }
+
+    if (parser_.opts.one_file) {
+      return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
+                      true);
+    }
+    return true;
+  }
+
+  // Save out the generated code for a single class while adding
+  // declaration boilerplate.
+  bool SaveType(const std::string &defname, const Namespace &ns,
+                const std::string &classcode, bool needs_includes) const {
+    if (!classcode.length()) return true;
+
+    std::string code;
+    if (lang_.language == IDLOptions::kCSharp) {
+      code =
+          "// <auto-generated>\n"
+          "//  " +
+          std::string(FlatBuffersGeneratedWarning()) +
+          "\n"
+          "// </auto-generated>\n\n";
+    } else {
+      code = "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+    }
+
+    std::string namespace_name = FullNamespace(".", ns);
+    if (!namespace_name.empty()) {
+      code += lang_.namespace_ident + namespace_name + lang_.namespace_begin;
+      code += "\n\n";
+    }
+    if (needs_includes) {
+      code += lang_.includes;
+      if (parser_.opts.gen_nullable) {
+        code += "\nimport javax.annotation.Nullable;\n";
+      }
+      code += lang_.class_annotation;
+    }
+    if (parser_.opts.gen_generated) {
+      code += lang_.generated_type_annotation;
+    }
+    code += classcode;
+    if (!namespace_name.empty()) code += lang_.namespace_end;
+    auto filename = NamespaceDir(ns) + defname + lang_.file_extension;
+    return SaveFile(filename.c_str(), code, false);
+  }
+
+  const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+  std::string FunctionStart(char upper) const {
+    return std::string() + (lang_.language == IDLOptions::kJava
+                                ? static_cast<char>(tolower(upper))
+                                : upper);
+  }
+
+  std::string GenNullableAnnotation(const Type &t) const {
+    return lang_.language == IDLOptions::kJava && parser_.opts.gen_nullable &&
+                   !IsScalar(DestinationType(t, true).base_type)
+               ? " @Nullable "
+               : "";
+  }
+
+  std::string GenTypeBasic(const Type &type, bool enableLangOverrides) const {
+    // clang-format off
+  static const char * const java_typename[] = {
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+        CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+        #JTYPE,
+      FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+    #undef FLATBUFFERS_TD
+  };
+
+  static const char * const csharp_typename[] = {
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+        CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+        #NTYPE,
+      FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+    #undef FLATBUFFERS_TD
+  };
+    // clang-format on
+
+    if (enableLangOverrides) {
+      if (lang_.language == IDLOptions::kCSharp) {
+        if (IsEnum(type)) return WrapInNameSpace(*type.enum_def);
+        if (type.base_type == BASE_TYPE_STRUCT) {
+          return "Offset<" + WrapInNameSpace(*type.struct_def) + ">";
+        }
+      }
+    }
+
+    if (lang_.language == IDLOptions::kJava) {
+      return java_typename[type.base_type];
+    } else {
+      FLATBUFFERS_ASSERT(lang_.language == IDLOptions::kCSharp);
+      return csharp_typename[type.base_type];
+    }
+  }
+
+  std::string GenTypeBasic(const Type &type) const {
+    return GenTypeBasic(type, true);
+  }
+
+  std::string GenTypePointer(const Type &type) const {
+    switch (type.base_type) {
+      case BASE_TYPE_STRING: return lang_.string_type;
+      case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+      case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
+      case BASE_TYPE_UNION:
+        // Unions in C# use a generic Table-derived type for better type safety
+        if (lang_.language == IDLOptions::kCSharp) return "TTable";
+        FLATBUFFERS_FALLTHROUGH();  // else fall thru
+      default: return "Table";
+    }
+  }
+
+  std::string GenTypeGet(const Type &type) const {
+    return IsScalar(type.base_type)
+               ? GenTypeBasic(type)
+               : (IsArray(type) ? GenTypeGet(type.VectorType())
+                                : GenTypePointer(type));
+  }
+
+  // Find the destination type the user wants to receive the value in (e.g.
+  // one size higher signed types for unsigned serialized values in Java).
+  Type DestinationType(const Type &type, bool vectorelem) const {
+    if (lang_.language != IDLOptions::kJava) return type;
+    switch (type.base_type) {
+      // We use int for both uchar/ushort, since that generally means less
+      // casting than using short for uchar.
+      case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT);
+      case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT);
+      case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG);
+      case BASE_TYPE_ARRAY:
+      case BASE_TYPE_VECTOR:
+        if (vectorelem) return DestinationType(type.VectorType(), vectorelem);
+        FLATBUFFERS_FALLTHROUGH(); // else fall thru
+      default: return type;
+    }
+  }
+
+  std::string GenOffsetType(const StructDef &struct_def) const {
+    if (lang_.language == IDLOptions::kCSharp) {
+      return "Offset<" + WrapInNameSpace(struct_def) + ">";
+    } else {
+      return "int";
+    }
+  }
+
+  std::string GenOffsetConstruct(const StructDef &struct_def,
+                                 const std::string &variable_name) const {
+    if (lang_.language == IDLOptions::kCSharp) {
+      return "new Offset<" + WrapInNameSpace(struct_def) + ">(" +
+             variable_name + ")";
+    }
+    return variable_name;
+  }
+
+  std::string GenVectorOffsetType() const {
+    if (lang_.language == IDLOptions::kCSharp) {
+      return "VectorOffset";
+    } else {
+      return "int";
+    }
+  }
+
+  // Generate destination type name
+  std::string GenTypeNameDest(const Type &type) const {
+    return GenTypeGet(DestinationType(type, true));
+  }
+
+  // Mask to turn serialized value into destination type value.
+  std::string DestinationMask(const Type &type, bool vectorelem) const {
+    if (lang_.language != IDLOptions::kJava) return "";
+    switch (type.base_type) {
+      case BASE_TYPE_UCHAR: return " & 0xFF";
+      case BASE_TYPE_USHORT: return " & 0xFFFF";
+      case BASE_TYPE_UINT: return " & 0xFFFFFFFFL";
+      case BASE_TYPE_VECTOR:
+        if (vectorelem) return DestinationMask(type.VectorType(), vectorelem);
+        FLATBUFFERS_FALLTHROUGH(); // else fall thru
+      default: return "";
+    }
+  }
+
+  // Casts necessary to correctly read serialized data
+  std::string DestinationCast(const Type &type) const {
+    if (IsSeries(type)) {
+      return DestinationCast(type.VectorType());
+    } else {
+      switch (lang_.language) {
+        case IDLOptions::kJava:
+          // Cast necessary to correctly read serialized unsigned values.
+          if (type.base_type == BASE_TYPE_UINT) return "(long)";
+          break;
+
+        case IDLOptions::kCSharp:
+          // Cast from raw integral types to enum.
+          if (IsEnum(type)) return "(" + WrapInNameSpace(*type.enum_def) + ")";
+          break;
+
+        default: break;
+      }
+    }
+    return "";
+  }
+
+  // Cast statements for mutator method parameters.
+  // In Java, parameters representing unsigned numbers need to be cast down to
+  // their respective type. For example, a long holding an unsigned int value
+  // would be cast down to int before being put onto the buffer. In C#, one cast
+  // directly cast an Enum to its underlying type, which is essential before
+  // putting it onto the buffer.
+  std::string SourceCast(const Type &type, bool castFromDest) const {
+    if (IsSeries(type)) {
+      return SourceCast(type.VectorType(), castFromDest);
+    } else {
+      switch (lang_.language) {
+        case IDLOptions::kJava:
+          if (castFromDest) {
+            if (type.base_type == BASE_TYPE_UINT)
+              return "(int)";
+            else if (type.base_type == BASE_TYPE_USHORT)
+              return "(short)";
+            else if (type.base_type == BASE_TYPE_UCHAR)
+              return "(byte)";
+          }
+          break;
+        case IDLOptions::kCSharp:
+          if (IsEnum(type)) return "(" + GenTypeBasic(type, false) + ")";
+          break;
+        default: break;
+      }
+    }
+    return "";
+  }
+
+  std::string SourceCast(const Type &type) const { return SourceCast(type, true); }
+
+  std::string SourceCastBasic(const Type &type, bool castFromDest) const {
+    return IsScalar(type.base_type) ? SourceCast(type, castFromDest) : "";
+  }
+
+  std::string SourceCastBasic(const Type &type) const {
+    return SourceCastBasic(type, true);
+  }
+
+  std::string GenEnumDefaultValue(const FieldDef &field) const {
+    auto &value = field.value;
+    FLATBUFFERS_ASSERT(value.type.enum_def);
+    auto &enum_def = *value.type.enum_def;
+    auto enum_val = enum_def.FindByValue(value.constant);
+    return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
+                    : value.constant;
+  }
+
+  std::string GenDefaultValue(const FieldDef &field, bool enableLangOverrides) const {
+    auto& value = field.value;
+    if (enableLangOverrides) {
+      // handles both enum case and vector of enum case
+      if (lang_.language == IDLOptions::kCSharp &&
+          value.type.enum_def != nullptr &&
+          value.type.base_type != BASE_TYPE_UNION) {
+        return GenEnumDefaultValue(field);
+      }
+    }
+
+    auto longSuffix = lang_.language == IDLOptions::kJava ? "L" : "";
+    switch (value.type.base_type) {
+      case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
+      case BASE_TYPE_ULONG: {
+        if (lang_.language != IDLOptions::kJava) return value.constant;
+        // Converts the ulong into its bits signed equivalent
+        uint64_t defaultValue = StringToUInt(value.constant.c_str());
+        return NumToString(static_cast<int64_t>(defaultValue)) + longSuffix;
+      }
+      case BASE_TYPE_UINT:
+      case BASE_TYPE_LONG: return value.constant + longSuffix;
+      default:
+        if(IsFloat(value.type.base_type))
+          return lang_.float_gen->GenFloatConstant(field);
+        else
+          return value.constant;
+    }
+  }
+
+  std::string GenDefaultValue(const FieldDef &field) const {
+    return GenDefaultValue(field, true);
+  }
+
+  std::string GenDefaultValueBasic(const FieldDef &field,
+                                   bool enableLangOverrides) const {
+    auto& value = field.value;
+    if (!IsScalar(value.type.base_type)) {
+      if (enableLangOverrides) {
+        if (lang_.language == IDLOptions::kCSharp) {
+          switch (value.type.base_type) {
+            case BASE_TYPE_STRING: return "default(StringOffset)";
+            case BASE_TYPE_STRUCT:
+              return "default(Offset<" +
+                     WrapInNameSpace(*value.type.struct_def) + ">)";
+            case BASE_TYPE_VECTOR: return "default(VectorOffset)";
+            default: break;
+          }
+        }
+      }
+      return "0";
+    }
+    return GenDefaultValue(field, enableLangOverrides);
+  }
+
+  std::string GenDefaultValueBasic(const FieldDef &field) const {
+    return GenDefaultValueBasic(field, true);
+  }
+
+  void GenEnum(EnumDef &enum_def, std::string *code_ptr) const {
+    std::string &code = *code_ptr;
+    if (enum_def.generated) return;
+
+    // Generate enum definitions of the form:
+    // public static (final) int name = value;
+    // In Java, we use ints rather than the Enum feature, because we want them
+    // to map directly to how they're used in C/C++ and file formats.
+    // That, and Java Enums are expensive, and not universally liked.
+    GenComment(enum_def.doc_comment, code_ptr, &lang_.comment_config);
+
+    // In C# this indicates enumeration values can be treated as bit flags.
+    if (lang_.language == IDLOptions::kCSharp && enum_def.attributes.Lookup("bit_flags")) {
+      code += "[System.FlagsAttribute]\n";
+    }
+    if (enum_def.attributes.Lookup("private")) {
+      // For Java, we leave the enum unmarked to indicate package-private
+      // For C# we mark the enum as internal
+      if (lang_.language == IDLOptions::kCSharp) {
+        code += "internal ";
+      }
+    } else {
+      code += "public ";
+    }
+    code += lang_.enum_decl + enum_def.name;
+    if (lang_.language == IDLOptions::kCSharp) {
+      code += lang_.inheritance_marker +
+              GenTypeBasic(enum_def.underlying_type, false);
+    }
+    code += lang_.open_curly;
+    if (lang_.language == IDLOptions::kJava) {
+      code += "  private " + enum_def.name + "() { }\n";
+    }
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      auto &ev = **it;
+      GenComment(ev.doc_comment, code_ptr, &lang_.comment_config, "  ");
+      if (lang_.language != IDLOptions::kCSharp) {
+        code += "  public static";
+        code += lang_.const_decl;
+        code += GenTypeBasic(enum_def.underlying_type, false);
+      }
+      code += (lang_.language == IDLOptions::kJava) ? " " : "  ";
+      code += ev.name + " = ";
+      code += enum_def.ToString(ev);
+      code += lang_.enum_separator;
+    }
+
+    // Generate a generate string table for enum values.
+    // We do not do that for C# where this functionality is native.
+    if (lang_.language != IDLOptions::kCSharp) {
+      // Problem is, if values are very sparse that could generate really big
+      // tables. Ideally in that case we generate a map lookup instead, but for
+      // the moment we simply don't output a table at all.
+      auto range = enum_def.Distance();
+      // Average distance between values above which we consider a table
+      // "too sparse". Change at will.
+      static const uint64_t kMaxSparseness = 5;
+      if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
+        code += "\n  public static";
+        code += lang_.const_decl;
+        code += lang_.string_type;
+        code += "[] names = { ";
+        auto val = enum_def.Vals().front();
+        for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+             ++it) {
+          auto ev = *it;
+          for (auto k = enum_def.Distance(val, ev); k > 1; --k)
+            code += "\"\", ";
+          val = ev;
+          code += "\"" + (*it)->name + "\", ";
+        }
+        code += "};\n\n";
+        code += "  public static ";
+        code += lang_.string_type;
+        code += " " + MakeCamel("name", lang_.first_camel_upper);
+        code += "(int e) { return names[e";
+        if (enum_def.MinValue()->IsNonZero())
+          code += " - " + enum_def.MinValue()->name;
+        code += "]; }\n";
+      }
+    }
+
+    // Close the class
+    code += "}";
+    // Java does not need the closing semi-colon on class definitions.
+    code += (lang_.language != IDLOptions::kJava) ? ";" : "";
+    code += "\n\n";
+  }
+
+  // Returns the function name that is able to read a value of the given type.
+  std::string GenGetter(const Type &type) const {
+    switch (type.base_type) {
+      case BASE_TYPE_STRING: return lang_.accessor_prefix + "__string";
+      case BASE_TYPE_STRUCT: return lang_.accessor_prefix + "__struct";
+      case BASE_TYPE_UNION: return lang_.accessor_prefix + "__union";
+      case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+      case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
+      default: {
+        std::string getter =
+            lang_.accessor_prefix + "bb." + FunctionStart('G') + "et";
+        if (type.base_type == BASE_TYPE_BOOL) {
+          getter = "0!=" + getter;
+        } else if (GenTypeBasic(type, false) != "byte") {
+          getter += MakeCamel(GenTypeBasic(type, false));
+        }
+        return getter;
+      }
+    }
+  }
+
+  // Returns the function name that is able to read a value of the given type.
+  std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
+                                      const std::string &data_buffer,
+                                      const char *num = nullptr) const {
+    auto type = key_field->value.type;
+    auto dest_mask = DestinationMask(type, true);
+    auto dest_cast = DestinationCast(type);
+    auto getter = data_buffer + "." + FunctionStart('G') + "et";
+    if (GenTypeBasic(type, false) != "byte") {
+      getter += MakeCamel(GenTypeBasic(type, false));
+    }
+    getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
+             dest_mask;
+    return getter;
+  }
+
+  // Direct mutation is only allowed for scalar fields.
+  // Hence a setter method will only be generated for such fields.
+  std::string GenSetter(const Type &type) const {
+    if (IsScalar(type.base_type)) {
+      std::string setter =
+          lang_.accessor_prefix + "bb." + FunctionStart('P') + "ut";
+      if (GenTypeBasic(type, false) != "byte" &&
+          type.base_type != BASE_TYPE_BOOL) {
+        setter += MakeCamel(GenTypeBasic(type, false));
+      }
+      return setter;
+    } else {
+      return "";
+    }
+  }
+
+  // Returns the method name for use with add/put calls.
+  std::string GenMethod(const Type &type) const {
+    return IsScalar(type.base_type) ? MakeCamel(GenTypeBasic(type, false))
+                                    : (IsStruct(type) ? "Struct" : "Offset");
+  }
+
+  // Recursively generate arguments for a constructor, to deal with nested
+  // structs.
+  void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
+                     const char *nameprefix, size_t array_count = 0) const {
+    std::string &code = *code_ptr;
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      const auto &field_type = field.value.type;
+      const auto array_field = IsArray(field_type);
+      const auto &type = array_field ? field_type.VectorType()
+                                     : DestinationType(field_type, false);
+      const auto array_cnt = array_field ? (array_count + 1) : array_count;
+      if (IsStruct(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.
+        GenStructArgs(*field_type.struct_def, code_ptr,
+                      (nameprefix + (field.name + "_")).c_str(), array_cnt);
+      } else {
+        code += ", ";
+        code += GenTypeBasic(type);
+        if (lang_.language == IDLOptions::kJava) {
+          for (size_t i = 0; i < array_cnt; i++) code += "[]";
+        } else if (lang_.language == IDLOptions::kCSharp) {
+          if (array_cnt > 0) {
+            code += "[";
+            for (size_t i = 1; i < array_cnt; i++) code += ",";
+            code += "]";
+          }
+        } else {
+          FLATBUFFERS_ASSERT(0);
+        }
+        code += " ";
+        code += nameprefix;
+        code += MakeCamel(field.name, lang_.first_camel_upper);
+      }
+    }
+  }
+
+  // Recusively generate struct construction statements of the form:
+  // builder.putType(name);
+  // and insert manual padding.
+  void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
+                     const char *nameprefix, size_t index = 0,
+                     bool in_array = false) const {
+    std::string &code = *code_ptr;
+    std::string indent((index + 1) * 2, ' ');
+    code += indent + "  builder." + FunctionStart('P') + "rep(";
+    code += NumToString(struct_def.minalign) + ", ";
+    code += NumToString(struct_def.bytesize) + ");\n";
+    for (auto it = struct_def.fields.vec.rbegin();
+         it != struct_def.fields.vec.rend(); ++it) {
+      auto &field = **it;
+      const auto &field_type = field.value.type;
+      if (field.padding) {
+        code += indent + "  builder." + FunctionStart('P') + "ad(";
+        code += NumToString(field.padding) + ");\n";
+      }
+      if (IsStruct(field_type)) {
+        GenStructBody(*field_type.struct_def, code_ptr,
+                      (nameprefix + (field.name + "_")).c_str(), index,
+                      in_array);
+      } else {
+        const auto &type =
+            IsArray(field_type) ? field_type.VectorType() : field_type;
+        const auto index_var = "_idx" + NumToString(index);
+        if (IsArray(field_type)) {
+          code += indent + "  for (int " + index_var + " = ";
+          code += NumToString(field_type.fixed_length);
+          code += "; " + index_var + " > 0; " + index_var + "--) {\n";
+          in_array = true;
+        }
+        if (IsStruct(type)) {
+          GenStructBody(*field_type.struct_def, code_ptr,
+                        (nameprefix + (field.name + "_")).c_str(), index + 1,
+                        in_array);
+        } else {
+          code += IsArray(field_type) ? "  " : "";
+          code += indent + "  builder." + FunctionStart('P') + "ut";
+          code += GenMethod(type) + "(";
+          code += SourceCast(type);
+          auto argname =
+              nameprefix + MakeCamel(field.name, lang_.first_camel_upper);
+          code += argname;
+          size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
+          if (lang_.language == IDLOptions::kJava) {
+            for (size_t i = 0; in_array && i < array_cnt; i++) {
+              code += "[_idx" + NumToString(i) + "-1]";
+            }
+          } else if (lang_.language == IDLOptions::kCSharp) {
+            if (array_cnt > 0) {
+              code += "[";
+              for (size_t i = 0; in_array && i < array_cnt; i++) {
+                code += "_idx" + NumToString(i) + "-1";
+                if (i != (array_cnt - 1)) code += ",";
+              }
+              code += "]";
+            }
+          } else {
+            FLATBUFFERS_ASSERT(0);
+          }
+          code += ");\n";
+        }
+        if (IsArray(field_type)) { code += indent + "  }\n"; }
+      }
+    }
+  }
+
+  std::string GenByteBufferLength(const char *bb_name) const {
+    std::string bb_len = bb_name;
+    if (lang_.language == IDLOptions::kCSharp)
+      bb_len += ".Length";
+    else
+      bb_len += ".capacity()";
+    return bb_len;
+  }
+
+  std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
+                              const char *num = nullptr) const {
+    std::string key_offset = "";
+    key_offset += lang_.accessor_prefix_static + "__offset(" +
+                  NumToString(key_field->value.offset) + ", ";
+    if (num) {
+      key_offset += num;
+      key_offset +=
+          (lang_.language == IDLOptions::kCSharp ? ".Value, builder.DataBuffer)"
+                                                 : ", _bb)");
+    } else {
+      key_offset += GenByteBufferLength("bb");
+      key_offset += " - tableOffset, bb)";
+    }
+    return key_offset;
+  }
+
+  std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const {
+    std::string key_getter = "      ";
+    key_getter += "int tableOffset = " + lang_.accessor_prefix_static;
+    key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
+    key_getter += ", bb);\n      ";
+    if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+      key_getter += "int comp = " + lang_.accessor_prefix_static;
+      key_getter += FunctionStart('C') + "ompareStrings(";
+      key_getter += GenOffsetGetter(key_field);
+      key_getter += ", byteKey, bb);\n";
+    } else {
+      auto get_val = GenGetterForLookupByKey(key_field, "bb");
+      if (lang_.language == IDLOptions::kCSharp) {
+        key_getter += "int comp = " + get_val + ".CompareTo(key);\n";
+      } else {
+        key_getter += GenTypeNameDest(key_field->value.type) + " val = ";
+        key_getter += get_val + ";\n";
+        key_getter += "      int comp = val > key ? 1 : val < key ? -1 : 0;\n";
+      }
+    }
+    return key_getter;
+  }
+
+  std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const {
+    std::string key_getter = "";
+    auto data_buffer =
+        (lang_.language == IDLOptions::kCSharp) ? "builder.DataBuffer" : "_bb";
+    if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+      if (lang_.language == IDLOptions::kJava) key_getter += " return ";
+      key_getter += lang_.accessor_prefix_static;
+      key_getter += FunctionStart('C') + "ompareStrings(";
+      key_getter += GenOffsetGetter(key_field, "o1") + ", ";
+      key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
+      if (lang_.language == IDLOptions::kJava) key_getter += ";";
+    } else {
+      auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
+      if (lang_.language == IDLOptions::kCSharp) {
+        key_getter += field_getter;
+        field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
+        key_getter += ".CompareTo(" + field_getter + ")";
+      } else {
+        key_getter +=
+            "\n    " + GenTypeNameDest(key_field->value.type) + " val_1 = ";
+        key_getter +=
+            field_getter + ";\n    " + GenTypeNameDest(key_field->value.type);
+        key_getter += " val_2 = ";
+        field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
+        key_getter += field_getter + ";\n";
+        key_getter +=
+            "    return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n ";
+      }
+    }
+    return key_getter;
+  }
+
+  void GenStruct(StructDef &struct_def, std::string *code_ptr) const {
+    if (struct_def.generated) return;
+    std::string &code = *code_ptr;
+
+    // Generate a struct accessor class, with methods of the form:
+    // public type name() { return bb.getType(i + offset); }
+    // or for tables of the form:
+    // public type name() {
+    //   int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
+    // }
+    GenComment(struct_def.doc_comment, code_ptr, &lang_.comment_config);
+    if (struct_def.attributes.Lookup("private")) {
+      // For Java, we leave the struct unmarked to indicate package-private
+      // For C# we mark the struct as internal
+      if (lang_.language == IDLOptions::kCSharp) {
+        code += "internal ";
+      }
+    } else {
+      code += "public ";
+    }
+    if (lang_.language == IDLOptions::kCSharp &&
+        struct_def.attributes.Lookup("csharp_partial")) {
+      // generate a partial class for this C# struct/table
+      code += "partial ";
+    } else {
+      code += lang_.unsubclassable_decl;
+    }
+    code += lang_.accessor_type + struct_def.name;
+    if (lang_.language == IDLOptions::kCSharp) {
+      code += " : IFlatbufferObject";
+      code += lang_.open_curly;
+      code += "  private ";
+      code += struct_def.fixed ? "Struct" : "Table";
+      code += " __p;\n";
+
+      if (lang_.language == IDLOptions::kCSharp) {
+        code += "  public ByteBuffer ByteBuffer { get { return __p.bb; } }\n";
+      }
+
+    } else {
+      code += lang_.inheritance_marker;
+      code += struct_def.fixed ? "Struct" : "Table";
+      code += lang_.open_curly;
+    }
+
+    if (!struct_def.fixed) {
+      // Generate verson check method.
+      // Force compile time error if not using the same version runtime.
+      code += "  public static void ValidateVersion() {";
+      if (lang_.language == IDLOptions::kCSharp)
+        code += " FlatBufferConstants.";
+      else
+        code += " Constants.";
+      code += "FLATBUFFERS_1_11_1(); ";
+      code += "}\n";
+
+      // Generate a special accessor for the table that when used as the root
+      // of a FlatBuffer
+      std::string method_name =
+          FunctionStart('G') + "etRootAs" + struct_def.name;
+      std::string method_signature =
+          "  public static " + struct_def.name + " " + method_name;
+
+      // create convenience method that doesn't require an existing object
+      code += method_signature + "(ByteBuffer _bb) ";
+      code += "{ return " + method_name + "(_bb, new " + struct_def.name +
+              "()); }\n";
+
+      // create method that allows object reuse
+      code +=
+          method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
+      code += lang_.set_bb_byteorder;
+      code += "return (obj.__assign(_bb." + FunctionStart('G') + "etInt(_bb.";
+      code += lang_.get_bb_position;
+      code += ") + _bb.";
+      code += lang_.get_bb_position;
+      code += ", _bb)); }\n";
+      if (parser_.root_struct_def_ == &struct_def) {
+        if (parser_.file_identifier_.length()) {
+          // Check if a buffer has the identifier.
+          code += "  public static ";
+          code += lang_.bool_type + struct_def.name;
+          code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
+          code += lang_.accessor_prefix_static + "__has_identifier(_bb, \"";
+          code += parser_.file_identifier_;
+          code += "\"); }\n";
+        }
+      }
+    }
+    // Generate the __init method that sets the field in a pre-existing
+    // accessor object. This is to allow object reuse.
+    code += "  public void __init(int _i, ByteBuffer _bb) ";
+    code += "{ ";
+    if (lang_.language == IDLOptions::kCSharp) {
+      code += "__p = new ";
+      code += struct_def.fixed ? "Struct" : "Table";
+      code += "(_i, _bb); ";
+    } else {
+      code += "__reset(_i, _bb); ";
+    }
+    code += "}\n";
+    code +=
+        "  public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
+    code += "{ __init(_i, _bb); return this; }\n\n";
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (field.deprecated) continue;
+      GenComment(field.doc_comment, code_ptr, &lang_.comment_config, "  ");
+      std::string type_name = GenTypeGet(field.value.type);
+      std::string type_name_dest = GenTypeNameDest(field.value.type);
+      std::string conditional_cast = "";
+      std::string optional = "";
+      if (lang_.language == IDLOptions::kCSharp && !struct_def.fixed &&
+          (field.value.type.base_type == BASE_TYPE_STRUCT ||
+           field.value.type.base_type == BASE_TYPE_UNION ||
+           (field.value.type.base_type == BASE_TYPE_VECTOR &&
+            (field.value.type.element == BASE_TYPE_STRUCT ||
+             field.value.type.element == BASE_TYPE_UNION)))) {
+        optional = lang_.optional_suffix;
+        conditional_cast = "(" + type_name_dest + optional + ")";
+      }
+      std::string dest_mask = DestinationMask(field.value.type, true);
+      std::string dest_cast = DestinationCast(field.value.type);
+      std::string src_cast = SourceCast(field.value.type);
+      std::string method_start = "  public " +
+                                 (field.required ? "" : GenNullableAnnotation(field.value.type)) +
+                                 type_name_dest + optional + " " +
+                                 MakeCamel(field.name, lang_.first_camel_upper);
+      std::string obj = lang_.language == IDLOptions::kCSharp
+                            ? "(new " + type_name + "())"
+                            : "obj";
+
+      // Most field accessors need to retrieve and test the field offset first,
+      // this is the prefix code for that:
+      auto offset_prefix =
+          IsArray(field.value.type)
+              ? " { return "
+              : (" { int o = " + lang_.accessor_prefix + "__offset(" +
+                 NumToString(field.value.offset) + "); return o != 0 ? ");
+      // Generate the accessors that don't do object reuse.
+      if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+        // Calls the accessor that takes an accessor object with a new object.
+        if (lang_.language != IDLOptions::kCSharp) {
+          code += method_start + "() { return ";
+          code += MakeCamel(field.name, lang_.first_camel_upper);
+          code += "(new ";
+          code += type_name + "()); }\n";
+        }
+      } else if (field.value.type.base_type == BASE_TYPE_VECTOR &&
+                 field.value.type.element == BASE_TYPE_STRUCT) {
+        // Accessors for vectors of structs also take accessor objects, this
+        // generates a variant without that argument.
+        if (lang_.language != IDLOptions::kCSharp) {
+          code += method_start + "(int j) { return ";
+          code += MakeCamel(field.name, lang_.first_camel_upper);
+          code += "(new " + type_name + "(), j); }\n";
+        }
+      } else if (field.value.type.base_type == BASE_TYPE_UNION ||
+          (field.value.type.base_type == BASE_TYPE_VECTOR &&
+           field.value.type.VectorType().base_type == BASE_TYPE_UNION)) {
+        if (lang_.language == IDLOptions::kCSharp) {
+          // Union types in C# use generic Table-derived type for better type
+          // safety.
+          method_start += "<TTable>";
+          type_name = type_name_dest;
+        }
+      }
+      std::string getter = dest_cast + GenGetter(field.value.type);
+      code += method_start;
+      std::string default_cast = "";
+      // only create default casts for c# scalars or vectors of scalars
+      if (lang_.language == IDLOptions::kCSharp &&
+          (IsScalar(field.value.type.base_type) ||
+           (field.value.type.base_type == BASE_TYPE_VECTOR &&
+            IsScalar(field.value.type.element)))) {
+        // For scalars, default value will be returned by GetDefaultValue().
+        // If the scalar is an enum, GetDefaultValue() returns an actual c# enum
+        // that doesn't need to be casted. However, default values for enum
+        // elements of vectors are integer literals ("0") and are still casted
+        // for clarity.
+        if (field.value.type.enum_def == nullptr ||
+            field.value.type.base_type == BASE_TYPE_VECTOR) {
+          default_cast = "(" + type_name_dest + ")";
+        }
+      }
+      std::string member_suffix = "; ";
+      if (IsScalar(field.value.type.base_type)) {
+        code += lang_.getter_prefix;
+        member_suffix += lang_.getter_suffix;
+        if (struct_def.fixed) {
+          code += " { return " + getter;
+          code += "(" + lang_.accessor_prefix + "bb_pos + ";
+          code += NumToString(field.value.offset) + ")";
+          code += dest_mask;
+        } else {
+          code += offset_prefix + getter;
+          code += "(o + " + lang_.accessor_prefix + "bb_pos)" + dest_mask;
+          code += " : " + default_cast;
+          code += GenDefaultValue(field);
+        }
+      } else {
+        switch (field.value.type.base_type) {
+          case BASE_TYPE_STRUCT:
+            if (lang_.language != IDLOptions::kCSharp) {
+              code += "(" + type_name + " obj" + ")";
+            } else {
+              code += lang_.getter_prefix;
+              member_suffix += lang_.getter_suffix;
+            }
+            if (struct_def.fixed) {
+              code += " { return " + obj + ".__assign(" + lang_.accessor_prefix;
+              code += "bb_pos + " + NumToString(field.value.offset) + ", ";
+              code += lang_.accessor_prefix + "bb)";
+            } else {
+              code += offset_prefix + conditional_cast;
+              code += obj + ".__assign(";
+              code += field.value.type.struct_def->fixed
+                          ? "o + " + lang_.accessor_prefix + "bb_pos"
+                          : lang_.accessor_prefix + "__indirect(o + " +
+                                lang_.accessor_prefix + "bb_pos)";
+              code += ", " + lang_.accessor_prefix + "bb) : null";
+            }
+            break;
+          case BASE_TYPE_STRING:
+            code += lang_.getter_prefix;
+            member_suffix += lang_.getter_suffix;
+            code += offset_prefix + getter + "(o + " + lang_.accessor_prefix;
+            code += "bb_pos) : null";
+            break;
+          case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();  // fall thru
+          case BASE_TYPE_VECTOR: {
+            auto vectortype = field.value.type.VectorType();
+            if (vectortype.base_type == BASE_TYPE_UNION &&
+                lang_.language == IDLOptions::kCSharp) {
+                  conditional_cast = "(TTable?)";
+                  getter += "<TTable>";
+            }
+            code += "(";
+            if (vectortype.base_type == BASE_TYPE_STRUCT) {
+              if (lang_.language != IDLOptions::kCSharp)
+                code += type_name + " obj, ";
+              getter = obj + ".__assign";
+            } else if (vectortype.base_type == BASE_TYPE_UNION) {
+              if (lang_.language != IDLOptions::kCSharp)
+                code += type_name + " obj, ";
+            }
+            code += "int j)";
+            const auto body = offset_prefix + conditional_cast + getter + "(";
+            if (vectortype.base_type == BASE_TYPE_UNION) {
+              if (lang_.language != IDLOptions::kCSharp)
+                code += body + "obj, ";
+              else
+                code += " where TTable : struct, IFlatbufferObject" + body;
+            } else {
+              code += body;
+            }
+            auto index = lang_.accessor_prefix;
+            if (IsArray(field.value.type)) {
+              index += "bb_pos + " + NumToString(field.value.offset) + " + ";
+            } else {
+              index += "__vector(o) + ";
+            }
+            index += "j * " + NumToString(InlineSize(vectortype));
+            if (vectortype.base_type == BASE_TYPE_STRUCT) {
+              code += vectortype.struct_def->fixed
+                          ? index
+                          : lang_.accessor_prefix + "__indirect(" + index + ")";
+              code += ", " + lang_.accessor_prefix + "bb";
+            } else if (vectortype.base_type == BASE_TYPE_UNION) {
+              code += index + " - " + lang_.accessor_prefix +  "bb_pos";
+            } else {
+              code += index;
+            }
+            code += ")" + dest_mask;
+            if (!IsArray(field.value.type)) {
+              code += " : ";
+              code +=
+                  field.value.type.element == BASE_TYPE_BOOL
+                      ? "false"
+                      : (IsScalar(field.value.type.element) ? default_cast + "0"
+                                                            : "null");
+            }
+
+            break;
+          }
+          case BASE_TYPE_UNION:
+            if (lang_.language == IDLOptions::kCSharp) {
+              code += "() where TTable : struct, IFlatbufferObject";
+              code += offset_prefix + "(TTable?)" + getter;
+              code += "<TTable>(o) : null";
+            } else {
+              code += "(" + type_name + " obj)" + offset_prefix + getter;
+              code += "(obj, o) : null";
+            }
+            break;
+          default: FLATBUFFERS_ASSERT(0);
+        }
+      }
+      code += member_suffix;
+      code += "}\n";
+      if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+        code +=
+            "  public int " + MakeCamel(field.name, lang_.first_camel_upper);
+        code += "Length";
+        code += lang_.getter_prefix;
+        code += offset_prefix;
+        code += lang_.accessor_prefix + "__vector_len(o) : 0; ";
+        code += lang_.getter_suffix;
+        code += "}\n";
+        // See if we should generate a by-key accessor.
+        if (field.value.type.element == BASE_TYPE_STRUCT &&
+            !field.value.type.struct_def->fixed) {
+          auto &sd = *field.value.type.struct_def;
+          auto &fields = sd.fields.vec;
+          for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+            auto &key_field = **kit;
+            if (key_field.key) {
+              auto qualified_name = WrapInNameSpace(sd);
+              code += "  public " + qualified_name + lang_.optional_suffix + " ";
+              code += MakeCamel(field.name, lang_.first_camel_upper) + "ByKey(";
+              code += GenTypeNameDest(key_field.value.type) + " key)";
+              code += offset_prefix;
+              code += qualified_name + ".__lookup_by_key(";
+              if (lang_.language == IDLOptions::kJava)
+                code += "null, ";
+              code += lang_.accessor_prefix + "__vector(o), key, ";
+              code += lang_.accessor_prefix + "bb) : null; ";
+              code += "}\n";
+              if (lang_.language == IDLOptions::kJava) {
+                code += "  public " + qualified_name + lang_.optional_suffix + " ";
+                code += MakeCamel(field.name, lang_.first_camel_upper) + "ByKey(";
+                code += qualified_name + lang_.optional_suffix + " obj, ";
+                code += GenTypeNameDest(key_field.value.type) + " key)";
+                code += offset_prefix;
+                code += qualified_name + ".__lookup_by_key(obj, ";
+                code += lang_.accessor_prefix + "__vector(o), key, ";
+                code += lang_.accessor_prefix + "bb) : null; ";
+                code += "}\n";
+              }
+              break;
+            }
+          }
+        }
+      }
+      // Generate a ByteBuffer accessor for strings & vectors of scalars.
+      if ((field.value.type.base_type == BASE_TYPE_VECTOR &&
+           IsScalar(field.value.type.VectorType().base_type)) ||
+          field.value.type.base_type == BASE_TYPE_STRING) {
+        switch (lang_.language) {
+          case IDLOptions::kJava:
+            code += "  public ByteBuffer ";
+            code += MakeCamel(field.name, lang_.first_camel_upper);
+            code += "AsByteBuffer() { return ";
+            code += lang_.accessor_prefix + "__vector_as_bytebuffer(";
+            code += NumToString(field.value.offset) + ", ";
+            code +=
+                NumToString(field.value.type.base_type == BASE_TYPE_STRING
+                                ? 1
+                                : InlineSize(field.value.type.VectorType()));
+            code += "); }\n";
+            code += "  public ByteBuffer ";
+            code += MakeCamel(field.name, lang_.first_camel_upper);
+            code += "InByteBuffer(ByteBuffer _bb) { return ";
+            code += lang_.accessor_prefix + "__vector_in_bytebuffer(_bb, ";
+            code += NumToString(field.value.offset) + ", ";
+            code +=
+                NumToString(field.value.type.base_type == BASE_TYPE_STRING
+                                ? 1
+                                : InlineSize(field.value.type.VectorType()));
+            code += "); }\n";
+            break;
+          case IDLOptions::kCSharp:
+            code += "#if ENABLE_SPAN_T\n";
+            code += "  public Span<byte> Get";
+            code += MakeCamel(field.name, lang_.first_camel_upper);
+            code += "Bytes() { return ";
+            code += lang_.accessor_prefix + "__vector_as_span(";
+            code += NumToString(field.value.offset);
+            code += "); }\n";
+            code += "#else\n";
+            code += "  public ArraySegment<byte>? Get";
+            code += MakeCamel(field.name, lang_.first_camel_upper);
+            code += "Bytes() { return ";
+            code += lang_.accessor_prefix + "__vector_as_arraysegment(";
+            code += NumToString(field.value.offset);
+            code += "); }\n";
+            code += "#endif\n";
+
+            // For direct blockcopying the data into a typed array
+            code += "  public ";
+            code += GenTypeBasic(field.value.type.VectorType());
+            code += "[] Get";
+            code += MakeCamel(field.name, lang_.first_camel_upper);
+            code += "Array() { return ";
+            code += lang_.accessor_prefix + "__vector_as_array<";
+            code += GenTypeBasic(field.value.type.VectorType());
+            code += ">(";
+            code += NumToString(field.value.offset);
+            code += "); }\n";
+            break;
+          default: break;
+        }
+      }
+      // generate object accessors if is nested_flatbuffer
+      if (field.nested_flatbuffer) {
+        auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
+        auto nested_method_name =
+            MakeCamel(field.name, lang_.first_camel_upper) + "As" +
+            field.nested_flatbuffer->name;
+        auto get_nested_method_name = nested_method_name;
+        if (lang_.language == IDLOptions::kCSharp) {
+          get_nested_method_name = "Get" + nested_method_name;
+          conditional_cast =
+              "(" + nested_type_name + lang_.optional_suffix + ")";
+        }
+        if (lang_.language != IDLOptions::kCSharp) {
+          code += "  public " + nested_type_name + lang_.optional_suffix + " ";
+          code += nested_method_name + "() { return ";
+          code +=
+              get_nested_method_name + "(new " + nested_type_name + "()); }\n";
+        } else {
+          obj = "(new " + nested_type_name + "())";
+        }
+        code += "  public " + nested_type_name + lang_.optional_suffix + " ";
+        code += get_nested_method_name + "(";
+        if (lang_.language != IDLOptions::kCSharp)
+          code += nested_type_name + " obj";
+        code += ") { int o = " + lang_.accessor_prefix + "__offset(";
+        code += NumToString(field.value.offset) + "); ";
+        code += "return o != 0 ? " + conditional_cast + obj + ".__assign(";
+        code += lang_.accessor_prefix;
+        code += "__indirect(" + lang_.accessor_prefix + "__vector(o)), ";
+        code += lang_.accessor_prefix + "bb) : null; }\n";
+      }
+      // Generate mutators for scalar fields or vectors of scalars.
+      if (parser_.opts.mutable_buffer) {
+        auto is_series = (IsSeries(field.value.type));
+        const auto &underlying_type =
+            is_series ? field.value.type.VectorType() : field.value.type;
+        // Boolean parameters have to be explicitly converted to byte
+        // representation.
+        auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
+                                    ? "(byte)(" + field.name + " ? 1 : 0)"
+                                    : field.name;
+        auto mutator_prefix = MakeCamel("mutate", lang_.first_camel_upper);
+        // A vector mutator also needs the index of the vector element it should
+        // mutate.
+        auto mutator_params = (is_series ? "(int j, " : "(") +
+                              GenTypeNameDest(underlying_type) + " " +
+                              field.name + ") { ";
+        auto setter_index =
+            is_series
+                ? lang_.accessor_prefix +
+                      (IsArray(field.value.type)
+                           ? "bb_pos + " + NumToString(field.value.offset)
+                           : "__vector(o)") +
+                      +" + j * " + NumToString(InlineSize(underlying_type))
+                : (struct_def.fixed
+                       ? lang_.accessor_prefix + "bb_pos + " +
+                             NumToString(field.value.offset)
+                       : "o + " + lang_.accessor_prefix + "bb_pos");
+        if (IsScalar(underlying_type.base_type)) {
+          code += "  public ";
+          code += struct_def.fixed ? "void " : lang_.bool_type;
+          code += mutator_prefix + MakeCamel(field.name, true);
+          code += mutator_params;
+          if (struct_def.fixed) {
+            code += GenSetter(underlying_type) + "(" + setter_index + ", ";
+            code += src_cast + setter_parameter + "); }\n";
+          } else {
+            code += "int o = " + lang_.accessor_prefix + "__offset(";
+            code += NumToString(field.value.offset) + ");";
+            code += " if (o != 0) { " + GenSetter(underlying_type);
+            code += "(" + setter_index + ", " + src_cast + setter_parameter +
+                    "); return true; } else { return false; } }\n";
+          }
+        }
+      }
+    }
+    code += "\n";
+    flatbuffers::FieldDef *key_field = nullptr;
+    if (struct_def.fixed) {
+      // create a struct constructor function
+      code += "  public static " + GenOffsetType(struct_def) + " ";
+      code += FunctionStart('C') + "reate";
+      code += struct_def.name + "(FlatBufferBuilder builder";
+      GenStructArgs(struct_def, code_ptr, "");
+      code += ") {\n";
+      GenStructBody(struct_def, code_ptr, "");
+      code += "    return ";
+      code += GenOffsetConstruct(
+          struct_def, "builder." + std::string(lang_.get_fbb_offset));
+      code += ";\n  }\n";
+    } else {
+      // Generate a method that creates a table in one go. This is only possible
+      // when the table has no struct fields, since those have to be created
+      // inline, and there's no way to do so in Java.
+      bool has_no_struct_fields = true;
+      int num_fields = 0;
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        auto &field = **it;
+        if (field.deprecated) continue;
+        if (IsStruct(field.value.type)) {
+          has_no_struct_fields = false;
+        } else {
+          num_fields++;
+        }
+      }
+      // JVM specifications restrict default constructor params to be < 255.
+      // Longs and doubles take up 2 units, so we set the limit to be < 127.
+      if (has_no_struct_fields && num_fields && num_fields < 127) {
+        // Generate a table constructor of the form:
+        // public static int createName(FlatBufferBuilder builder, args...)
+        code += "  public static " + GenOffsetType(struct_def) + " ";
+        code += FunctionStart('C') + "reate" + struct_def.name;
+        code += "(FlatBufferBuilder builder";
+        for (auto it = struct_def.fields.vec.begin();
+             it != struct_def.fields.vec.end(); ++it) {
+          auto &field = **it;
+          if (field.deprecated) continue;
+          code += ",\n      ";
+          code += GenTypeBasic(DestinationType(field.value.type, false));
+          code += " ";
+          code += field.name;
+          if (!IsScalar(field.value.type.base_type)) code += "Offset";
+
+          // Java doesn't have defaults, which means this method must always
+          // supply all arguments, and thus won't compile when fields are added.
+          if (lang_.language != IDLOptions::kJava) {
+            code += " = ";
+            code += GenDefaultValueBasic(field);
+          }
+        }
+        code += ") {\n    builder.";
+        code += FunctionStart('S') + "tartTable(";
+        code += NumToString(struct_def.fields.vec.size()) + ");\n";
+        for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
+             size; size /= 2) {
+          for (auto it = struct_def.fields.vec.rbegin();
+               it != struct_def.fields.vec.rend(); ++it) {
+            auto &field = **it;
+            if (!field.deprecated &&
+                (!struct_def.sortbysize ||
+                 size == SizeOf(field.value.type.base_type))) {
+              code += "    " + struct_def.name + ".";
+              code += FunctionStart('A') + "dd";
+              code += MakeCamel(field.name) + "(builder, " + field.name;
+              if (!IsScalar(field.value.type.base_type)) code += "Offset";
+              code += ");\n";
+            }
+          }
+        }
+        code += "    return " + struct_def.name + ".";
+        code += FunctionStart('E') + "nd" + struct_def.name;
+        code += "(builder);\n  }\n\n";
+      }
+      // Generate a set of static methods that allow table construction,
+      // of the form:
+      // public static void addName(FlatBufferBuilder builder, short name)
+      // { builder.addShort(id, name, default); }
+      // Unlike the Create function, these always work.
+      code += "  public static void " + FunctionStart('S') + "tart";
+      code += struct_def.name;
+      code += "(FlatBufferBuilder builder) { builder.";
+      code += FunctionStart('S') + "tartTable(";
+      code += NumToString(struct_def.fields.vec.size()) + "); }\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.key) key_field = &field;
+        code += "  public static void " + FunctionStart('A') + "dd";
+        code += MakeCamel(field.name);
+        code += "(FlatBufferBuilder builder, ";
+        code += GenTypeBasic(DestinationType(field.value.type, false));
+        auto argname = MakeCamel(field.name, false);
+        if (!IsScalar(field.value.type.base_type)) argname += "Offset";
+        code += " " + argname + ") { builder." + FunctionStart('A') + "dd";
+        code += GenMethod(field.value.type) + "(";
+        code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
+        code += SourceCastBasic(field.value.type);
+        code += argname;
+        if (!IsScalar(field.value.type.base_type) &&
+            field.value.type.base_type != BASE_TYPE_UNION &&
+            lang_.language == IDLOptions::kCSharp) {
+          code += ".Value";
+        }
+        code += ", ";
+        if (lang_.language == IDLOptions::kJava)
+          code += SourceCastBasic(field.value.type);
+        code += GenDefaultValue(field, false);
+        code += "); }\n";
+        if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+          auto vector_type = field.value.type.VectorType();
+          auto alignment = InlineAlignment(vector_type);
+          auto elem_size = InlineSize(vector_type);
+          if (!IsStruct(vector_type)) {
+            // Generate a method to create a vector from a Java array.
+            code += "  public static " + GenVectorOffsetType() + " ";
+            code += FunctionStart('C') + "reate";
+            code += MakeCamel(field.name);
+            code += "Vector(FlatBufferBuilder builder, ";
+            code += GenTypeBasic(vector_type) + "[] data) ";
+            code += "{ builder." + FunctionStart('S') + "tartVector(";
+            code += NumToString(elem_size);
+            code += ", data." + FunctionStart('L') + "ength, ";
+            code += NumToString(alignment);
+            code += "); for (int i = data.";
+            code += FunctionStart('L') + "ength - 1; i >= 0; i--) builder.";
+            code += FunctionStart('A') + "dd";
+            code += GenMethod(vector_type);
+            code += "(";
+            code += SourceCastBasic(vector_type, false);
+            code += "data[i]";
+            if (lang_.language == IDLOptions::kCSharp &&
+                (vector_type.base_type == BASE_TYPE_STRUCT ||
+                 vector_type.base_type == BASE_TYPE_STRING))
+              code += ".Value";
+            code += "); return ";
+            code += "builder." + FunctionStart('E') + "ndVector(); }\n";
+            // For C#, include a block copy method signature.
+            if (lang_.language == IDLOptions::kCSharp) {
+              code += "  public static " + GenVectorOffsetType() + " ";
+              code += FunctionStart('C') + "reate";
+              code += MakeCamel(field.name);
+              code += "VectorBlock(FlatBufferBuilder builder, ";
+              code += GenTypeBasic(vector_type) + "[] data) ";
+              code += "{ builder." + FunctionStart('S') + "tartVector(";
+              code += NumToString(elem_size);
+              code += ", data." + FunctionStart('L') + "ength, ";
+              code += NumToString(alignment);
+              code += "); builder.Add(data); return builder.EndVector(); }\n";
+            }
+          }
+          // Generate a method to start a vector, data to be added manually
+          // after.
+          code += "  public static void " + FunctionStart('S') + "tart";
+          code += MakeCamel(field.name);
+          code += "Vector(FlatBufferBuilder builder, int numElems) ";
+          code += "{ builder." + FunctionStart('S') + "tartVector(";
+          code += NumToString(elem_size);
+          code += ", numElems, " + NumToString(alignment);
+          code += "); }\n";
+        }
+      }
+      code += "  public static " + GenOffsetType(struct_def) + " ";
+      code += FunctionStart('E') + "nd" + struct_def.name;
+      code += "(FlatBufferBuilder builder) {\n    int o = builder.";
+      code += FunctionStart('E') + "ndTable();\n";
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        auto &field = **it;
+        if (!field.deprecated && field.required) {
+          code += "    builder." + FunctionStart('R') + "equired(o, ";
+          code += NumToString(field.value.offset);
+          code += ");  // " + field.name + "\n";
+        }
+      }
+      code += "    return " + GenOffsetConstruct(struct_def, "o") + ";\n  }\n";
+      if (parser_.root_struct_def_ == &struct_def) {
+        std::string size_prefix[] = { "", "SizePrefixed" };
+        for (int i = 0; i < 2; ++i) {
+          code += "  public static void ";
+          code += FunctionStart('F') + "inish" + size_prefix[i] +
+                  struct_def.name;
+          code += "Buffer(FlatBufferBuilder builder, " +
+                  GenOffsetType(struct_def);
+          code += " offset) {";
+          code += " builder." + FunctionStart('F') + "inish" + size_prefix[i] +
+                  "(offset";
+          if (lang_.language == IDLOptions::kCSharp) { code += ".Value"; }
+
+          if (parser_.file_identifier_.length())
+            code += ", \"" + parser_.file_identifier_ + "\"";
+          code += "); }\n";
+        }
+      }
+    }
+    // Only generate key compare function for table,
+    // because `key_field` is not set for struct
+    if (struct_def.has_key && !struct_def.fixed) {
+      FLATBUFFERS_ASSERT(key_field);
+      if (lang_.language == IDLOptions::kJava) {
+        code += "\n  @Override\n  protected int keysCompare(";
+        code += "Integer o1, Integer o2, ByteBuffer _bb) {";
+        code += GenKeyGetter(key_field);
+        code += " }\n";
+      } else {
+        code += "\n  public static VectorOffset ";
+        code += "CreateSortedVectorOf" + struct_def.name;
+        code += "(FlatBufferBuilder builder, ";
+        code += "Offset<" + struct_def.name + ">";
+        code += "[] offsets) {\n";
+        code += "    Array.Sort(offsets, (Offset<" + struct_def.name +
+                "> o1, Offset<" + struct_def.name + "> o2) => " +
+                GenKeyGetter(key_field);
+        code += ");\n";
+        code += "    return builder.CreateVectorOfTables(offsets);\n  }\n";
+      }
+
+      code += "\n  public static " + struct_def.name + lang_.optional_suffix;
+      code += " __lookup_by_key(";
+      if (lang_.language == IDLOptions::kJava)
+        code +=  struct_def.name + " obj, ";
+      code += "int vectorLocation, ";
+      code += GenTypeNameDest(key_field->value.type);
+      code += " key, ByteBuffer bb) {\n";
+      if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+        code += "    byte[] byteKey = ";
+        if (lang_.language == IDLOptions::kJava)
+          code += "key.getBytes(Table.UTF8_CHARSET.get());\n";
+        else
+          code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
+      }
+      code += "    int span = ";
+      code += "bb." + FunctionStart('G') + "etInt(vectorLocation - 4);\n";
+      code += "    int start = 0;\n";
+      code += "    while (span != 0) {\n";
+      code += "      int middle = span / 2;\n";
+      code += GenLookupKeyGetter(key_field);
+      code += "      if (comp > 0) {\n";
+      code += "        span = middle;\n";
+      code += "      } else if (comp < 0) {\n";
+      code += "        middle++;\n";
+      code += "        start += middle;\n";
+      code += "        span -= middle;\n";
+      code += "      } else {\n";
+      code += "        return ";
+      if (lang_.language == IDLOptions::kJava)
+        code += "(obj == null ? new " + struct_def.name + "() : obj)";
+      else
+        code += "new " + struct_def.name + "()";
+      code += ".__assign(tableOffset, bb);\n";
+      code += "      }\n    }\n";
+      code += "    return null;\n";
+      code += "  }\n";
+    }
+    code += "}";
+    // Java does not need the closing semi-colon on class definitions.
+    code += (lang_.language != IDLOptions::kJava) ? ";" : "";
+    code += "\n\n";
+  }
+  const LanguageParameters &lang_;
+  // This tracks the current namespace used to determine if a type need to be
+  // prefixed by its namespace
+  const Namespace *cur_name_space_;
+};
+}  // namespace general
+
+bool GenerateGeneral(const Parser &parser, const std::string &path,
+                     const std::string &file_name) {
+  general::GeneralGenerator generator(parser, path, file_name);
+  return generator.generate();
+}
+
+std::string GeneralMakeRule(const Parser &parser, const std::string &path,
+                            const std::string &file_name) {
+  FLATBUFFERS_ASSERT(parser.opts.lang <= IDLOptions::kMAX);
+  const auto &lang = GetLangParams(parser.opts.lang);
+
+  std::string make_rule;
+
+  for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end();
+       ++it) {
+    auto &enum_def = **it;
+    if (!make_rule.empty()) make_rule += " ";
+    std::string directory =
+        BaseGenerator::NamespaceDir(parser, path, *enum_def.defined_namespace);
+    make_rule += directory + enum_def.name + lang.file_extension;
+  }
+
+  for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
+       ++it) {
+    auto &struct_def = **it;
+    if (!make_rule.empty()) make_rule += " ";
+    std::string directory = BaseGenerator::NamespaceDir(
+        parser, path, *struct_def.defined_namespace);
+    make_rule += directory + struct_def.name + lang.file_extension;
+  }
+
+  make_rule += ": ";
+  auto included_files = parser.GetIncludedFilesRecursive(file_name);
+  for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+    make_rule += " " + *it;
+  }
+  return make_rule;
+}
+
+std::string BinaryFileName(const Parser &parser, const std::string &path,
+                           const std::string &file_name) {
+  auto ext = parser.file_extension_.length() ? parser.file_extension_ : "bin";
+  return path + file_name + "." + ext;
+}
+
+bool GenerateBinary(const Parser &parser, const std::string &path,
+                    const std::string &file_name) {
+  return !parser.builder_.GetSize() ||
+         flatbuffers::SaveFile(
+             BinaryFileName(parser, path, file_name).c_str(),
+             reinterpret_cast<char *>(parser.builder_.GetBufferPointer()),
+             parser.builder_.GetSize(), true);
+}
+
+std::string BinaryMakeRule(const Parser &parser, const std::string &path,
+                           const std::string &file_name) {
+  if (!parser.builder_.GetSize()) return "";
+  std::string filebase =
+      flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+  std::string make_rule =
+      BinaryFileName(parser, path, filebase) + ": " + file_name;
+  auto included_files =
+      parser.GetIncludedFilesRecursive(parser.root_struct_def_->file);
+  for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+    make_rule += " " + *it;
+  }
+  return make_rule;
+}
+
+}  // namespace flatbuffers
diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp
new file mode 100644
index 0000000..5e62b61
--- /dev/null
+++ b/src/idl_gen_go.cpp
@@ -0,0 +1,1009 @@
+/*
+ * Copyright 2014 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.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include <sstream>
+#include <string>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#ifdef _WIN32
+#  include <direct.h>
+#  define PATH_SEPARATOR "\\"
+#  define mkdir(n, m) _mkdir(n)
+#else
+#  include <sys/stat.h>
+#  define PATH_SEPARATOR "/"
+#endif
+
+namespace flatbuffers {
+
+static std::string GeneratedFileName(const std::string &path,
+                                     const std::string &file_name) {
+  return path + file_name + "_generated.go";
+}
+
+namespace go {
+
+// see https://golang.org/ref/spec#Keywords
+static const char * const g_golang_keywords[] = {
+  "break",  "default", "func",        "interface", "select", "case", "defer",
+  "go",     "map",     "struct",      "chan",      "else",   "goto", "package",
+  "switch", "const",   "fallthrough", "if",        "range",  "type", "continue",
+  "for",    "import",  "return",      "var",
+};
+
+static std::string GoIdentity(const std::string &name) {
+  for (size_t i = 0;
+       i < sizeof(g_golang_keywords) / sizeof(g_golang_keywords[0]); i++) {
+    if (name == g_golang_keywords[i]) { return MakeCamel(name + "_", false); }
+  }
+
+  return MakeCamel(name, false);
+}
+
+class GoGenerator : public BaseGenerator {
+ public:
+  GoGenerator(const Parser &parser, const std::string &path,
+              const std::string &file_name, const std::string &go_namespace)
+      : BaseGenerator(parser, path, file_name, "" /* not used*/,
+                      "" /* not used */),
+        cur_name_space_(nullptr) {
+    std::istringstream iss(go_namespace);
+    std::string component;
+    while (std::getline(iss, component, '.')) {
+      go_namespace_.components.push_back(component);
+    }
+  }
+
+  bool generate() {
+    std::string one_file_code;
+    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+         ++it) {
+      tracked_imported_namespaces_.clear();
+      std::string enumcode;
+      GenEnum(**it, &enumcode);
+      if (parser_.opts.one_file) {
+        one_file_code += enumcode;
+      } else {
+        if (!SaveType(**it, enumcode, false, true)) return false;
+      }
+    }
+
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      tracked_imported_namespaces_.clear();
+      std::string declcode;
+      GenStruct(**it, &declcode);
+      if (parser_.opts.one_file) {
+        one_file_code += declcode;
+      } else {
+        if (!SaveType(**it, declcode, true, false)) return false;
+      }
+    }
+
+    if (parser_.opts.one_file) {
+      std::string code = "";
+      const bool is_enum = !parser_.enums_.vec.empty();
+      BeginFile(LastNamespacePart(go_namespace_), true, is_enum, &code);
+      code += one_file_code;
+      const std::string filename = GeneratedFileName(path_, file_name_);
+      return SaveFile(filename.c_str(), code, false);
+    }
+
+    return true;
+  }
+
+ private:
+  Namespace go_namespace_;
+  Namespace *cur_name_space_;
+
+  struct NamespacePtrLess {
+    bool operator()(const Namespace *a, const Namespace *b) const {
+      return *a < *b;
+    }
+  };
+  std::set<const Namespace *, NamespacePtrLess> tracked_imported_namespaces_;
+
+  // Most field accessors need to retrieve and test the field offset first,
+  // this is the prefix code for that.
+  std::string OffsetPrefix(const FieldDef &field) {
+    return "{\n\to := flatbuffers.UOffsetT(rcv._tab.Offset(" +
+           NumToString(field.value.offset) + "))\n\tif o != 0 {\n";
+  }
+
+  // Begin a class declaration.
+  void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += "type " + struct_def.name + " struct {\n\t";
+
+    // _ is reserved in flatbuffers field names, so no chance of name conflict:
+    code += "_tab ";
+    code += struct_def.fixed ? "flatbuffers.Struct" : "flatbuffers.Table";
+    code += "\n}\n\n";
+  }
+
+  // Construct the name of the type for this enum.
+  std::string GetEnumTypeName(const EnumDef &enum_def) {
+    return WrapInNameSpaceAndTrack(enum_def.defined_namespace, GoIdentity(enum_def.name));
+  }
+
+  // Create a type for the enum values.
+  void GenEnumType(const EnumDef &enum_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "type " + GetEnumTypeName(enum_def) + " ";
+    code += GenTypeBasic(enum_def.underlying_type) + "\n\n";
+  }
+
+  // Begin enum code with a class declaration.
+  void BeginEnum(std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "const (\n";
+  }
+
+  // A single enum member.
+  void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
+                  size_t max_name_length, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "\t";
+    code += enum_def.name;
+    code += ev.name;
+    code += " ";
+    code += std::string(max_name_length - ev.name.length(), ' ');
+    code += GetEnumTypeName(enum_def);
+    code += " = ";
+    code += enum_def.ToString(ev) + "\n";
+  }
+
+  // End enum code.
+  void EndEnum(std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += ")\n\n";
+  }
+
+  // Begin enum name map.
+  void BeginEnumNames(const EnumDef &enum_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "var EnumNames";
+    code += enum_def.name;
+    code += " = map[" + GetEnumTypeName(enum_def) + "]string{\n";
+  }
+
+  // A single enum name member.
+  void EnumNameMember(const EnumDef &enum_def, const EnumVal &ev,
+                      size_t max_name_length, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "\t";
+    code += enum_def.name;
+    code += ev.name;
+    code += ": ";
+    code += std::string(max_name_length - ev.name.length(), ' ');
+    code += "\"";
+    code += ev.name;
+    code += "\",\n";
+  }
+
+  // End enum name map.
+  void EndEnumNames(std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "}\n\n";
+  }
+
+  // Generate String() method on enum type.
+  void EnumStringer(const EnumDef &enum_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "func (v " + enum_def.name + ") String() string {\n";
+    code += "\tif s, ok := EnumNames" + enum_def.name + "[v]; ok {\n";
+    code += "\t\treturn s\n";
+    code += "\t}\n";
+    code += "\treturn \""+ enum_def.name;
+    code += "(\" + strconv.FormatInt(int64(v), 10) + \")\"\n";
+    code += "}\n\n";
+  }
+
+  // Begin enum value map.
+  void BeginEnumValues(const EnumDef &enum_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "var EnumValues";
+    code += enum_def.name;
+    code += " = map[string]" + GetEnumTypeName(enum_def) + "{\n";
+  }
+
+  // A single enum value member.
+  void EnumValueMember(const EnumDef &enum_def, const EnumVal &ev,
+                       size_t max_name_length, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "\t\"";
+    code += ev.name;
+    code += "\": ";
+    code += std::string(max_name_length - ev.name.length(), ' ');
+    code += enum_def.name;
+    code += ev.name;
+    code += ",\n";
+  }
+
+  // End enum value map.
+  void EndEnumValues(std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "}\n\n";
+  }
+
+  // Initialize a new struct or table from existing data.
+  void NewRootTypeFromBuffer(const StructDef &struct_def,
+                             std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += "func GetRootAs";
+    code += struct_def.name;
+    code += "(buf []byte, offset flatbuffers.UOffsetT) ";
+    code += "*" + struct_def.name + "";
+    code += " {\n";
+    code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n";
+    code += "\tx := &" + struct_def.name + "{}\n";
+    code += "\tx.Init(buf, n+offset)\n";
+    code += "\treturn x\n";
+    code += "}\n\n";
+  }
+
+  // Initialize an existing object with other data, to avoid an allocation.
+  void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    GenReceiver(struct_def, code_ptr);
+    code += " Init(buf []byte, i flatbuffers.UOffsetT) ";
+    code += "{\n";
+    code += "\trcv._tab.Bytes = buf\n";
+    code += "\trcv._tab.Pos = i\n";
+    code += "}\n\n";
+  }
+
+  // Implement the table accessor
+  void GenTableAccessor(const StructDef &struct_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    GenReceiver(struct_def, code_ptr);
+    code += " Table() flatbuffers.Table ";
+    code += "{\n";
+
+    if (struct_def.fixed) {
+      code += "\treturn rcv._tab.Table\n";
+    } else {
+      code += "\treturn rcv._tab\n";
+    }
+    code += "}\n\n";
+  }
+
+  // Get the length of a vector.
+  void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
+                    std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    GenReceiver(struct_def, code_ptr);
+    code += " " + MakeCamel(field.name) + "Length(";
+    code += ") int " + OffsetPrefix(field);
+    code += "\t\treturn rcv._tab.VectorLen(o)\n\t}\n";
+    code += "\treturn 0\n}\n\n";
+  }
+
+  // Get a [ubyte] vector as a byte slice.
+  void GetUByteSlice(const StructDef &struct_def, const FieldDef &field,
+                     std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    GenReceiver(struct_def, code_ptr);
+    code += " " + MakeCamel(field.name) + "Bytes(";
+    code += ") []byte " + OffsetPrefix(field);
+    code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n";
+    code += "\treturn nil\n}\n\n";
+  }
+
+  // Get the value of a struct's scalar.
+  void GetScalarFieldOfStruct(const StructDef &struct_def,
+                              const FieldDef &field,
+                              std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    std::string getter = GenGetter(field.value.type);
+    GenReceiver(struct_def, code_ptr);
+    code += " " + MakeCamel(field.name);
+    code += "() " + TypeName(field) + " {\n";
+    code += "\treturn " + CastToEnum(
+        field.value.type,
+        getter + "(rcv._tab.Pos + flatbuffers.UOffsetT(" +
+        NumToString(field.value.offset) + "))");
+    code += "\n}\n";
+  }
+
+  // Get the value of a table's scalar.
+  void GetScalarFieldOfTable(const StructDef &struct_def,
+                             const FieldDef &field,
+                             std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    std::string getter = GenGetter(field.value.type);
+    GenReceiver(struct_def, code_ptr);
+    code += " " + MakeCamel(field.name);
+    code += "() " + TypeName(field) + " ";
+    code += OffsetPrefix(field) + "\t\treturn ";
+    code += CastToEnum(field.value.type, getter + "(o + rcv._tab.Pos)");
+    code += "\n\t}\n";
+    code += "\treturn " + GenConstant(field) + "\n";
+    code += "}\n\n";
+  }
+
+  // Get a struct by initializing an existing struct.
+  // Specific to Struct.
+  void GetStructFieldOfStruct(const StructDef &struct_def,
+                              const FieldDef &field,
+                              std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    GenReceiver(struct_def, code_ptr);
+    code += " " + MakeCamel(field.name);
+    code += "(obj *" + TypeName(field);
+    code += ") *" + TypeName(field);
+    code += " {\n";
+    code += "\tif obj == nil {\n";
+    code += "\t\tobj = new(" + TypeName(field) + ")\n";
+    code += "\t}\n";
+    code += "\tobj.Init(rcv._tab.Bytes, rcv._tab.Pos+";
+    code += NumToString(field.value.offset) + ")";
+    code += "\n\treturn obj\n";
+    code += "}\n";
+  }
+
+  // Get a struct by initializing an existing struct.
+  // Specific to Table.
+  void GetStructFieldOfTable(const StructDef &struct_def,
+                             const FieldDef &field,
+                             std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    GenReceiver(struct_def, code_ptr);
+    code += " " + MakeCamel(field.name);
+    code += "(obj *";
+    code += TypeName(field);
+    code += ") *" + TypeName(field) + " " + OffsetPrefix(field);
+    if (field.value.type.struct_def->fixed) {
+      code += "\t\tx := o + rcv._tab.Pos\n";
+    } else {
+      code += "\t\tx := rcv._tab.Indirect(o + rcv._tab.Pos)\n";
+    }
+    code += "\t\tif obj == nil {\n";
+    code += "\t\t\tobj = new(" + TypeName(field) + ")\n";
+    code += "\t\t}\n";
+    code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
+    code += "\t\treturn obj\n\t}\n\treturn nil\n";
+    code += "}\n\n";
+  }
+
+  // Get the value of a string.
+  void GetStringField(const StructDef &struct_def,
+                      const FieldDef &field,
+                      std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    GenReceiver(struct_def, code_ptr);
+    code += " " + MakeCamel(field.name);
+    code += "() " + TypeName(field) + " ";
+    code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type);
+    code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n";
+    code += "}\n\n";
+  }
+
+  // Get the value of a union from an object.
+  void GetUnionField(const StructDef &struct_def, const FieldDef &field,
+                     std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    GenReceiver(struct_def, code_ptr);
+    code += " " + MakeCamel(field.name) + "(";
+    code += "obj " + GenTypePointer(field.value.type) + ") bool ";
+    code += OffsetPrefix(field);
+    code += "\t\t" + GenGetter(field.value.type);
+    code += "(obj, o)\n\t\treturn true\n\t}\n";
+    code += "\treturn false\n";
+    code += "}\n\n";
+  }
+
+  // Get the value of a vector's struct member.
+  void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+                                 const FieldDef &field,
+                                 std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    auto vectortype = field.value.type.VectorType();
+
+    GenReceiver(struct_def, code_ptr);
+    code += " " + MakeCamel(field.name);
+    code += "(obj *" + TypeName(field);
+    code += ", j int) bool " + OffsetPrefix(field);
+    code += "\t\tx := rcv._tab.Vector(o)\n";
+    code += "\t\tx += flatbuffers.UOffsetT(j) * ";
+    code += NumToString(InlineSize(vectortype)) + "\n";
+    if (!(vectortype.struct_def->fixed)) {
+      code += "\t\tx = rcv._tab.Indirect(x)\n";
+    }
+    code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
+    code += "\t\treturn true\n\t}\n";
+    code += "\treturn false\n";
+    code += "}\n\n";
+  }
+
+  // Get the value of a vector's non-struct member.
+  void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
+                                    const FieldDef &field,
+                                    std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    auto vectortype = field.value.type.VectorType();
+
+    GenReceiver(struct_def, code_ptr);
+    code += " " + MakeCamel(field.name);
+    code += "(j int) " + TypeName(field) + " ";
+    code += OffsetPrefix(field);
+    code += "\t\ta := rcv._tab.Vector(o)\n";
+    code += "\t\treturn " + CastToEnum(
+        field.value.type,
+        GenGetter(field.value.type) + "(a + flatbuffers.UOffsetT(j*" +
+        NumToString(InlineSize(vectortype)) + "))");
+    code += "\n\t}\n";
+    if (vectortype.base_type == BASE_TYPE_STRING) {
+      code += "\treturn nil\n";
+    } else if (vectortype.base_type == BASE_TYPE_BOOL) {
+      code += "\treturn false\n";
+    } else {
+      code += "\treturn 0\n";
+    }
+    code += "}\n\n";
+  }
+
+  // Begin the creator function signature.
+  void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    if (code.substr(code.length() - 2) != "\n\n") {
+      // a previous mutate has not put an extra new line
+      code += "\n";
+    }
+    code += "func Create" + struct_def.name;
+    code += "(builder *flatbuffers.Builder";
+  }
+
+  // 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 + (field.name + "_")).c_str(), code_ptr);
+      } else {
+        std::string &code = *code_ptr;
+        code += std::string(", ") + nameprefix;
+        code += GoIdentity(field.name);
+        code += " " + TypeName(field);
+      }
+    }
+  }
+
+  // End the creator function signature.
+  void EndBuilderArgs(std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += ") flatbuffers.UOffsetT {\n";
+  }
+
+  // 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 += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", ";
+    code += 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 += "\tbuilder.Pad(" + NumToString(field.padding) + ")\n";
+      if (IsStruct(field.value.type)) {
+        StructBuilderBody(*field.value.type.struct_def,
+                          (nameprefix + (field.name + "_")).c_str(), code_ptr);
+      } else {
+        code += "\tbuilder.Prepend" + GenMethod(field) + "(";
+        code += CastToBaseType(field.value.type, nameprefix + GoIdentity(field.name)) + ")\n";
+      }
+    }
+  }
+
+  void EndBuilderBody(std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "\treturn builder.Offset()\n";
+    code += "}\n";
+  }
+
+  // Get the value of a table's starting offset.
+  void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "func " + struct_def.name + "Start";
+    code += "(builder *flatbuffers.Builder) {\n";
+    code += "\tbuilder.StartObject(";
+    code += NumToString(struct_def.fields.vec.size());
+    code += ")\n}\n";
+  }
+
+  // Set the value of a table's field.
+  void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
+                         const size_t offset, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "func " + struct_def.name + "Add" + MakeCamel(field.name);
+    code += "(builder *flatbuffers.Builder, ";
+    code += GoIdentity(field.name) + " ";
+    if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
+      code += "flatbuffers.UOffsetT";
+    } else {
+      code += TypeName(field);
+    }
+    code += ") {\n";
+    code += "\tbuilder.Prepend";
+    code += GenMethod(field) + "Slot(";
+    code += NumToString(offset) + ", ";
+    if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
+      code += "flatbuffers.UOffsetT";
+      code += "(";
+      code += GoIdentity(field.name) + ")";
+    } else {
+      code += CastToBaseType(field.value.type, GoIdentity(field.name));
+    }
+    code += ", " + GenConstant(field);
+    code += ")\n}\n";
+  }
+
+  // Set the value of one of the members of a table's vector.
+  void BuildVectorOfTable(const StructDef &struct_def,
+                          const FieldDef &field, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "func " + struct_def.name + "Start";
+    code += MakeCamel(field.name);
+    code += "Vector(builder *flatbuffers.Builder, numElems int) ";
+    code += "flatbuffers.UOffsetT {\n\treturn builder.StartVector(";
+    auto vector_type = field.value.type.VectorType();
+    auto alignment = InlineAlignment(vector_type);
+    auto elem_size = InlineSize(vector_type);
+    code += NumToString(elem_size);
+    code += ", numElems, " + NumToString(alignment);
+    code += ")\n}\n";
+  }
+
+  // Get the offset of the end of a table.
+  void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "func " + struct_def.name + "End";
+    code += "(builder *flatbuffers.Builder) flatbuffers.UOffsetT ";
+    code += "{\n\treturn builder.EndObject()\n}\n";
+  }
+
+  // Generate the receiver for function signatures.
+  void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "func (rcv *" + struct_def.name + ")";
+  }
+
+  // Generate a struct field getter, 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, "");
+    if (IsScalar(field.value.type.base_type)) {
+      if (struct_def.fixed) {
+        GetScalarFieldOfStruct(struct_def, field, code_ptr);
+      } else {
+        GetScalarFieldOfTable(struct_def, field, code_ptr);
+      }
+    } else {
+      switch (field.value.type.base_type) {
+        case BASE_TYPE_STRUCT:
+          if (struct_def.fixed) {
+            GetStructFieldOfStruct(struct_def, field, code_ptr);
+          } else {
+            GetStructFieldOfTable(struct_def, field, code_ptr);
+          }
+          break;
+        case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break;
+        case BASE_TYPE_VECTOR: {
+          auto vectortype = field.value.type.VectorType();
+          if (vectortype.base_type == BASE_TYPE_STRUCT) {
+            GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
+          } else {
+            GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
+          }
+          break;
+        }
+        case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
+        default: FLATBUFFERS_ASSERT(0);
+      }
+    }
+    if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+      GetVectorLen(struct_def, field, code_ptr);
+      if (field.value.type.element == BASE_TYPE_UCHAR) {
+        GetUByteSlice(struct_def, field, code_ptr);
+      }
+    }
+  }
+
+  // Mutate the value of a struct's scalar.
+  void MutateScalarFieldOfStruct(const StructDef &struct_def,
+                                 const FieldDef &field,
+                                 std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    std::string type = MakeCamel(GenTypeBasic(field.value.type));
+    std::string setter = "rcv._tab.Mutate" + type;
+    GenReceiver(struct_def, code_ptr);
+    code += " Mutate" + MakeCamel(field.name);
+    code += "(n " + TypeName(field) + ") bool {\n\treturn " + setter;
+    code += "(rcv._tab.Pos+flatbuffers.UOffsetT(";
+    code += NumToString(field.value.offset) + "), ";
+    code += CastToBaseType(field.value.type, "n") + ")\n}\n\n";
+  }
+
+  // Mutate the value of a table's scalar.
+  void MutateScalarFieldOfTable(const StructDef &struct_def,
+                                const FieldDef &field,
+                                std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    std::string type = MakeCamel(GenTypeBasic(field.value.type));
+    std::string setter = "rcv._tab.Mutate" + type + "Slot";
+    GenReceiver(struct_def, code_ptr);
+    code += " Mutate" + MakeCamel(field.name);
+    code += "(n " + TypeName(field) + ") bool {\n\treturn ";
+    code += setter + "(" + NumToString(field.value.offset) + ", ";
+    code += CastToBaseType(field.value.type, "n") + ")\n";
+    code += "}\n\n";
+  }
+
+  // Mutate an element of a vector of scalars.
+  void MutateElementOfVectorOfNonStruct(const StructDef &struct_def,
+                                        const FieldDef &field,
+                                        std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    auto vectortype = field.value.type.VectorType();
+    std::string type = MakeCamel(GenTypeBasic(vectortype));
+    std::string setter = "rcv._tab.Mutate" + type;
+    GenReceiver(struct_def, code_ptr);
+    code += " Mutate" + MakeCamel(field.name);
+    code += "(j int, n " + TypeName(field) + ") bool ";
+    code += OffsetPrefix(field);
+    code += "\t\ta := rcv._tab.Vector(o)\n";
+    code += "\t\treturn " + setter + "(";
+    code += "a+flatbuffers.UOffsetT(j*";
+    code += NumToString(InlineSize(vectortype)) + "), ";
+    code += CastToBaseType(vectortype, "n") + ")\n";
+    code += "\t}\n";
+    code += "\treturn false\n";
+    code += "}\n\n";
+  }
+
+  // Generate a struct field setter, conditioned on its child type(s).
+  void GenStructMutator(const StructDef &struct_def, const FieldDef &field,
+                        std::string *code_ptr) {
+    GenComment(field.doc_comment, code_ptr, nullptr, "");
+    if (IsScalar(field.value.type.base_type)) {
+      if (struct_def.fixed) {
+        MutateScalarFieldOfStruct(struct_def, field, code_ptr);
+      } else {
+        MutateScalarFieldOfTable(struct_def, field, code_ptr);
+      }
+    } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+      if (IsScalar(field.value.type.element)) {
+        MutateElementOfVectorOfNonStruct(struct_def, field, code_ptr);
+      }
+    }
+  }
+
+  // Generate table constructors, conditioned on its members' types.
+  void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
+    GetStartOfTable(struct_def, code_ptr);
+
+    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();
+      BuildFieldOfTable(struct_def, field, offset, code_ptr);
+      if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+        BuildVectorOfTable(struct_def, field, code_ptr);
+      }
+    }
+
+    GetEndOffsetOnTable(struct_def, code_ptr);
+  }
+
+  // Generate struct or table methods.
+  void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+    if (struct_def.generated) return;
+
+    cur_name_space_ = struct_def.defined_namespace;
+
+    GenComment(struct_def.doc_comment, code_ptr, nullptr);
+    BeginClass(struct_def, code_ptr);
+    if (!struct_def.fixed) {
+      // Generate a special accessor for the table that has been declared as
+      // the root type.
+      NewRootTypeFromBuffer(struct_def, code_ptr);
+    }
+    // Generate the Init method that sets the field in a pre-existing
+    // accessor object. This is to allow object reuse.
+    InitializeExisting(struct_def, code_ptr);
+    // Generate _tab accessor
+    GenTableAccessor(struct_def, code_ptr);
+
+    // Generate struct fields accessors
+    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);
+      GenStructMutator(struct_def, field, code_ptr);
+    }
+
+    // Generate builders
+    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;
+
+    auto max_name_length = MaxNameLength(enum_def);
+    cur_name_space_ = enum_def.defined_namespace;
+
+    GenComment(enum_def.doc_comment, code_ptr, nullptr);
+    GenEnumType(enum_def, code_ptr);
+    BeginEnum(code_ptr);
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      auto &ev = **it;
+      GenComment(ev.doc_comment, code_ptr, nullptr, "\t");
+      EnumMember(enum_def, ev, max_name_length, code_ptr);
+    }
+    EndEnum(code_ptr);
+
+    BeginEnumNames(enum_def, code_ptr);
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      auto &ev = **it;
+      EnumNameMember(enum_def, ev, max_name_length, code_ptr);
+    }
+    EndEnumNames(code_ptr);
+
+    BeginEnumValues(enum_def, code_ptr);
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+         ++it) {
+      auto &ev = **it;
+      EnumValueMember(enum_def, ev, max_name_length, code_ptr);
+    }
+    EndEnumValues(code_ptr);
+
+    EnumStringer(enum_def, code_ptr);
+  }
+
+  // Returns the function name that is able to read a value of the given type.
+  std::string GenGetter(const Type &type) {
+    switch (type.base_type) {
+      case BASE_TYPE_STRING: return "rcv._tab.ByteVector";
+      case BASE_TYPE_UNION: return "rcv._tab.Union";
+      case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+      default: return "rcv._tab.Get" + MakeCamel(GenTypeBasic(type));
+    }
+  }
+
+  // Returns the method name for use with add/put calls.
+  std::string GenMethod(const FieldDef &field) {
+    return IsScalar(field.value.type.base_type)
+               ? MakeCamel(GenTypeBasic(field.value.type))
+               : (IsStruct(field.value.type) ? "Struct" : "UOffsetT");
+  }
+
+  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) \
+        #GTYPE,
+        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+      #undef FLATBUFFERS_TD
+      // clang-format on
+    };
+    return ctypename[type.base_type];
+  }
+
+  std::string GenTypePointer(const Type &type) {
+    switch (type.base_type) {
+      case BASE_TYPE_STRING: return "[]byte";
+      case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+      case BASE_TYPE_STRUCT: return WrapInNameSpaceAndTrack(*type.struct_def);
+      case BASE_TYPE_UNION:
+        // fall through
+      default: return "*flatbuffers.Table";
+    }
+  }
+
+  std::string GenTypeGet(const Type &type) {
+    if (type.enum_def != nullptr) {
+      return GetEnumTypeName(*type.enum_def);
+    }
+    return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+  }
+
+  std::string TypeName(const FieldDef &field) {
+    return GenTypeGet(field.value.type);
+  }
+
+  // If type is an enum, returns value with a cast to the enum type, otherwise
+  // returns value as-is.
+  std::string CastToEnum(const Type &type, std::string value) {
+    if (type.enum_def == nullptr) {
+      return value;
+    } else {
+      return GenTypeGet(type) + "(" + value + ")";
+    }
+  }
+
+  // If type is an enum, returns value with a cast to the enum base type,
+  // otherwise returns value as-is.
+  std::string CastToBaseType(const Type &type, std::string value) {
+    if (type.enum_def == nullptr) {
+      return value;
+    } else {
+      return GenTypeBasic(type) + "(" + value + ")";
+    }
+  }
+
+  std::string GenConstant(const FieldDef &field) {
+    switch (field.value.type.base_type) {
+      case BASE_TYPE_BOOL: return field.value.constant == "0" ? "false" : "true";;
+      default: return field.value.constant;
+    }
+  }
+
+  // Create a struct with a builder and the struct's arguments.
+  void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
+    BeginBuilderArgs(struct_def, code_ptr);
+    StructBuilderArgs(struct_def, "", code_ptr);
+    EndBuilderArgs(code_ptr);
+
+    StructBuilderBody(struct_def, "", code_ptr);
+    EndBuilderBody(code_ptr);
+  }
+  // Begin by declaring namespace and imports.
+  void BeginFile(const std::string &name_space_name, const bool needs_imports,
+                 const bool is_enum, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code = code + "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n";
+    code += "package " + name_space_name + "\n\n";
+    if (needs_imports) {
+      code += "import (\n";
+      if (is_enum) {
+        code += "\t\"strconv\"\n\n";
+      }
+      if (!parser_.opts.go_import.empty()) {
+        code += "\tflatbuffers \"" + parser_.opts.go_import + "\"\n";
+      } else {
+        code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n";
+      }
+      if (tracked_imported_namespaces_.size() > 0) {
+        code += "\n";
+        for (auto it = tracked_imported_namespaces_.begin();
+             it != tracked_imported_namespaces_.end();
+             ++it) {
+        code += "\t" + NamespaceImportName(*it) + " \"" + \
+                NamespaceImportPath(*it) + "\"\n";
+        }
+      }
+      code += ")\n\n";
+    } else {
+      if (is_enum) {
+        code += "import \"strconv\"\n\n";
+      }
+    }
+  }
+
+  // Save out the generated code for a Go Table type.
+  bool SaveType(const Definition &def, const std::string &classcode,
+                const bool needs_imports, const bool is_enum) {
+    if (!classcode.length()) return true;
+
+    Namespace &ns = go_namespace_.components.empty() ? *def.defined_namespace
+                                                     : go_namespace_;
+    std::string code = "";
+    BeginFile(LastNamespacePart(ns), needs_imports, is_enum, &code);
+    code += classcode;
+    // Strip extra newlines at end of file to make it gofmt-clean.
+    while (code.length() > 2 && code.substr(code.length() - 2) == "\n\n") {
+      code.pop_back();
+    }
+    std::string filename = NamespaceDir(ns) + def.name + ".go";
+    return SaveFile(filename.c_str(), code, false);
+  }
+
+  // Create the full name of the imported namespace (format: A__B__C).
+  std::string NamespaceImportName(const Namespace *ns) {
+    std::string s = "";
+    for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
+      if (s.size() == 0) {
+        s += *it;
+      } else {
+        s += "__" + *it;
+      }
+    }
+    return s;
+  }
+
+  // Create the full path for the imported namespace (format: A/B/C).
+  std::string NamespaceImportPath(const Namespace *ns) {
+    std::string s = "";
+    for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
+      if (s.size() == 0) {
+        s += *it;
+      } else {
+        s += "/" + *it;
+      }
+    }
+    return s;
+  }
+
+  // Ensure that a type is prefixed with its go package import name if it is
+  // used outside of its namespace.
+  std::string WrapInNameSpaceAndTrack(const Namespace *ns,
+                                      const std::string &name) {
+    if (CurrentNameSpace() == ns) return name;
+
+    tracked_imported_namespaces_.insert(ns);
+
+    std::string import_name = NamespaceImportName(ns);
+    return import_name + "." + name;
+  }
+
+  std::string WrapInNameSpaceAndTrack(const Definition &def) {
+    return WrapInNameSpaceAndTrack(def.defined_namespace, def.name);
+  }
+
+  const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+  static size_t MaxNameLength(const EnumDef &enum_def) {
+    size_t max = 0;
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+        ++it) {
+      max = std::max((*it)->name.length(), max);
+    }
+    return max;
+  }
+};
+}  // namespace go
+
+bool GenerateGo(const Parser &parser, const std::string &path,
+                const std::string &file_name) {
+  go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace);
+  return generator.generate();
+}
+
+}  // namespace flatbuffers
diff --git a/src/idl_gen_grpc.cpp b/src/idl_gen_grpc.cpp
new file mode 100644
index 0000000..1d5e8e5
--- /dev/null
+++ b/src/idl_gen_grpc.cpp
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2014 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.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#include "src/compiler/cpp_generator.h"
+#include "src/compiler/go_generator.h"
+#include "src/compiler/java_generator.h"
+
+#if defined(_MSC_VER)
+#  pragma warning(push)
+#  pragma warning(disable : 4512)  // C4512: 'class' : assignment operator could
+// not be generated
+#endif
+
+namespace flatbuffers {
+
+class FlatBufMethod : public grpc_generator::Method {
+ public:
+  enum Streaming {
+    kNone, kClient, kServer, kBiDi
+  };
+
+  FlatBufMethod(const RPCCall *method) : method_(method) {
+    streaming_ = kNone;
+    auto val = method_->attributes.Lookup("streaming");
+    if (val) {
+      if (val->constant == "client") streaming_ = kClient;
+      if (val->constant == "server") streaming_ = kServer;
+      if (val->constant == "bidi") streaming_ = kBiDi;
+    }
+  }
+
+  grpc::string GetLeadingComments(const grpc::string) const { return ""; }
+
+  grpc::string GetTrailingComments(const grpc::string) const { return ""; }
+
+  std::vector<grpc::string> GetAllComments() const {
+    return method_->doc_comment;
+  }
+
+  std::string name() const { return method_->name; }
+
+  std::string GRPCType(const StructDef &sd) const {
+    return "flatbuffers::grpc::Message<" + sd.name + ">";
+  }
+
+  std::string get_input_type_name() const { return (*method_->request).name; }
+
+  std::string get_output_type_name() const { return (*method_->response).name; }
+
+  bool get_module_and_message_path_input(grpc::string * /*str*/,
+                                         grpc::string /*generator_file_name*/,
+                                         bool /*generate_in_pb2_grpc*/,
+                                         grpc::string /*import_prefix*/) const {
+    return true;
+  }
+
+  bool get_module_and_message_path_output(
+      grpc::string * /*str*/, grpc::string /*generator_file_name*/,
+      bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const {
+    return true;
+  }
+
+  std::string input_type_name() const { return GRPCType(*method_->request); }
+
+  std::string output_type_name() const { return GRPCType(*method_->response); }
+
+  bool NoStreaming() const { return streaming_ == kNone; }
+
+  bool ClientStreaming() const { return streaming_ == kClient; }
+
+  bool ServerStreaming() const { return streaming_ == kServer; }
+
+  bool BidiStreaming() const { return streaming_ == kBiDi; }
+
+ private:
+  const RPCCall *method_;
+  Streaming streaming_;
+};
+
+class FlatBufService : public grpc_generator::Service {
+ public:
+  FlatBufService(const ServiceDef *service) : service_(service) {}
+
+  grpc::string GetLeadingComments(const grpc::string) const { return ""; }
+
+  grpc::string GetTrailingComments(const grpc::string) const { return ""; }
+
+  std::vector<grpc::string> GetAllComments() const {
+    return service_->doc_comment;
+  }
+
+  std::string name() const { return service_->name; }
+
+  int method_count() const {
+    return static_cast<int>(service_->calls.vec.size());
+  }
+
+  std::unique_ptr<const grpc_generator::Method> method(int i) const {
+    return std::unique_ptr<const grpc_generator::Method>(
+        new FlatBufMethod(service_->calls.vec[i]));
+  }
+
+ private:
+  const ServiceDef *service_;
+};
+
+class FlatBufPrinter : public grpc_generator::Printer {
+ public:
+  FlatBufPrinter(std::string *str) : str_(str), escape_char_('$'), indent_(0) {}
+
+  void Print(const std::map<std::string, std::string> &vars,
+             const char *string_template) {
+    std::string s = string_template;
+    // Replace any occurrences of strings in "vars" that are surrounded
+    // by the escape character by what they're mapped to.
+    size_t pos;
+    while ((pos = s.find(escape_char_)) != std::string::npos) {
+      // Found an escape char, must also find the closing one.
+      size_t pos2 = s.find(escape_char_, pos + 1);
+      // If placeholder not closed, ignore.
+      if (pos2 == std::string::npos) break;
+      auto it = vars.find(s.substr(pos + 1, pos2 - pos - 1));
+      // If unknown placeholder, ignore.
+      if (it == vars.end()) break;
+      // Subtitute placeholder.
+      s.replace(pos, pos2 - pos + 1, it->second);
+    }
+    Print(s.c_str());
+  }
+
+  void Print(const char *s) {
+    if (s == nullptr || *s == '\0') { return; }
+    // Add this string, but for each part separated by \n, add indentation.
+    for (;;) {
+      // Current indentation.
+      str_->insert(str_->end(), indent_ * 2, ' ');
+      // See if this contains more than one line.
+      const char *lf = strchr(s, '\n');
+      if (lf) {
+        (*str_) += std::string(s, lf + 1);
+        s = lf + 1;
+        if (!*s) break;  // Only continue if there's more lines.
+      } else {
+        (*str_) += s;
+        break;
+      }
+    }
+  }
+
+  void Indent() { indent_++; }
+
+  void Outdent() {
+    indent_--;
+        FLATBUFFERS_ASSERT(indent_ >= 0);
+  }
+
+ private:
+  std::string *str_;
+  char escape_char_;
+  int indent_;
+};
+
+class FlatBufFile : public grpc_generator::File {
+ public:
+  enum Language {
+    kLanguageGo, kLanguageCpp, kLanguageJava
+  };
+
+  FlatBufFile(const Parser &parser, const std::string &file_name,
+              Language language)
+      : parser_(parser), file_name_(file_name), language_(language) {}
+
+  FlatBufFile &operator=(const FlatBufFile &);
+
+  grpc::string GetLeadingComments(const grpc::string) const { return ""; }
+
+  grpc::string GetTrailingComments(const grpc::string) const { return ""; }
+
+  std::vector<grpc::string> GetAllComments() const {
+    return std::vector<grpc::string>();
+  }
+
+  std::string filename() const { return file_name_; }
+
+  std::string filename_without_ext() const {
+    return StripExtension(file_name_);
+  }
+
+  std::string message_header_ext() const { return "_generated.h"; }
+
+  std::string service_header_ext() const { return ".grpc.fb.h"; }
+
+  std::string package() const {
+    return parser_.current_namespace_->GetFullyQualifiedName("");
+  }
+
+  std::vector<std::string> package_parts() const {
+    return parser_.current_namespace_->components;
+  }
+
+  std::string additional_headers() const {
+    switch (language_) {
+      case kLanguageCpp: {
+        return "#include \"flatbuffers/grpc.h\"\n";
+      }
+      case kLanguageGo: {
+        return "import \"github.com/google/flatbuffers/go\"";
+      }
+      case kLanguageJava: {
+        return "import com.google.flatbuffers.grpc.FlatbuffersUtils;";
+      }
+    }
+    return "";
+  }
+
+  int service_count() const {
+    return static_cast<int>(parser_.services_.vec.size());
+  }
+
+  std::unique_ptr<const grpc_generator::Service> service(int i) const {
+    return std::unique_ptr<const grpc_generator::Service>(
+        new FlatBufService(parser_.services_.vec[i]));
+  }
+
+  std::unique_ptr<grpc_generator::Printer> CreatePrinter(
+      std::string *str) const {
+    return std::unique_ptr<grpc_generator::Printer>(new FlatBufPrinter(str));
+  }
+
+ private:
+  const Parser &parser_;
+  const std::string &file_name_;
+  const Language language_;
+};
+
+class GoGRPCGenerator : public flatbuffers::BaseGenerator {
+ public:
+  GoGRPCGenerator(const Parser &parser, const std::string &path,
+                  const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "", "" /*Unused*/),
+        parser_(parser),
+        path_(path),
+        file_name_(file_name) {}
+
+  bool generate() {
+    FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageGo);
+    grpc_go_generator::Parameters p;
+    p.custom_method_io_type = "flatbuffers.Builder";
+    for (int i = 0; i < file.service_count(); i++) {
+      auto service = file.service(i);
+      const Definition *def = parser_.services_.vec[i];
+      p.package_name = LastNamespacePart(*(def->defined_namespace));
+      p.service_prefix = def->defined_namespace->GetFullyQualifiedName(""); // file.package();
+      std::string output =
+          grpc_go_generator::GenerateServiceSource(&file, service.get(), &p);
+      std::string filename =
+          NamespaceDir(*def->defined_namespace) + def->name + "_grpc.go";
+      if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
+    }
+    return true;
+  }
+
+ protected:
+  const Parser &parser_;
+  const std::string &path_, &file_name_;
+};
+
+bool GenerateGoGRPC(const Parser &parser, const std::string &path,
+                    const std::string &file_name) {
+  int nservices = 0;
+  for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+       ++it) {
+    if (!(*it)->generated) nservices++;
+  }
+  if (!nservices) return true;
+  return GoGRPCGenerator(parser, path, file_name).generate();
+}
+
+bool GenerateCppGRPC(const Parser &parser, const std::string &path,
+                     const std::string &file_name) {
+  int nservices = 0;
+  for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+       ++it) {
+    if (!(*it)->generated) nservices++;
+  }
+  if (!nservices) return true;
+
+  grpc_cpp_generator::Parameters generator_parameters;
+  // TODO(wvo): make the other parameters in this struct configurable.
+  generator_parameters.use_system_headers = true;
+
+  FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguageCpp);
+
+  std::string header_code =
+      grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
+          grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) +
+          grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) +
+          grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters);
+
+  std::string source_code =
+      grpc_cpp_generator::GetSourcePrologue(&fbfile, generator_parameters) +
+          grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) +
+          grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
+          grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
+
+  return flatbuffers::SaveFile((path + file_name + ".grpc.fb.h").c_str(),
+                               header_code, false) &&
+      flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(),
+                            source_code, false);
+}
+
+class JavaGRPCGenerator : public flatbuffers::BaseGenerator {
+ public:
+  JavaGRPCGenerator(const Parser &parser, const std::string &path,
+                    const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "", "." /*separator*/) {}
+
+  bool generate() {
+    FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageJava);
+    grpc_java_generator::Parameters p;
+    for (int i = 0; i < file.service_count(); i++) {
+      auto service = file.service(i);
+      const Definition *def = parser_.services_.vec[i];
+      p.package_name =
+          def->defined_namespace->GetFullyQualifiedName("");  // file.package();
+      std::string output =
+          grpc_java_generator::GenerateServiceSource(&file, service.get(), &p);
+      std::string filename =
+          NamespaceDir(*def->defined_namespace) + def->name + "Grpc.java";
+      if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
+    }
+    return true;
+  }
+};
+
+bool GenerateJavaGRPC(const Parser &parser, const std::string &path,
+                      const std::string &file_name) {
+  int nservices = 0;
+  for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+       ++it) {
+    if (!(*it)->generated) nservices++;
+  }
+  if (!nservices) return true;
+  return JavaGRPCGenerator(parser, path, file_name).generate();
+}
+
+}  // namespace flatbuffers
+
+#if defined(_MSC_VER)
+#  pragma warning(pop)
+#endif
diff --git a/src/idl_gen_js_ts.cpp b/src/idl_gen_js_ts.cpp
new file mode 100644
index 0000000..9c89c1a
--- /dev/null
+++ b/src/idl_gen_js_ts.cpp
@@ -0,0 +1,1405 @@
+/*
+ * Copyright 2014 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.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+#include <cassert>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+const std::string kGeneratedFileNamePostfix = "_generated";
+
+struct JsTsLanguageParameters {
+  IDLOptions::Language language;
+  std::string file_extension;
+};
+
+struct ReexportDescription {
+  std::string symbol;
+  std::string source_namespace;
+  std::string target_namespace;
+};
+
+enum AnnotationType { kParam = 0, kType = 1, kReturns = 2 };
+
+const JsTsLanguageParameters &GetJsLangParams(IDLOptions::Language lang) {
+  static JsTsLanguageParameters js_language_parameters[] = {
+    {
+        IDLOptions::kJs,
+        ".js",
+    },
+    {
+        IDLOptions::kTs,
+        ".ts",
+    },
+  };
+
+  if (lang == IDLOptions::kJs) {
+    return js_language_parameters[0];
+  } else {
+    FLATBUFFERS_ASSERT(lang == IDLOptions::kTs);
+    return js_language_parameters[1];
+  }
+}
+
+static std::string GeneratedFileName(const std::string &path,
+                                     const std::string &file_name,
+                                     const JsTsLanguageParameters &lang) {
+  return path + file_name + kGeneratedFileNamePostfix + lang.file_extension;
+}
+
+namespace jsts {
+// Iterate through all definitions we haven't generate code for (enums, structs,
+// and tables) and output them to a single file.
+class JsTsGenerator : public BaseGenerator {
+ public:
+  typedef std::unordered_set<std::string> imported_fileset;
+  typedef std::unordered_multimap<std::string, ReexportDescription>
+      reexport_map;
+
+  JsTsGenerator(const Parser &parser, const std::string &path,
+                const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "", "."),
+        lang_(GetJsLangParams(parser_.opts.lang)) {}
+  // Iterate through all definitions we haven't generate code for (enums,
+  // structs, and tables) and output them to a single file.
+  bool generate() {
+    imported_fileset imported_files;
+    reexport_map reexports;
+
+    std::string enum_code, struct_code, import_code, exports_code, code;
+    generateEnums(&enum_code, &exports_code, reexports);
+    generateStructs(&struct_code, &exports_code, imported_files);
+    generateImportDependencies(&import_code, imported_files);
+    generateReexports(&import_code, reexports, imported_files);
+
+    code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
+
+    // Generate code for all the namespace declarations.
+    GenNamespaces(&code, &exports_code);
+
+    // Output the main declaration code from above.
+    code += import_code;
+
+    code += enum_code;
+    code += struct_code;
+
+    if (lang_.language == IDLOptions::kJs && !exports_code.empty() &&
+        !parser_.opts.skip_js_exports) {
+      if (parser_.opts.use_ES6_js_export_format)
+        code += "// Exports for ECMAScript6 Modules\n";
+      else
+        code += "// Exports for Node.js and RequireJS\n";
+      code += exports_code;
+    }
+
+    return SaveFile(GeneratedFileName(path_, file_name_, lang_).c_str(), code,
+                    false);
+  }
+
+ private:
+  JsTsLanguageParameters lang_;
+
+  // Generate code for imports
+  void generateImportDependencies(std::string *code_ptr,
+                                  const imported_fileset &imported_files) {
+    std::string &code = *code_ptr;
+    for (auto it = imported_files.begin(); it != imported_files.end(); ++it) {
+      const auto &file = *it;
+      const auto basename =
+          flatbuffers::StripPath(flatbuffers::StripExtension(file));
+      if (basename != file_name_) {
+        code += GenPrefixedImport(file, basename);
+      }
+    }
+  }
+
+  // Generate reexports, which might not have been explicitly imported using the
+  // "export import" trick
+  void generateReexports(std::string *code_ptr, const reexport_map &reexports,
+                         imported_fileset imported_files) {
+    if (!parser_.opts.reexport_ts_modules ||
+        lang_.language != IDLOptions::kTs) {
+      return;
+    }
+
+    std::string &code = *code_ptr;
+    for (auto it = reexports.begin(); it != reexports.end(); ++it) {
+      const auto &file = *it;
+      const auto basename =
+          flatbuffers::StripPath(flatbuffers::StripExtension(file.first));
+      if (basename != file_name_) {
+        if (imported_files.find(file.first) == imported_files.end()) {
+          code += GenPrefixedImport(file.first, basename);
+          imported_files.emplace(file.first);
+        }
+
+        code += "export namespace " + file.second.target_namespace + " { \n";
+        code += "export import " + file.second.symbol + " = ";
+        code += GenFileNamespacePrefix(file.first) + "." +
+                file.second.source_namespace + "." + file.second.symbol +
+                "; }\n";
+      }
+    }
+  }
+
+  // Generate code for all enums.
+  void generateEnums(std::string *enum_code_ptr, std::string *exports_code_ptr,
+                     reexport_map &reexports) {
+    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+         ++it) {
+      auto &enum_def = **it;
+      GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports, false);
+      GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports, true);
+    }
+  }
+
+  // Generate code for all structs.
+  void generateStructs(std::string *decl_code_ptr,
+                       std::string *exports_code_ptr,
+                       imported_fileset &imported_files) {
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      auto &struct_def = **it;
+      GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr,
+                imported_files);
+    }
+  }
+  void GenNamespaces(std::string *code_ptr, std::string *exports_ptr) {
+    if (lang_.language == IDLOptions::kTs &&
+        parser_.opts.skip_flatbuffers_import) {
+      return;
+    }
+
+    std::set<std::string> namespaces;
+
+    for (auto it = parser_.namespaces_.begin(); it != parser_.namespaces_.end();
+         ++it) {
+      std::string namespace_so_far;
+
+      // Gather all parent namespaces for this namespace
+      for (auto component = (*it)->components.begin();
+           component != (*it)->components.end(); ++component) {
+        if (!namespace_so_far.empty()) { namespace_so_far += '.'; }
+        namespace_so_far += *component;
+        namespaces.insert(namespace_so_far);
+      }
+    }
+
+    // Make sure parent namespaces come before child namespaces
+    std::vector<std::string> sorted_namespaces(namespaces.begin(),
+                                               namespaces.end());
+    std::sort(sorted_namespaces.begin(), sorted_namespaces.end());
+
+    // Emit namespaces in a form that Closure Compiler can optimize
+    std::string &code = *code_ptr;
+    std::string &exports = *exports_ptr;
+    for (auto it = sorted_namespaces.begin(); it != sorted_namespaces.end();
+         ++it) {
+      if (lang_.language == IDLOptions::kTs) {
+        if (it->find('.') == std::string::npos) {
+          code += "import { flatbuffers } from \"./flatbuffers\"\n";
+          break;
+        }
+      } else {
+        code += "/**\n * @const\n * @namespace\n */\n";
+        if (it->find('.') == std::string::npos) {
+          code += "var ";
+          if (parser_.opts.use_goog_js_export_format) {
+            exports += "goog.exportSymbol('" + *it + "', " + *it + ");\n";
+          } else if (parser_.opts.use_ES6_js_export_format) {
+            exports += "export {" + *it + "};\n";
+          } else {
+            exports += "this." + *it + " = " + *it + ";\n";
+          }
+        }
+        code += *it + " = " + *it + " || {};\n\n";
+      }
+    }
+  }
+
+  // Generate a documentation comment, if available.
+  static void GenDocComment(const std::vector<std::string> &dc,
+                            std::string *code_ptr,
+                            const std::string &extra_lines,
+                            const char *indent = nullptr) {
+    if (dc.empty() && extra_lines.empty()) {
+      // Don't output empty comment blocks with 0 lines of comment content.
+      return;
+    }
+
+    std::string &code = *code_ptr;
+    if (indent) code += indent;
+    code += "/**\n";
+    for (auto it = dc.begin(); it != dc.end(); ++it) {
+      if (indent) code += indent;
+      code += " *" + *it + "\n";
+    }
+    if (!extra_lines.empty()) {
+      if (!dc.empty()) {
+        if (indent) code += indent;
+        code += " *\n";
+      }
+      if (indent) code += indent;
+      std::string::size_type start = 0;
+      for (;;) {
+        auto end = extra_lines.find('\n', start);
+        if (end != std::string::npos) {
+          code += " * " + extra_lines.substr(start, end - start) + "\n";
+          start = end + 1;
+        } else {
+          code += " * " + extra_lines.substr(start) + "\n";
+          break;
+        }
+      }
+    }
+    if (indent) code += indent;
+    code += " */\n";
+  }
+
+  static void GenDocComment(std::string *code_ptr,
+                            const std::string &extra_lines) {
+    GenDocComment(std::vector<std::string>(), code_ptr, extra_lines);
+  }
+
+  std::string GenTypeAnnotation(AnnotationType annotation_type,
+                                const std::string &type_name,
+                                const std::string &arg_name,
+                                bool include_newline = true) {
+    std::string result = "";
+    switch (annotation_type) {
+      case kParam: {
+        result += "@param";
+        break;
+      }
+      case kType: {
+        if (lang_.language != IDLOptions::kTs) {
+          result += "@type";
+        } else {
+          return "";
+        }
+        break;
+      }
+      case kReturns: {
+        result += "@returns";
+        break;
+      }
+    }
+    switch (lang_.language) {
+      case IDLOptions::kTs: {
+        result += " " + type_name;
+        break;
+      }
+      default: { result += " {" + type_name + "}"; }
+    }
+    if (!arg_name.empty()) {
+      result += " " + arg_name;
+    }
+    if (include_newline) {
+      result += "\n";
+    }
+
+    return result;
+  }
+
+  // Generate an enum declaration and an enum string lookup table.
+  void GenEnum(EnumDef &enum_def, std::string *code_ptr,
+               std::string *exports_ptr, reexport_map &reexports,
+               bool reverse) {
+    if (enum_def.generated) return;
+    if (reverse && lang_.language == IDLOptions::kTs) return;  // FIXME.
+    std::string &code = *code_ptr;
+    std::string &exports = *exports_ptr;
+    GenDocComment(enum_def.doc_comment, code_ptr,
+                  reverse ? "@enum {string}" : "@enum {number}");
+    std::string ns = GetNameSpace(enum_def);
+    std::string enum_def_name = enum_def.name + (reverse ? "Name" : "");
+    if (lang_.language == IDLOptions::kTs) {
+      if (!ns.empty()) { code += "export namespace " + ns + "{\n"; }
+      code += "export enum " + enum_def.name + "{\n";
+    } else {
+      if (enum_def.defined_namespace->components.empty()) {
+        code += "var ";
+        if (parser_.opts.use_goog_js_export_format) {
+          exports += "goog.exportSymbol('" + enum_def_name + "', " +
+                     enum_def.name + ");\n";
+        } else if (parser_.opts.use_ES6_js_export_format) {
+          exports += "export {" + enum_def_name + "};\n";
+        } else {
+          exports += "this." + enum_def_name + " = " + enum_def_name + ";\n";
+        }
+      }
+      code += WrapInNameSpace(enum_def) + (reverse ? "Name" : "") + " = {\n";
+    }
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      auto &ev = **it;
+      if (!ev.doc_comment.empty()) {
+        if (it != enum_def.Vals().begin()) { code += '\n'; }
+        GenDocComment(ev.doc_comment, code_ptr, "", "  ");
+      }
+
+      // Generate mapping between EnumName: EnumValue(int)
+      if (reverse) {
+        code += "  " + enum_def.ToString(ev);
+        code += lang_.language == IDLOptions::kTs ? "= " : ": ";
+        code += "'" + ev.name + "'";
+      } else {
+        code += "  " + ev.name;
+        code += lang_.language == IDLOptions::kTs ? "= " : ": ";
+        code += enum_def.ToString(ev);
+      }
+
+      code += (it + 1) != enum_def.Vals().end() ? ",\n" : "\n";
+
+      if (ev.union_type.struct_def) {
+        ReexportDescription desc = { ev.name,
+                                     GetNameSpace(*ev.union_type.struct_def),
+                                     GetNameSpace(enum_def) };
+        reexports.insert(
+            std::make_pair(ev.union_type.struct_def->file, std::move(desc)));
+      }
+    }
+
+    if (lang_.language == IDLOptions::kTs && !ns.empty()) { code += "}"; }
+    code += "};\n\n";
+  }
+
+  static std::string GenType(const Type &type) {
+    switch (type.base_type) {
+      case BASE_TYPE_BOOL:
+      case BASE_TYPE_CHAR: return "Int8";
+      case BASE_TYPE_UTYPE:
+      case BASE_TYPE_UCHAR: return "Uint8";
+      case BASE_TYPE_SHORT: return "Int16";
+      case BASE_TYPE_USHORT: return "Uint16";
+      case BASE_TYPE_INT: return "Int32";
+      case BASE_TYPE_UINT: return "Uint32";
+      case BASE_TYPE_LONG: return "Int64";
+      case BASE_TYPE_ULONG: return "Uint64";
+      case BASE_TYPE_FLOAT: return "Float32";
+      case BASE_TYPE_DOUBLE: return "Float64";
+      case BASE_TYPE_STRING: return "String";
+      case BASE_TYPE_VECTOR: return GenType(type.VectorType());
+      case BASE_TYPE_STRUCT: return type.struct_def->name;
+      default: return "Table";
+    }
+  }
+
+  std::string GenGetter(const Type &type, const std::string &arguments) {
+    switch (type.base_type) {
+      case BASE_TYPE_STRING: return GenBBAccess() + ".__string" + arguments;
+      case BASE_TYPE_STRUCT: return GenBBAccess() + ".__struct" + arguments;
+      case BASE_TYPE_UNION: return GenBBAccess() + ".__union" + arguments;
+      case BASE_TYPE_VECTOR: return GenGetter(type.VectorType(), arguments);
+      default: {
+        auto getter =
+            GenBBAccess() + ".read" + MakeCamel(GenType(type)) + arguments;
+        if (type.base_type == BASE_TYPE_BOOL) { getter = "!!" + getter; }
+        if (type.enum_def) {
+          getter = "/** " +
+                   GenTypeAnnotation(kType, WrapInNameSpace(*type.enum_def), "",
+                                     false) +
+                   " */ (" + getter + ")";
+        }
+        return getter;
+      }
+    }
+  }
+
+  std::string GenBBAccess() {
+    return lang_.language == IDLOptions::kTs ? "this.bb!" : "this.bb";
+  }
+
+  std::string GenDefaultValue(const Value &value, const std::string &context) {
+    if (value.type.enum_def) {
+      if (auto val = value.type.enum_def->FindByValue(value.constant)) {
+        if (lang_.language == IDLOptions::kTs) {
+          return GenPrefixedTypeName(WrapInNameSpace(*value.type.enum_def),
+                                     value.type.enum_def->file) +
+                 "." + val->name;
+        } else {
+          return WrapInNameSpace(*value.type.enum_def) + "." + val->name;
+        }
+      } else {
+        return "/** " +
+               GenTypeAnnotation(kType, WrapInNameSpace(*value.type.enum_def),
+                                 "", false) +
+               "} */ (" + value.constant + ")";
+      }
+    }
+
+    switch (value.type.base_type) {
+      case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
+
+      case BASE_TYPE_STRING: return "null";
+
+      case BASE_TYPE_LONG:
+      case BASE_TYPE_ULONG: {
+        int64_t constant = StringToInt(value.constant.c_str());
+        return context + ".createLong(" +
+               NumToString(static_cast<int32_t>(constant)) + ", " +
+               NumToString(static_cast<int32_t>(constant >> 32)) + ")";
+      }
+
+      default: return value.constant;
+    }
+  }
+
+  std::string GenTypeName(const Type &type, bool input,
+                          bool allowNull = false) {
+    if (!input) {
+      if (type.base_type == BASE_TYPE_STRING ||
+          type.base_type == BASE_TYPE_STRUCT) {
+        std::string name;
+        if (type.base_type == BASE_TYPE_STRING) {
+          name = "string|Uint8Array";
+        } else {
+          name = WrapInNameSpace(*type.struct_def);
+        }
+        return (allowNull) ? (name + "|null") : (name);
+      }
+    }
+
+    switch (type.base_type) {
+      case BASE_TYPE_BOOL: return "boolean";
+      case BASE_TYPE_LONG:
+      case BASE_TYPE_ULONG: return "flatbuffers.Long";
+      default:
+        if (IsScalar(type.base_type)) {
+          if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
+          return "number";
+        }
+        return "flatbuffers.Offset";
+    }
+  }
+
+  // Returns the method name for use with add/put calls.
+  static std::string GenWriteMethod(const Type &type) {
+    // Forward to signed versions since unsigned versions don't exist
+    switch (type.base_type) {
+      case BASE_TYPE_UTYPE:
+      case BASE_TYPE_UCHAR: return GenWriteMethod(Type(BASE_TYPE_CHAR));
+      case BASE_TYPE_USHORT: return GenWriteMethod(Type(BASE_TYPE_SHORT));
+      case BASE_TYPE_UINT: return GenWriteMethod(Type(BASE_TYPE_INT));
+      case BASE_TYPE_ULONG: return GenWriteMethod(Type(BASE_TYPE_LONG));
+      default: break;
+    }
+
+    return IsScalar(type.base_type) ? MakeCamel(GenType(type))
+                                    : (IsStruct(type) ? "Struct" : "Offset");
+  }
+
+  template<typename T> static std::string MaybeAdd(T value) {
+    return value != 0 ? " + " + NumToString(value) : "";
+  }
+
+  template<typename T> static std::string MaybeScale(T value) {
+    return value != 1 ? " * " + NumToString(value) : "";
+  }
+
+  static std::string GenFileNamespacePrefix(const std::string &file) {
+    return "NS" + std::to_string(HashFnv1a<uint64_t>(file.c_str()));
+  }
+
+  std::string GenPrefixedImport(const std::string &full_file_name,
+                                const std::string &base_name) {
+    // Either keep the include path as it was
+    // or use only the base_name + kGeneratedFileNamePostfix
+    std::string path;
+    if (parser_.opts.keep_include_path) {
+      auto it = parser_.included_files_.find(full_file_name);
+      FLATBUFFERS_ASSERT(it != parser_.included_files_.end());
+      path =
+          flatbuffers::StripExtension(it->second) + kGeneratedFileNamePostfix;
+    } else {
+      path = base_name + kGeneratedFileNamePostfix;
+    }
+
+    // Add the include prefix and make the path always relative
+    path = flatbuffers::ConCatPathFileName(parser_.opts.include_prefix, path);
+    path = std::string(".") + kPathSeparator + path;
+
+    return "import * as " + GenFileNamespacePrefix(full_file_name) +
+           " from \"" + path + "\";\n";
+  }
+
+  // Adds a source-dependent prefix, for of import * statements.
+  std::string GenPrefixedTypeName(const std::string &typeName,
+                                  const std::string &file) {
+    const auto basename =
+        flatbuffers::StripPath(flatbuffers::StripExtension(file));
+    if (basename == file_name_ || parser_.opts.generate_all) {
+      return typeName;
+    }
+    return GenFileNamespacePrefix(file) + "." + typeName;
+  }
+
+  void GenStructArgs(const StructDef &struct_def, std::string *annotations,
+                     std::string *arguments, const std::string &nameprefix) {
+    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.
+        GenStructArgs(*field.value.type.struct_def, annotations, arguments,
+                      nameprefix + field.name + "_");
+      } else {
+        *annotations +=
+            GenTypeAnnotation(kParam, GenTypeName(field.value.type, true),
+                              nameprefix + field.name);
+        if (lang_.language == IDLOptions::kTs) {
+          *arguments += ", " + nameprefix + field.name + ": " +
+                        GenTypeName(field.value.type, true);
+        } else {
+          *arguments += ", " + nameprefix + field.name;
+        }
+      }
+    }
+  }
+
+  static void GenStructBody(const StructDef &struct_def, std::string *body,
+                            const std::string &nameprefix) {
+    *body += "  builder.prep(";
+    *body += NumToString(struct_def.minalign) + ", ";
+    *body += 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) {
+        *body += "  builder.pad(" + NumToString(field.padding) + ");\n";
+      }
+      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.
+        GenStructBody(*field.value.type.struct_def, body,
+                      nameprefix + field.name + "_");
+      } else {
+        *body += "  builder.write" + GenWriteMethod(field.value.type) + "(";
+        if (field.value.type.base_type == BASE_TYPE_BOOL) { *body += "+"; }
+        *body += nameprefix + field.name + ");\n";
+      }
+    }
+  }
+
+  void GenerateRootAccessor(StructDef &struct_def, std::string *code_ptr,
+                 std::string &code, std::string &object_name, bool size_prefixed) {
+    if (!struct_def.fixed) {
+      GenDocComment(code_ptr,
+                    GenTypeAnnotation(kParam, "flatbuffers.ByteBuffer", "bb") +
+                        GenTypeAnnotation(kParam, object_name + "=", "obj") +
+                        GenTypeAnnotation(kReturns, object_name, "", false));
+      std::string sizePrefixed("SizePrefixed");
+      if (lang_.language == IDLOptions::kTs) {
+        code += "static get" + (size_prefixed ? sizePrefixed : "") + "Root" + Verbose(struct_def, "As");
+        code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name +
+                "):" + object_name + " {\n";
+      } else {
+        code += object_name + ".get" + (size_prefixed ? sizePrefixed : "") + "Root" + Verbose(struct_def, "As");
+        code += " = function(bb, obj) {\n";
+      }
+      code += "  return (obj || new " + object_name;
+      code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n";
+      code += "};\n\n";
+    }
+  }
+
+  void GenerateFinisher(StructDef &struct_def, std::string *code_ptr,
+                 std::string &code, std::string &object_name, bool size_prefixed) {
+    if (parser_.root_struct_def_ == &struct_def) {
+      std::string sizePrefixed("SizePrefixed");
+      GenDocComment(
+          code_ptr,
+          GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
+              GenTypeAnnotation(kParam, "flatbuffers.Offset", "offset",
+                                false));
+
+      if (lang_.language == IDLOptions::kTs) {
+        code += "static finish" + (size_prefixed ? sizePrefixed : "") + Verbose(struct_def) + "Buffer";
+        code +=
+            "(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n";
+      } else {
+        code += object_name + ".finish" + (size_prefixed ? sizePrefixed : "") + Verbose(struct_def) + "Buffer";
+        code += " = function(builder, offset) {\n";
+      }
+
+      code += "  builder.finish(offset";
+      if (!parser_.file_identifier_.empty()) {
+        code += ", '" + parser_.file_identifier_ + "'";
+      }
+      if (size_prefixed) {
+        if (parser_.file_identifier_.empty()) {
+          code += ", undefined";
+        }
+        code += ", true";
+      }
+      code += ");\n";
+      code += "};\n\n";
+    }
+  }
+
+  // Generate an accessor struct with constructor for a flatbuffers struct.
+  void GenStruct(const Parser &parser, StructDef &struct_def,
+                 std::string *code_ptr, std::string *exports_ptr,
+                 imported_fileset &imported_files) {
+    if (struct_def.generated) return;
+    std::string &code = *code_ptr;
+    std::string &exports = *exports_ptr;
+
+    std::string object_name;
+    std::string object_namespace = GetNameSpace(struct_def);
+
+    // Emit constructor
+    if (lang_.language == IDLOptions::kTs) {
+      object_name = struct_def.name;
+      GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
+      if (!object_namespace.empty()) {
+        code += "export namespace " + object_namespace + "{\n";
+      }
+      code += "export class " + struct_def.name;
+      code += " {\n";
+      if (lang_.language != IDLOptions::kTs) {
+        code += "  /**\n";
+        code += "   * " + GenTypeAnnotation(kType, "flatbuffers.ByteBuffer", "");
+        code += "   */\n";
+      }
+      code += "  bb: flatbuffers.ByteBuffer|null = null;\n";
+      code += "\n";
+      if (lang_.language != IDLOptions::kTs) {
+        code += "  /**\n";
+        code += "   * " + GenTypeAnnotation(kType, "number", "");
+        code += "   */\n";
+      }
+      code += "  bb_pos:number = 0;\n";
+    } else {
+      bool isStatement = struct_def.defined_namespace->components.empty();
+      object_name = WrapInNameSpace(struct_def);
+      GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
+      if (isStatement) {
+        if (parser_.opts.use_goog_js_export_format) {
+          exports += "goog.exportSymbol('" + struct_def.name + "', " +
+                     struct_def.name + ");\n";
+        } else if (parser_.opts.use_ES6_js_export_format) {
+          exports += "export {" + struct_def.name + "};\n";
+        } else {
+          exports +=
+              "this." + struct_def.name + " = " + struct_def.name + ";\n";
+        }
+        code += "function " + object_name;
+      } else {
+        code += object_name + " = function";
+      }
+      code += "() {\n";
+      code += "  /**\n";
+      code += "   * " + GenTypeAnnotation(kType, "flatbuffers.ByteBuffer", "");
+      code += "   */\n";
+      code += "  this.bb = null;\n";
+      code += "\n";
+      code += "  /**\n";
+      code += "   * " + GenTypeAnnotation(kType, "number", "");
+      code += "   */\n";
+      code += "  this.bb_pos = 0;\n";
+      code += isStatement ? "}\n\n" : "};\n\n";
+    }
+
+    // Generate the __init method that sets the field in a pre-existing
+    // accessor object. This is to allow object reuse.
+    code += "/**\n";
+    code += " * " + GenTypeAnnotation(kParam, "number", "i");
+    code += " * " + GenTypeAnnotation(kParam, "flatbuffers.ByteBuffer", "bb");
+    code += " * " + GenTypeAnnotation(kReturns, object_name, "");
+    code += " */\n";
+
+    if (lang_.language == IDLOptions::kTs) {
+      code +=
+          "__init(i:number, bb:flatbuffers.ByteBuffer):" + object_name + " {\n";
+    } else {
+      code += object_name + ".prototype.__init = function(i, bb) {\n";
+    }
+
+    code += "  this.bb_pos = i;\n";
+    code += "  this.bb = bb;\n";
+    code += "  return this;\n";
+    code += "};\n\n";
+
+    // Generate special accessors for the table that when used as the root of a
+    // FlatBuffer
+    GenerateRootAccessor(struct_def, code_ptr, code, object_name, false);
+    GenerateRootAccessor(struct_def, code_ptr, code, object_name, true);
+
+    // Generate the identifier check method
+    if (!struct_def.fixed && parser_.root_struct_def_ == &struct_def &&
+        !parser_.file_identifier_.empty()) {
+      GenDocComment(
+          code_ptr,
+          GenTypeAnnotation(kParam, "flatbuffers.ByteBuffer", "bb") +
+              GenTypeAnnotation(kReturns, "boolean", "", false));
+      if (lang_.language == IDLOptions::kTs) {
+        code +=
+            "static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean "
+            "{\n";
+      } else {
+        code += object_name + ".bufferHasIdentifier = function(bb) {\n";
+      }
+
+      code += "  return bb.__has_identifier('" + parser_.file_identifier_;
+      code += "');\n};\n\n";
+    }
+
+    // Emit field accessors
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (field.deprecated) continue;
+      auto offset_prefix =
+          "  var offset = " + GenBBAccess() + ".__offset(this.bb_pos, " +
+          NumToString(field.value.offset) + ");\n  return offset ? ";
+
+      // Emit a scalar field
+      if (IsScalar(field.value.type.base_type) ||
+          field.value.type.base_type == BASE_TYPE_STRING) {
+        GenDocComment(
+            field.doc_comment, code_ptr,
+            std::string(field.value.type.base_type == BASE_TYPE_STRING
+                            ? GenTypeAnnotation(kParam, "flatbuffers.Encoding=",
+                                                "optionalEncoding")
+                            : "") +
+                GenTypeAnnotation(kReturns,
+                                  GenTypeName(field.value.type, false, true),
+                                  "", false));
+        if (lang_.language == IDLOptions::kTs) {
+          std::string prefix = MakeCamel(field.name, false) + "(";
+          if (field.value.type.base_type == BASE_TYPE_STRING) {
+            code += prefix + "):string|null\n";
+            code += prefix + "optionalEncoding:flatbuffers.Encoding" +
+                    "):" + GenTypeName(field.value.type, false, true) + "\n";
+            code += prefix + "optionalEncoding?:any";
+          } else {
+            code += prefix;
+          }
+          if (field.value.type.enum_def) {
+            code +=
+                "):" +
+                GenPrefixedTypeName(GenTypeName(field.value.type, false, true),
+                                    field.value.type.enum_def->file) +
+                " {\n";
+
+            if (!parser_.opts.generate_all) {
+              imported_files.insert(field.value.type.enum_def->file);
+            }
+          } else {
+            code += "):" + GenTypeName(field.value.type, false, true) + " {\n";
+          }
+        } else {
+          code += object_name + ".prototype." + MakeCamel(field.name, false);
+          code += " = function(";
+          if (field.value.type.base_type == BASE_TYPE_STRING) {
+            code += "optionalEncoding";
+          }
+          code += ") {\n";
+        }
+
+        if (struct_def.fixed) {
+          code +=
+              "  return " +
+              GenGetter(field.value.type,
+                        "(this.bb_pos" + MaybeAdd(field.value.offset) + ")") +
+              ";\n";
+        } else {
+          std::string index = "this.bb_pos + offset";
+          if (field.value.type.base_type == BASE_TYPE_STRING) {
+            index += ", optionalEncoding";
+          }
+          code += offset_prefix +
+                  GenGetter(field.value.type, "(" + index + ")") + " : " +
+                  GenDefaultValue(field.value, GenBBAccess());
+          code += ";\n";
+        }
+      }
+
+      // Emit an object field
+      else {
+        switch (field.value.type.base_type) {
+          case BASE_TYPE_STRUCT: {
+            auto type = WrapInNameSpace(*field.value.type.struct_def);
+            GenDocComment(
+                field.doc_comment, code_ptr,
+                GenTypeAnnotation(kParam, type + "=", "obj") +
+                    GenTypeAnnotation(kReturns, type + "|null", "", false));
+            if (lang_.language == IDLOptions::kTs) {
+              type =
+                  GenPrefixedTypeName(type, field.value.type.struct_def->file);
+              code += MakeCamel(field.name, false);
+              code += "(obj?:" + type + "):" + type + "|null {\n";
+            } else {
+              code +=
+                  object_name + ".prototype." + MakeCamel(field.name, false);
+              code += " = function(obj) {\n";
+            }
+
+            if (struct_def.fixed) {
+              code += "  return (obj || new " + type;
+              code += ").__init(this.bb_pos";
+              code +=
+                  MaybeAdd(field.value.offset) + ", " + GenBBAccess() + ");\n";
+            } else {
+              code += offset_prefix + "(obj || new " + type + ").__init(";
+              code += field.value.type.struct_def->fixed
+                          ? "this.bb_pos + offset"
+                          : GenBBAccess() + ".__indirect(this.bb_pos + offset)";
+              code += ", " + GenBBAccess() + ") : null;\n";
+            }
+
+            if (lang_.language == IDLOptions::kTs && !parser_.opts.generate_all) {
+              imported_files.insert(field.value.type.struct_def->file);
+            }
+
+            break;
+          }
+
+          case BASE_TYPE_VECTOR: {
+            auto vectortype = field.value.type.VectorType();
+            auto vectortypename = GenTypeName(vectortype, false);
+            auto inline_size = InlineSize(vectortype);
+            auto index = GenBBAccess() +
+                         ".__vector(this.bb_pos + offset) + index" +
+                         MaybeScale(inline_size);
+            std::string args = GenTypeAnnotation(kParam, "number", "index");
+            std::string ret_type;
+            bool is_union = false;
+            switch (vectortype.base_type) {
+              case BASE_TYPE_STRUCT:
+                args += GenTypeAnnotation(kParam, vectortypename + "=", "obj");
+                ret_type = vectortypename;
+                break;
+              case BASE_TYPE_STRING:
+                args += GenTypeAnnotation(
+                    kParam, "flatbuffers.Encoding=", "optionalEncoding");
+                ret_type = vectortypename;
+                break;
+              case BASE_TYPE_UNION:
+                args += GenTypeAnnotation(kParam, "flatbuffers.Table=", "obj");
+                ret_type = "?flatbuffers.Table";
+                is_union = true;
+                break;
+              default: ret_type = vectortypename;
+            }
+            GenDocComment(
+                field.doc_comment, code_ptr,
+                args + GenTypeAnnotation(kReturns, ret_type, "", false));
+            if (lang_.language == IDLOptions::kTs) {
+              std::string prefix = MakeCamel(field.name, false);
+              if (is_union) { prefix += "<T extends flatbuffers.Table>"; }
+              prefix += "(index: number";
+              if (is_union) {
+                vectortypename = "T";
+                code += prefix + ", obj:T";
+              } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
+                vectortypename = GenPrefixedTypeName(
+                    vectortypename, vectortype.struct_def->file);
+                code += prefix + ", obj?:" + vectortypename;
+
+                if (!parser_.opts.generate_all) {
+                  imported_files.insert(vectortype.struct_def->file);
+                }
+              } else if (vectortype.base_type == BASE_TYPE_STRING) {
+                code += prefix + "):string\n";
+                code += prefix + ",optionalEncoding:flatbuffers.Encoding" +
+                        "):" + vectortypename + "\n";
+                code += prefix + ",optionalEncoding?:any";
+              } else {
+                code += prefix;
+              }
+              code += "):" + vectortypename + "|null {\n";
+            } else {
+              code +=
+                  object_name + ".prototype." + MakeCamel(field.name, false);
+              code += " = function(index";
+              if (vectortype.base_type == BASE_TYPE_STRUCT || is_union) {
+                code += ", obj";
+              } else if (vectortype.base_type == BASE_TYPE_STRING) {
+                code += ", optionalEncoding";
+              }
+              code += ") {\n";
+            }
+
+            if (vectortype.base_type == BASE_TYPE_STRUCT) {
+              code += offset_prefix + "(obj || new " + vectortypename;
+              code += ").__init(";
+              code += vectortype.struct_def->fixed
+                          ? index
+                          : GenBBAccess() + ".__indirect(" + index + ")";
+              code += ", " + GenBBAccess() + ")";
+            } else {
+              if (is_union) {
+                index = "obj, " + index;
+              } else if (vectortype.base_type == BASE_TYPE_STRING) {
+                index += ", optionalEncoding";
+              }
+              code += offset_prefix + GenGetter(vectortype, "(" + index + ")");
+            }
+            code += " : ";
+            if (field.value.type.element == BASE_TYPE_BOOL) {
+              code += "false";
+            } else if (field.value.type.element == BASE_TYPE_LONG ||
+                       field.value.type.element == BASE_TYPE_ULONG) {
+              code += GenBBAccess() + ".createLong(0, 0)";
+            } else if (IsScalar(field.value.type.element)) {
+              if (field.value.type.enum_def) {
+                code += "/** " +
+                        GenTypeAnnotation(
+                            kType, WrapInNameSpace(*field.value.type.enum_def),
+                            "", false) +
+                        " */ (" + field.value.constant + ")";
+              } else {
+                code += "0";
+              }
+            } else {
+              code += "null";
+            }
+            code += ";\n";
+            break;
+          }
+
+          case BASE_TYPE_UNION:
+            GenDocComment(
+                field.doc_comment, code_ptr,
+                GenTypeAnnotation(kParam, "flatbuffers.Table", "obj") +
+                    GenTypeAnnotation(kReturns, "?flatbuffers.Table", "",
+                                      false));
+            if (lang_.language == IDLOptions::kTs) {
+              code += MakeCamel(field.name, false);
+              code += "<T extends flatbuffers.Table>(obj:T):T|null {\n";
+            } else {
+              code +=
+                  object_name + ".prototype." + MakeCamel(field.name, false);
+              code += " = function(obj) {\n";
+            }
+
+            code += offset_prefix +
+                    GenGetter(field.value.type, "(obj, this.bb_pos + offset)") +
+                    " : null;\n";
+            break;
+
+          default: FLATBUFFERS_ASSERT(0);
+        }
+      }
+      code += "};\n\n";
+
+      if (parser_.opts.use_goog_js_export_format) {
+        exports += "goog.exportProperty(" + object_name + ".prototype, '" +
+                   MakeCamel(field.name, false) + "', " + object_name +
+                   ".prototype." + MakeCamel(field.name, false) + ");\n";
+      }
+
+      // Adds the mutable scalar value to the output
+      if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer) {
+        std::string annotations = GenTypeAnnotation(
+            kParam, GenTypeName(field.value.type, true), "value");
+        GenDocComment(
+            code_ptr,
+            annotations + GenTypeAnnotation(kReturns, "boolean", "", false));
+
+        if (lang_.language == IDLOptions::kTs) {
+          std::string type;
+          if (field.value.type.enum_def) {
+            type = GenPrefixedTypeName(GenTypeName(field.value.type, true),
+                                       field.value.type.enum_def->file);
+          } else {
+            type = GenTypeName(field.value.type, true);
+          }
+
+          code += "mutate_" + field.name + "(value:" + type + "):boolean {\n";
+        } else {
+          code += object_name + ".prototype.mutate_" + field.name +
+                  " = function(value) {\n";
+        }
+
+        code += "  var offset = " + GenBBAccess() + ".__offset(this.bb_pos, " +
+                NumToString(field.value.offset) + ");\n\n";
+        code += "  if (offset === 0) {\n";
+        code += "    return false;\n";
+        code += "  }\n\n";
+
+        // special case for bools, which are treated as uint8
+        code += "  " + GenBBAccess() + ".write" +
+                MakeCamel(GenType(field.value.type)) +
+                "(this.bb_pos + offset, ";
+        if (field.value.type.base_type == BASE_TYPE_BOOL &&
+            lang_.language == IDLOptions::kTs) {
+          code += "+";
+        }
+
+        code += "value);\n";
+        code += "  return true;\n";
+        code += "};\n\n";
+
+        if (parser_.opts.use_goog_js_export_format) {
+          exports += "goog.exportProperty(" + object_name +
+                     ".prototype, 'mutate_" + field.name + "', " + object_name +
+                     ".prototype.mutate_" + field.name + ");\n";
+        }
+      }
+
+      // Emit vector helpers
+      if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+        // Emit a length helper
+        GenDocComment(code_ptr,
+                      GenTypeAnnotation(kReturns, "number", "", false));
+        if (lang_.language == IDLOptions::kTs) {
+          code += MakeCamel(field.name, false);
+          code += "Length():number {\n" + offset_prefix;
+        } else {
+          code += object_name + ".prototype." + MakeCamel(field.name, false);
+          code += "Length = function() {\n" + offset_prefix;
+        }
+
+        code +=
+            GenBBAccess() + ".__vector_len(this.bb_pos + offset) : 0;\n};\n\n";
+
+        if (parser_.opts.use_goog_js_export_format) {
+          exports += "goog.exportProperty(" + object_name + ".prototype, '" +
+                     MakeCamel(field.name, false) + "Length', " + object_name +
+                     ".prototype." + MakeCamel(field.name, false) +
+                     "Length);\n";
+        }
+
+        // For scalar types, emit a typed array helper
+        auto vectorType = field.value.type.VectorType();
+        if (IsScalar(vectorType.base_type) && !IsLong(vectorType.base_type)) {
+          GenDocComment(code_ptr, GenTypeAnnotation(
+                                      kReturns, GenType(vectorType) + "Array",
+                                      "", false));
+
+          if (lang_.language == IDLOptions::kTs) {
+            code += MakeCamel(field.name, false);
+            code += "Array():" + GenType(vectorType) + "Array|null {\n" +
+                    offset_prefix;
+          } else {
+            code += object_name + ".prototype." + MakeCamel(field.name, false);
+            code += "Array = function() {\n" + offset_prefix;
+          }
+
+          code += "new " + GenType(vectorType) + "Array(" + GenBBAccess() +
+                  ".bytes().buffer, " + GenBBAccess() +
+                  ".bytes().byteOffset + " + GenBBAccess() +
+                  ".__vector(this.bb_pos + offset), " + GenBBAccess() +
+                  ".__vector_len(this.bb_pos + offset)) : null;\n};\n\n";
+
+          if (parser_.opts.use_goog_js_export_format) {
+            exports += "goog.exportProperty(" + object_name + ".prototype, '" +
+                       MakeCamel(field.name, false) + "Array', " + object_name +
+                       ".prototype." + MakeCamel(field.name, false) +
+                       "Array);\n";
+          }
+        }
+      }
+    }
+
+    // Emit a factory constructor
+    if (struct_def.fixed) {
+      std::string annotations =
+          GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder");
+      std::string arguments;
+      GenStructArgs(struct_def, &annotations, &arguments, "");
+      GenDocComment(code_ptr, annotations + GenTypeAnnotation(
+                                                kReturns, "flatbuffers.Offset",
+                                                "", false));
+
+      if (lang_.language == IDLOptions::kTs) {
+        code += "static create" + Verbose(struct_def) +
+                "(builder:flatbuffers.Builder";
+        code += arguments + "):flatbuffers.Offset {\n";
+      } else {
+        code += object_name + ".create" + Verbose(struct_def);
+        code += " = function(builder";
+        code += arguments + ") {\n";
+      }
+
+      GenStructBody(struct_def, &code, "");
+      code += "  return builder.offset();\n};\n\n";
+    } else {
+      // Generate a method to start building a new object
+      GenDocComment(code_ptr, GenTypeAnnotation(kParam, "flatbuffers.Builder",
+                                                "builder", false));
+
+      if (lang_.language == IDLOptions::kTs) {
+        code += "static start" + Verbose(struct_def) +
+                "(builder:flatbuffers.Builder) {\n";
+      } else {
+        code += object_name + ".start" + Verbose(struct_def);
+        code += " = function(builder) {\n";
+      }
+
+      code += "  builder.startObject(" +
+              NumToString(struct_def.fields.vec.size()) + ");\n";
+      code += "};\n\n";
+
+      // Generate a set of static methods that allow table construction
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        auto &field = **it;
+        if (field.deprecated) continue;
+        const auto argname = GetArgName(field);
+
+        // Generate the field insertion method
+        GenDocComment(
+            code_ptr,
+            GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
+                GenTypeAnnotation(kParam, GenTypeName(field.value.type, true),
+                                  argname, false));
+
+        if (lang_.language == IDLOptions::kTs) {
+          code += "static add" + MakeCamel(field.name);
+          code += "(builder:flatbuffers.Builder, " + argname + ":" +
+                  GetArgType(field) + ") {\n";
+        } else {
+          code += object_name + ".add" + MakeCamel(field.name);
+          code += " = function(builder, " + argname + ") {\n";
+        }
+
+        code += "  builder.addField" + GenWriteMethod(field.value.type) + "(";
+        code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
+        if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; }
+        code += argname + ", ";
+        if (!IsScalar(field.value.type.base_type)) {
+          code += "0";
+        } else {
+          if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; }
+          code += GenDefaultValue(field.value, "builder");
+        }
+        code += ");\n};\n\n";
+
+        if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+          auto vector_type = field.value.type.VectorType();
+          auto alignment = InlineAlignment(vector_type);
+          auto elem_size = InlineSize(vector_type);
+
+          // Generate a method to create a vector from a JavaScript array
+          if (!IsStruct(vector_type)) {
+            GenDocComment(
+                code_ptr,
+                GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
+                    GenTypeAnnotation(
+                        kParam,
+                        "Array.<" + GenTypeName(vector_type, true) + ">",
+                        "data") +
+                    GenTypeAnnotation(kReturns, "flatbuffers.Offset", "",
+                                      false));
+
+            if (lang_.language == IDLOptions::kTs) {
+              code += "static create" + MakeCamel(field.name);
+              std::string type = GenTypeName(vector_type, true) + "[]";
+              if (type == "number[]") { type += " | Uint8Array"; }
+              code += "Vector(builder:flatbuffers.Builder, data:" + type +
+                      "):flatbuffers.Offset {\n";
+            } else {
+              code += object_name + ".create" + MakeCamel(field.name);
+              code += "Vector = function(builder, data) {\n";
+            }
+
+            code += "  builder.startVector(" + NumToString(elem_size);
+            code += ", data.length, " + NumToString(alignment) + ");\n";
+            code += "  for (var i = data.length - 1; i >= 0; i--) {\n";
+            code += "    builder.add" + GenWriteMethod(vector_type) + "(";
+            if (vector_type.base_type == BASE_TYPE_BOOL) { code += "+"; }
+            code += "data[i]);\n";
+            code += "  }\n";
+            code += "  return builder.endVector();\n";
+            code += "};\n\n";
+          }
+
+          // Generate a method to start a vector, data to be added manually
+          // after
+          GenDocComment(
+              code_ptr,
+              GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
+                  GenTypeAnnotation(kParam, "number", "numElems", false));
+
+          if (lang_.language == IDLOptions::kTs) {
+            code += "static start" + MakeCamel(field.name);
+            code += "Vector(builder:flatbuffers.Builder, numElems:number) {\n";
+          } else {
+            code += object_name + ".start" + MakeCamel(field.name);
+            code += "Vector = function(builder, numElems) {\n";
+          }
+
+          code += "  builder.startVector(" + NumToString(elem_size);
+          code += ", numElems, " + NumToString(alignment) + ");\n";
+          code += "};\n\n";
+        }
+      }
+
+      // Generate a method to stop building a new object
+      GenDocComment(
+          code_ptr,
+          GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
+              GenTypeAnnotation(kReturns, "flatbuffers.Offset", "", false));
+
+      if (lang_.language == IDLOptions::kTs) {
+        code += "static end" + Verbose(struct_def);
+        code += "(builder:flatbuffers.Builder):flatbuffers.Offset {\n";
+      } else {
+        code += object_name + ".end" + Verbose(struct_def);
+        code += " = function(builder) {\n";
+      }
+
+      code += "  var offset = builder.endObject();\n";
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        auto &field = **it;
+        if (!field.deprecated && field.required) {
+          code += "  builder.requiredField(offset, ";
+          code += NumToString(field.value.offset);
+          code += "); // " + field.name + "\n";
+        }
+      }
+      code += "  return offset;\n";
+      code += "};\n\n";
+
+      // Generate the methods to complete buffer construction
+      GenerateFinisher(struct_def, code_ptr, code, object_name, false);
+      GenerateFinisher(struct_def, code_ptr, code, object_name, true);
+
+      // Generate a convenient CreateX function
+      if (lang_.language == IDLOptions::kJs) {
+        std::string paramDoc =
+            GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder");
+        for (auto it = struct_def.fields.vec.begin();
+             it != struct_def.fields.vec.end(); ++it) {
+          const auto &field = **it;
+          if (field.deprecated)
+            continue;
+          paramDoc +=
+              GenTypeAnnotation(kParam, GetArgType(field), GetArgName(field));
+        }
+        paramDoc +=
+            GenTypeAnnotation(kReturns, "flatbuffers.Offset", "", false);
+
+        GenDocComment(code_ptr, paramDoc);
+      }
+
+      if (lang_.language == IDLOptions::kTs) {
+        code += "static create" + Verbose(struct_def);
+        code += "(builder:flatbuffers.Builder";
+      } else {
+        code += object_name + ".create" + Verbose(struct_def);
+        code += " = function(builder";
+      }
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        const auto &field = **it;
+        if (field.deprecated)
+          continue;
+
+        if (lang_.language == IDLOptions::kTs) {
+          code += ", " + GetArgName(field) + ":" + GetArgType(field);
+        } else {
+          code += ", " + GetArgName(field);
+        }
+      }
+
+      if (lang_.language == IDLOptions::kTs) {
+        code += "):flatbuffers.Offset {\n";
+        code += "  " + struct_def.name + ".start" + Verbose(struct_def) +
+                "(builder);\n";
+      } else {
+        code += ") {\n";
+        code += "  " + object_name + ".start" + Verbose(struct_def) +
+                "(builder);\n";
+      }
+
+      std::string methodPrefix =
+          lang_.language == IDLOptions::kTs ? struct_def.name : object_name;
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        const auto &field = **it;
+        if (field.deprecated)
+          continue;
+
+        code += "  " + methodPrefix + ".add" + MakeCamel(field.name) + "(";
+        code += "builder, " + GetArgName(field) + ");\n";
+      }
+
+      code += "  return " + methodPrefix + ".end" + Verbose(struct_def) +
+              "(builder);\n";
+      code += "}\n";
+      if (lang_.language == IDLOptions::kJs)
+        code += "\n";
+    }
+
+    if (lang_.language == IDLOptions::kTs) {
+      if (!object_namespace.empty()) {
+        code += "}\n";
+      }
+      code += "}\n";
+    }
+  }
+
+  std::string GetArgType(const FieldDef &field) {
+    if (field.value.type.enum_def)
+      return GenPrefixedTypeName(GenTypeName(field.value.type, true),
+                                 field.value.type.enum_def->file);
+    return GenTypeName(field.value.type, true);
+  }
+
+  static std::string GetArgName(const FieldDef &field) {
+    auto argname = MakeCamel(field.name, false);
+    if (!IsScalar(field.value.type.base_type)) { argname += "Offset"; }
+
+    return argname;
+  }
+
+  std::string Verbose(const StructDef &struct_def,
+                      const char* prefix = "")
+  {
+    return parser_.opts.js_ts_short_names ? "" : prefix + struct_def.name;
+  }
+};
+}  // namespace jsts
+
+bool GenerateJSTS(const Parser &parser, const std::string &path,
+                  const std::string &file_name) {
+  jsts::JsTsGenerator generator(parser, path, file_name);
+  return generator.generate();
+}
+
+std::string JSTSMakeRule(const Parser &parser, const std::string &path,
+                         const std::string &file_name) {
+  FLATBUFFERS_ASSERT(parser.opts.lang <= IDLOptions::kMAX);
+  const auto &lang = GetJsLangParams(parser.opts.lang);
+
+  std::string filebase =
+      flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+  std::string make_rule = GeneratedFileName(path, filebase, lang) + ": ";
+
+  auto included_files = parser.GetIncludedFilesRecursive(file_name);
+  for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+    make_rule += " " + *it;
+  }
+  return make_rule;
+}
+
+}  // namespace flatbuffers
diff --git a/src/idl_gen_json_schema.cpp b/src/idl_gen_json_schema.cpp
new file mode 100644
index 0000000..27e2cd4
--- /dev/null
+++ b/src/idl_gen_json_schema.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2014 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 <iostream>
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+static std::string GeneratedFileName(const std::string &path,
+                                     const std::string &file_name) {
+  return path + file_name + ".schema.json";
+}
+
+namespace jsons {
+
+std::string GenNativeType(BaseType type) {
+  switch (type) {
+    case BASE_TYPE_BOOL: return "boolean";
+    case BASE_TYPE_CHAR:
+    case BASE_TYPE_UCHAR:
+    case BASE_TYPE_SHORT:
+    case BASE_TYPE_USHORT:
+    case BASE_TYPE_INT:
+    case BASE_TYPE_UINT:
+    case BASE_TYPE_LONG:
+    case BASE_TYPE_ULONG:
+    case BASE_TYPE_FLOAT:
+    case BASE_TYPE_DOUBLE: return "number";
+    case BASE_TYPE_STRING: return "string";
+    case BASE_TYPE_ARRAY: return "array";
+    default: return "";
+  }
+}
+
+template<class T> std::string GenFullName(const T *enum_def) {
+  std::string full_name;
+  const auto &name_spaces = enum_def->defined_namespace->components;
+  for (auto ns = name_spaces.cbegin(); ns != name_spaces.cend(); ++ns) {
+    full_name.append(*ns + "_");
+  }
+  full_name.append(enum_def->name);
+  return full_name;
+}
+
+template<class T> std::string GenTypeRef(const T *enum_def) {
+  return "\"$ref\" : \"#/definitions/" + GenFullName(enum_def) + "\"";
+}
+
+std::string GenType(const std::string &name) {
+  return "\"type\" : \"" + name + "\"";
+}
+
+std::string GenType(const Type &type) {
+  if (type.enum_def != nullptr && !type.enum_def->is_union) {
+    // it is a reference to an enum type
+    return GenTypeRef(type.enum_def);
+  }
+  switch (type.base_type) {
+    case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();  // fall thru
+    case BASE_TYPE_VECTOR: {
+      std::string typeline;
+      typeline.append("\"type\" : \"array\", \"items\" : { ");
+      if (type.element == BASE_TYPE_STRUCT) {
+        typeline.append(GenTypeRef(type.struct_def));
+      } else {
+        typeline.append(GenType(GenNativeType(type.element)));
+      }
+      typeline.append(" }");
+      return typeline;
+    }
+    case BASE_TYPE_STRUCT: {
+      return GenTypeRef(type.struct_def);
+    }
+    case BASE_TYPE_UNION: {
+      std::string union_type_string("\"anyOf\": [");
+      const auto &union_types = type.enum_def->Vals();
+      for (auto ut = union_types.cbegin(); ut < union_types.cend(); ++ut) {
+        auto &union_type = *ut;
+        if (union_type->union_type.base_type == BASE_TYPE_NONE) { continue; }
+        if (union_type->union_type.base_type == BASE_TYPE_STRUCT) {
+          union_type_string.append(
+              "{ " + GenTypeRef(union_type->union_type.struct_def) + " }");
+        }
+        if (union_type != *type.enum_def->Vals().rbegin()) {
+          union_type_string.append(",");
+        }
+      }
+      union_type_string.append("]");
+      return union_type_string;
+    }
+    case BASE_TYPE_UTYPE: return GenTypeRef(type.enum_def);
+    default: return GenType(GenNativeType(type.base_type));
+  }
+}
+
+class JsonSchemaGenerator : public BaseGenerator {
+ private:
+  CodeWriter code_;
+
+ public:
+  JsonSchemaGenerator(const Parser &parser, const std::string &path,
+                      const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "", "") {}
+
+  explicit JsonSchemaGenerator(const BaseGenerator &base_generator)
+      : BaseGenerator(base_generator) {}
+
+  bool generate() {
+    code_.Clear();
+    code_ += "{";
+    code_ += "  \"$schema\": \"http://json-schema.org/draft-04/schema#\",";
+    code_ += "  \"definitions\": {";
+    for (auto e = parser_.enums_.vec.cbegin(); e != parser_.enums_.vec.cend();
+         ++e) {
+      code_ += "    \"" + GenFullName(*e) + "\" : {";
+      code_ += "      " + GenType("string") + ",";
+      std::string enumdef("      \"enum\": [");
+      for (auto enum_value = (*e)->Vals().begin();
+           enum_value != (*e)->Vals().end(); ++enum_value) {
+        enumdef.append("\"" + (*enum_value)->name + "\"");
+        if (*enum_value != (*e)->Vals().back()) { enumdef.append(", "); }
+      }
+      enumdef.append("]");
+      code_ += enumdef;
+      code_ += "    },";  // close type
+    }
+    for (auto s = parser_.structs_.vec.cbegin();
+         s != parser_.structs_.vec.cend(); ++s) {
+      const auto &structure = *s;
+      code_ += "    \"" + GenFullName(structure) + "\" : {";
+      code_ += "      " + GenType("object") + ",";
+      std::string comment;
+      const auto &comment_lines = structure->doc_comment;
+      for (auto comment_line = comment_lines.cbegin();
+           comment_line != comment_lines.cend(); ++comment_line) {
+        comment.append(*comment_line);
+      }
+      if (comment.size() > 0) {
+        code_ += "      \"description\" : \"" + comment + "\",";
+      }
+      code_ += "      \"properties\" : {";
+
+      const auto &properties = structure->fields.vec;
+      for (auto prop = properties.cbegin(); prop != properties.cend(); ++prop) {
+        const auto &property = *prop;
+        std::string arrayInfo = "";
+        if (IsArray(property->value.type)) {
+          arrayInfo = ",\n                \"minItems\": " +
+                      NumToString(property->value.type.fixed_length) +
+                      ",\n                \"maxItems\": " +
+                      NumToString(property->value.type.fixed_length);
+        }
+        std::string typeLine =
+            "        \"" + property->name + "\" : {\n" + "                " +
+            GenType(property->value.type) + arrayInfo + "\n              }";
+        if (property != properties.back()) { typeLine.append(","); }
+        code_ += typeLine;
+      }
+      code_ += "      },";  // close properties
+
+      std::vector<FieldDef *> requiredProperties;
+      std::copy_if(properties.begin(), properties.end(),
+                   back_inserter(requiredProperties),
+                   [](FieldDef const *prop) { return prop->required; });
+      if (requiredProperties.size() > 0) {
+        std::string required_string("      \"required\" : [");
+        for (auto req_prop = requiredProperties.cbegin();
+             req_prop != requiredProperties.cend(); ++req_prop) {
+          required_string.append("\"" + (*req_prop)->name + "\"");
+          if (*req_prop != requiredProperties.back()) {
+            required_string.append(", ");
+          }
+        }
+        required_string.append("],");
+        code_ += required_string;
+      }
+      code_ += "      \"additionalProperties\" : false";
+      std::string closeType("    }");
+      if (*s != parser_.structs_.vec.back()) { closeType.append(","); }
+      code_ += closeType;  // close type
+    }
+    code_ += "  },";  // close definitions
+
+    // mark root type
+    code_ += "  \"$ref\" : \"#/definitions/" +
+             GenFullName(parser_.root_struct_def_) + "\"";
+
+    code_ += "}";  // close schema root
+    const std::string file_path = GeneratedFileName(path_, file_name_);
+    const std::string final_code = code_.ToString();
+    return SaveFile(file_path.c_str(), final_code, false);
+  }
+};
+}  // namespace jsons
+
+bool GenerateJsonSchema(const Parser &parser, const std::string &path,
+                        const std::string &file_name) {
+  jsons::JsonSchemaGenerator generator(parser, path, file_name);
+  return generator.generate();
+}
+}  // namespace flatbuffers
diff --git a/src/idl_gen_kotlin.cpp b/src/idl_gen_kotlin.cpp
new file mode 100644
index 0000000..3ced7b3
--- /dev/null
+++ b/src/idl_gen_kotlin.cpp
@@ -0,0 +1,1527 @@
+/*
+ * Copyright 2014 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.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include <functional>
+#include <unordered_set>
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+#if defined(FLATBUFFERS_CPP98_STL)
+#include <cctype>
+#endif  // defined(FLATBUFFERS_CPP98_STL)
+
+namespace flatbuffers {
+
+namespace kotlin {
+
+typedef std::map<std::string, std::pair<std::string, std::string> > FbbParamMap;
+static TypedFloatConstantGenerator KotlinFloatGen("Double.", "Float.", "NaN",
+                                                  "POSITIVE_INFINITY",
+                                                  "NEGATIVE_INFINITY");
+
+static const CommentConfig comment_config = {"/**", " *", " */"};
+static const std::string ident_pad = "    ";
+static const char *keywords[] = {
+    "package",  "as",     "typealias", "class",  "this",   "super",
+    "val",      "var",    "fun",       "for",    "null",   "true",
+    "false",    "is",     "in",        "throw",  "return", "break",
+    "continue", "object", "if",        "try",    "else",   "while",
+    "do",       "when",   "interface", "typeof", "Any",    "Character"};
+
+// Escape Keywords
+static std::string Esc(const std::string &name) {
+  for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
+    if (name == keywords[i]) {
+      return MakeCamel(name + "_", false);
+    }
+  }
+
+  return MakeCamel(name, false);
+}
+
+class KotlinGenerator : public BaseGenerator {
+ public:
+  KotlinGenerator(const Parser &parser, const std::string &path,
+                  const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "", "."),
+        cur_name_space_(nullptr) {}
+
+  KotlinGenerator &operator=(const KotlinGenerator &);
+  bool generate() FLATBUFFERS_OVERRIDE {
+    std::string one_file_code;
+
+    cur_name_space_ = parser_.current_namespace_;
+    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+         ++it) {
+      CodeWriter enumWriter(ident_pad);
+      auto &enum_def = **it;
+      if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
+      GenEnum(enum_def, enumWriter);
+      if (parser_.opts.one_file) {
+        one_file_code += enumWriter.ToString();
+      } else {
+        if (!SaveType(enum_def.name, *enum_def.defined_namespace,
+                      enumWriter.ToString(), false))
+          return false;
+      }
+    }
+
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      CodeWriter structWriter(ident_pad);
+      auto &struct_def = **it;
+      if (!parser_.opts.one_file)
+        cur_name_space_ = struct_def.defined_namespace;
+      GenStruct(struct_def, structWriter);
+      if (parser_.opts.one_file) {
+        one_file_code += structWriter.ToString();
+      } else {
+        if (!SaveType(struct_def.name, *struct_def.defined_namespace,
+                      structWriter.ToString(), true))
+          return false;
+      }
+    }
+
+    if (parser_.opts.one_file) {
+      return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
+                      true);
+    }
+    return true;
+  }
+
+  // Save out the generated code for a single class while adding
+  // declaration boilerplate.
+  bool SaveType(const std::string &defname, const Namespace &ns,
+                const std::string &classcode, bool needs_includes) const {
+    if (!classcode.length()) return true;
+
+    std::string code =
+        "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+    std::string namespace_name = FullNamespace(".", ns);
+    if (!namespace_name.empty()) {
+      code += "package " + namespace_name;
+      code += "\n\n";
+    }
+    if (needs_includes) {
+      code += "import java.nio.*\n";
+      code += "import kotlin.math.sign\n";
+      code += "import com.google.flatbuffers.*\n\n";
+    }
+    code += classcode;
+    auto filename = NamespaceDir(ns) + defname + ".kt";
+    return SaveFile(filename.c_str(), code, false);
+  }
+
+  const Namespace *CurrentNameSpace() const FLATBUFFERS_OVERRIDE {
+    return cur_name_space_;
+  }
+
+  static bool IsEnum(const Type &type) {
+    return type.enum_def != nullptr && IsInteger(type.base_type);
+  }
+
+  static std::string GenTypeBasic(const BaseType &type) {
+    // clang-format off
+        static const char * const kotlin_typename[] = {
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+        CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+    #KTYPE,
+        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+    #undef FLATBUFFERS_TD
+        };
+        return kotlin_typename[type];
+
+    }
+
+    std::string GenTypePointer(const Type &type) const {
+        switch (type.base_type) {
+        case BASE_TYPE_STRING:
+            return "String";
+        case BASE_TYPE_VECTOR:
+            return GenTypeGet(type.VectorType());
+        case BASE_TYPE_STRUCT:
+            return WrapInNameSpace(*type.struct_def);
+        default:
+            return "Table";
+        }
+    }
+
+    std::string GenTypeGet(const Type &type) const {
+        return IsScalar(type.base_type) ? GenTypeBasic(type.base_type)
+                                        : GenTypePointer(type);
+    }
+
+    std::string GenEnumDefaultValue(const FieldDef &field) const {
+        auto &value = field.value;
+        FLATBUFFERS_ASSERT(value.type.enum_def);
+        auto &enum_def = *value.type.enum_def;
+        auto enum_val = enum_def.FindByValue(value.constant);
+        return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
+                        : value.constant;
+    }
+
+
+     // Generate default values to compare against a default value when
+     // `force_defaults` is `false`.
+     // Main differences are:
+     // - Floats are upcasted to doubles
+     // - Unsigned are casted to signed
+    std::string GenFBBDefaultValue(const FieldDef &field) const {
+        auto out = GenDefaultValue(field, true);
+        // All FlatBufferBuilder default floating point values are doubles
+        if (field.value.type.base_type == BASE_TYPE_FLOAT) {
+            if (out.find("Float") != std::string::npos) {
+                out.replace(0, 5, "Double");
+            }
+        }
+        //Guarantee all values are doubles
+        if (out.back() == 'f')
+            out.pop_back();
+        return out;
+    }
+
+
+    // FlatBufferBuilder only store signed types, so this function
+    // returns a cast for unsigned values
+    std::string GenFBBValueCast(const FieldDef &field) const {
+        if (IsUnsigned(field.value.type.base_type)) {
+            return CastToSigned(field.value.type);
+        }
+        return "";
+    }
+
+    std::string GenDefaultValue(const FieldDef &field,
+                                bool force_signed = false) const {
+        auto &value = field.value;
+        auto base_type = field.value.type.base_type;
+        if (IsFloat(base_type)) {
+            auto val = KotlinFloatGen.GenFloatConstant(field);
+            if (base_type == BASE_TYPE_DOUBLE &&
+                    val.back() == 'f') {
+                val.pop_back();
+            }
+            return val;
+        }
+
+        if (base_type  == BASE_TYPE_BOOL) {
+            return value.constant == "0" ? "false" : "true";
+        }
+
+        std::string suffix = "";
+
+        if (base_type == BASE_TYPE_LONG || !force_signed) {
+            suffix = LiteralSuffix(base_type);
+        }
+        return value.constant + suffix;
+    }
+
+    void GenEnum(EnumDef &enum_def, CodeWriter &writer) const {
+        if (enum_def.generated) return;
+
+        GenerateComment(enum_def.doc_comment, writer, &comment_config);
+
+        writer += "@Suppress(\"unused\")";
+        writer += "@ExperimentalUnsignedTypes";
+        writer += "class " + Esc(enum_def.name) + " private constructor() {";
+        writer.IncrementIdentLevel();
+
+        GenerateCompanionObject(writer, [&](){
+            // Write all properties
+            auto vals = enum_def.Vals();
+            for (auto it = vals.begin(); it != vals.end(); ++it) {
+                auto &ev = **it;
+                auto field_type = GenTypeBasic(enum_def.underlying_type.base_type);
+                auto val = enum_def.ToString(ev);
+                auto suffix = LiteralSuffix(enum_def.underlying_type.base_type);
+                writer.SetValue("name", Esc(ev.name));
+                writer.SetValue("type", field_type);
+                writer.SetValue("val", val + suffix);
+                GenerateComment(ev.doc_comment, writer, &comment_config);
+                writer += "const val {{name}}: {{type}} = {{val}}";
+            }
+
+            // Generate a generate string table for enum values.
+            // Problem is, if values are very sparse that could generate really
+            // big tables. Ideally in that case we generate a map lookup
+            // instead, but for the moment we simply don't output a table at all.
+            auto range = enum_def.Distance();
+            // Average distance between values above which we consider a table
+            // "too sparse". Change at will.
+            static const uint64_t kMaxSparseness = 5;
+            if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
+                GeneratePropertyOneLine(writer, "names", "Array<String>",
+                               [&](){
+                    writer += "arrayOf(\\";
+                    auto val = enum_def.Vals().front();
+                    for (auto it = vals.begin(); it != vals.end(); ++it) {
+                        auto ev = *it;
+                        for (auto k = enum_def.Distance(val, ev); k > 1; --k)
+                            writer += "\"\", \\";
+                        val = ev;
+                        writer += "\"" + (*it)->name + "\"\\";
+                        if (it+1 != vals.end()) {
+                            writer += ", \\";
+                        }
+                    }
+                    writer += ")";
+                });
+                GenerateFunOneLine(writer, "name", "e: Int", "String", [&](){
+                    writer += "names[e\\";
+                    if (enum_def.MinValue()->IsNonZero())
+                        writer += " - " + enum_def.MinValue()->name + ".toInt()\\";
+                    writer += "]";
+                });
+            }
+        });
+        writer.DecrementIdentLevel();
+        writer += "}";
+    }
+
+    // Returns the function name that is able to read a value of the given type.
+    std::string ByteBufferGetter(const Type &type, std::string bb_var_name) const {
+        switch (type.base_type) {
+        case BASE_TYPE_STRING:
+            return "__string";
+        case BASE_TYPE_STRUCT:
+            return "__struct";
+        case BASE_TYPE_UNION:
+            return "__union";
+        case BASE_TYPE_VECTOR:
+            return ByteBufferGetter(type.VectorType(), bb_var_name);
+        case BASE_TYPE_INT:
+        case BASE_TYPE_UINT:
+            return bb_var_name + ".getInt";
+        case BASE_TYPE_SHORT:
+        case BASE_TYPE_USHORT:
+            return bb_var_name + ".getShort";
+        case BASE_TYPE_ULONG:
+        case BASE_TYPE_LONG:
+            return bb_var_name + ".getLong";
+        case BASE_TYPE_FLOAT:
+            return bb_var_name + ".getFloat";
+        case BASE_TYPE_DOUBLE:
+            return bb_var_name + ".getDouble";
+        case BASE_TYPE_CHAR:
+        case BASE_TYPE_UCHAR:
+        case BASE_TYPE_NONE:
+        case BASE_TYPE_UTYPE:
+            return bb_var_name + ".get";
+        case BASE_TYPE_BOOL:
+            return "0.toByte() != " + bb_var_name + ".get";
+        default:
+            return bb_var_name + ".get" + MakeCamel(GenTypeBasic(type.base_type));
+        }
+    }
+
+    std::string ByteBufferSetter(const Type &type) const {
+        if (IsScalar(type.base_type)) {
+            switch (type.base_type) {
+            case BASE_TYPE_INT:
+            case BASE_TYPE_UINT:
+                return "bb.putInt";
+            case BASE_TYPE_SHORT:
+            case BASE_TYPE_USHORT:
+                return "bb.putShort";
+            case BASE_TYPE_ULONG:
+            case BASE_TYPE_LONG:
+                return "bb.putLong";
+            case BASE_TYPE_FLOAT:
+                return "bb.putFloat";
+            case BASE_TYPE_DOUBLE:
+                return "bb.putDouble";
+            case BASE_TYPE_CHAR:
+            case BASE_TYPE_UCHAR:
+            case BASE_TYPE_BOOL:
+            case BASE_TYPE_NONE:
+            case BASE_TYPE_UTYPE:
+                return "bb.put";
+            default:
+                return "bb.put" + MakeCamel(GenTypeBasic(type.base_type));
+            }
+        }
+        return "";
+    }
+
+    // Returns the function name that is able to read a value of the given type.
+    std::string GenLookupByKey(flatbuffers::FieldDef *key_field,
+                               const std::string &bb_var_name,
+                               const char *num = nullptr) const {
+        auto type = key_field->value.type;
+        return ByteBufferGetter(type, bb_var_name) + "(" + GenOffsetGetter(key_field, num) + ")";
+
+    }
+
+    // Returns the method name for use with add/put calls.
+    static std::string GenMethod(const Type &type) {
+        return IsScalar(type.base_type) ? ToSignedType(type)
+                                        : (IsStruct(type) ? "Struct" : "Offset");
+    }
+
+    // Recursively generate arguments for a constructor, to deal with nested
+    // structs.
+    static void GenStructArgs(const StructDef &struct_def, CodeWriter &writer,
+                              const char *nameprefix) {
+        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.
+                GenStructArgs(*field.value.type.struct_def, writer,
+                              (nameprefix + (field.name + "_")).c_str());
+            } else {
+                writer += std::string(", ") + nameprefix + "\\";
+                writer += MakeCamel(field.name) + ": \\";
+                writer += GenTypeBasic(field.value.type.base_type) + "\\";
+            }
+        }
+    }
+
+    // Recusively generate struct construction statements of the form:
+    // builder.putType(name);
+    // and insert manual padding.
+    static void GenStructBody(const StructDef &struct_def, CodeWriter &writer,
+                              const char *nameprefix) {
+        writer.SetValue("align", NumToString(struct_def.minalign));
+        writer.SetValue("size", NumToString(struct_def.bytesize));
+        writer += "builder.prep({{align}}, {{size}})";
+        auto fields_vec = struct_def.fields.vec;
+        for (auto it = fields_vec.rbegin(); it != fields_vec.rend(); ++it) {
+            auto &field = **it;
+
+            if (field.padding) {
+                writer.SetValue("pad", NumToString(field.padding));
+                writer += "builder.pad({{pad}})";
+            }
+            if (IsStruct(field.value.type)) {
+                GenStructBody(*field.value.type.struct_def, writer,
+                              (nameprefix + (field.name + "_")).c_str());
+            } else {
+                writer.SetValue("type", GenMethod(field.value.type));
+                writer.SetValue("argname", nameprefix +
+                              MakeCamel(field.name, false));
+                writer.SetValue("cast", CastToSigned(field.value.type));
+                writer += "builder.put{{type}}({{argname}}{{cast}})";
+            }
+        }
+    }
+
+    std::string GenByteBufferLength(const char *bb_name) const {
+        std::string bb_len = bb_name;
+        bb_len += ".capacity()";
+        return bb_len;
+    }
+
+    std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
+                                const char *num = nullptr) const {
+        std::string key_offset = "__offset(" +
+                NumToString(key_field->value.offset) + ", ";
+        if (num) {
+            key_offset += num;
+            key_offset += ", _bb)";
+        } else {
+            key_offset += GenByteBufferLength("bb");
+            key_offset += " - tableOffset, bb)";
+        }
+        return key_offset;
+    }
+
+    void GenStruct(StructDef &struct_def, CodeWriter &writer) const {
+        if (struct_def.generated) return;
+
+        GenerateComment(struct_def.doc_comment, writer, &comment_config);
+        auto fixed = struct_def.fixed;
+
+        writer.SetValue("struct_name", Esc(struct_def.name));
+        writer.SetValue("superclass", fixed ? "Struct" : "Table");
+
+        writer += "@Suppress(\"unused\")";
+        writer += "@ExperimentalUnsignedTypes";
+        writer += "class {{struct_name}} : {{superclass}}() {\n";
+
+        writer.IncrementIdentLevel();
+
+        {
+            // Generate the __init() method that sets the field in a pre-existing
+            // accessor object. This is to allow object reuse.
+            GenerateFun(writer, "__init", "_i: Int, _bb: ByteBuffer", "", [&]() {
+                writer += "__reset(_i, _bb)";
+            });
+
+            // Generate assign method
+            GenerateFun(writer, "__assign", "_i: Int, _bb: ByteBuffer",
+                        Esc(struct_def.name), [&]() {
+                writer += "__init(_i, _bb)";
+                writer += "return this";
+            });
+
+            // Generate all getters
+            GenerateStructGetters(struct_def, writer);
+
+            // Generate Static Fields
+            GenerateCompanionObject(writer, [&](){
+
+                if (!struct_def.fixed) {
+                    FieldDef *key_field = nullptr;
+
+                    // Generate verson check method.
+                    // Force compile time error if not using the same version
+                    // runtime.
+                    GenerateFunOneLine(writer, "validateVersion", "", "", [&](){
+                        writer += "Constants.FLATBUFFERS_1_11_1()";
+                    });
+
+                    GenerateGetRootAsAccessors(Esc(struct_def.name), writer);
+                    GenerateBufferHasIdentifier(struct_def, writer);
+                    GenerateTableCreator(struct_def, writer);
+
+                    GenerateStartStructMethod(struct_def, writer);
+
+                    // Static Add for fields
+                    auto fields = struct_def.fields.vec;
+                    int field_pos = -1;
+                    for (auto it = fields.begin(); it != fields.end(); ++it) {
+                        auto &field = **it;
+                        field_pos++;
+                        if (field.deprecated) continue;
+                        if (field.key) key_field = &field;
+                        GenerateAddField(NumToString(field_pos), field, writer);
+
+                        if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+                            auto vector_type = field.value.type.VectorType();
+                            if (!IsStruct(vector_type)) {
+                                GenerateCreateVectorField(field, writer);
+                            }
+                            GenerateStartVectorField(field, writer);
+                        }
+                    }
+
+                    GenerateEndStructMethod(struct_def, writer);
+                    auto file_identifier = parser_.file_identifier_;
+                    if (parser_.root_struct_def_ == &struct_def) {
+                        GenerateFinishStructBuffer(struct_def,
+                                                   file_identifier,
+                                                   writer);
+                        GenerateFinishSizePrefixed(struct_def,
+                                                   file_identifier,
+                                                   writer);
+                    }
+
+                    if (struct_def.has_key) {
+                        GenerateLookupByKey(key_field, struct_def, writer);
+                    }
+                } else {
+                    GenerateStaticConstructor(struct_def, writer);
+                }
+            });
+        }
+
+        // class closing
+        writer.DecrementIdentLevel();
+        writer += "}";
+    }
+
+    // TODO: move key_field to reference instead of pointer
+    void GenerateLookupByKey(FieldDef *key_field, StructDef &struct_def,
+                             CodeWriter &writer) const {
+        std::stringstream params;
+        params << "obj: " << Esc(struct_def.name) << "?" << ", ";
+        params << "vectorLocation: Int, ";
+        params << "key: " <<  GenTypeGet(key_field->value.type) << ", ";
+        params << "bb: ByteBuffer";
+
+        auto statements = [&]() {
+            auto base_type = key_field->value.type.base_type;
+            writer.SetValue("struct_name", Esc(struct_def.name));
+            if (base_type == BASE_TYPE_STRING) {
+                writer += "val byteKey = key."
+                        "toByteArray(Table.UTF8_CHARSET.get()!!)";
+            }
+            writer += "var span = bb.getInt(vectorLocation - 4)";
+            writer += "var start = 0";
+            writer += "while (span != 0) {";
+            writer.IncrementIdentLevel();
+            writer += "var middle = span / 2";
+            writer += "val tableOffset = __indirect(vector"
+                    "Location + 4 * (start + middle), bb)";
+            if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+                writer += "val comp = compareStrings(\\";
+                writer += GenOffsetGetter(key_field) + "\\";
+                writer += ", byteKey, bb)";
+            } else {
+                auto cast = CastToUsigned(key_field->value.type);
+                auto get_val = GenLookupByKey(key_field, "bb");
+                writer += "val value = " + get_val + cast;
+                writer += "val comp = value.compareTo(key)";
+            }
+            writer += "when {";
+            writer.IncrementIdentLevel();
+            writer += "comp > 0 -> span = middle";
+            writer += "comp < 0 -> {";
+            writer.IncrementIdentLevel();
+            writer += "middle++";
+            writer += "start += middle";
+            writer += "span -= middle";
+            writer.DecrementIdentLevel();
+            writer += "}"; // end comp < 0
+            writer += "else -> {";
+            writer.IncrementIdentLevel();
+            writer += "return (obj ?: {{struct_name}}()).__assign(tableOffset, bb)";
+            writer.DecrementIdentLevel();
+            writer += "}"; // end else
+            writer.DecrementIdentLevel();
+            writer += "}"; // end when
+            writer.DecrementIdentLevel();
+            writer += "}"; // end while
+            writer += "return null";
+        };
+        GenerateFun(writer, "__lookup_by_key",
+                    params.str(),
+                    Esc(struct_def.name) + "?",
+                    statements);
+    }
+
+    void GenerateFinishSizePrefixed(StructDef &struct_def,
+                                                const std::string &identifier,
+                                                CodeWriter &writer) const {
+        auto id = identifier.length() > 0  ? ", \"" + identifier + "\"" : "";
+        auto params = "builder: FlatBufferBuilder, offset: Int";
+        auto method_name = "finishSizePrefixed" + Esc(struct_def.name) + "Buffer";
+        GenerateFunOneLine(writer, method_name, params, "", [&]() {
+            writer += "builder.finishSizePrefixed(offset" + id  + ")";
+        });
+    }
+    void GenerateFinishStructBuffer(StructDef &struct_def,
+                                    const std::string &identifier,
+                                    CodeWriter &writer) const {
+        auto id = identifier.length() > 0  ? ", \"" + identifier + "\"" : "";
+        auto params = "builder: FlatBufferBuilder, offset: Int";
+        auto method_name = "finish" + Esc(struct_def.name) + "Buffer";
+        GenerateFunOneLine(writer, method_name, params, "", [&]() {
+            writer += "builder.finish(offset" + id + ")";
+        });
+    }
+
+    void GenerateEndStructMethod(StructDef &struct_def, CodeWriter &writer) const {
+        // Generate end{{TableName}}(builder: FlatBufferBuilder) method
+        auto name = "end" + Esc(struct_def.name);
+        auto params = "builder: FlatBufferBuilder";
+        auto returns = "Int";
+        auto field_vec = struct_def.fields.vec;
+
+        GenerateFun(writer, name, params, returns, [&](){
+            writer += "val o = builder.endTable()";
+            writer.IncrementIdentLevel();
+            for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
+                auto &field = **it;
+                if (field.deprecated || !field.required) {
+                    continue;
+                }
+                writer.SetValue("offset", NumToString(field.value.offset));
+                writer += "builder.required(o, {{offset}})";
+            }
+            writer.DecrementIdentLevel();
+            writer += "return o";
+        });
+    }
+
+    // Generate a method to create a vector from a Kotlin array.
+    void GenerateCreateVectorField(FieldDef &field, CodeWriter &writer) const {
+        auto vector_type = field.value.type.VectorType();
+        auto method_name = "create" + MakeCamel(Esc(field.name)) + "Vector";
+        auto params = "builder: FlatBufferBuilder, data: " +
+                GenTypeBasic(vector_type.base_type) + "Array";
+        writer.SetValue("size", NumToString(InlineSize(vector_type)));
+        writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
+        writer.SetValue("root", GenMethod(vector_type));
+        writer.SetValue("cast", CastToSigned(vector_type));
+
+        GenerateFun(writer, method_name, params, "Int", [&](){
+            writer += "builder.startVector({{size}}, data.size, {{align}})";
+            writer += "for (i in data.size - 1 downTo 0) {";
+            writer.IncrementIdentLevel();
+            writer += "builder.add{{root}}(data[i]{{cast}})";
+            writer.DecrementIdentLevel();
+            writer += "}";
+            writer += "return builder.endVector()";
+        });
+    }
+
+    void GenerateStartVectorField(FieldDef &field, CodeWriter &writer) const {
+        // Generate a method to start a vector, data to be added manually
+        // after.
+        auto vector_type = field.value.type.VectorType();
+        auto params = "builder: FlatBufferBuilder, numElems: Int";
+        writer.SetValue("size", NumToString(InlineSize(vector_type)));
+        writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
+
+        GenerateFunOneLine(writer,
+                           "start" + MakeCamel(Esc(field.name) + "Vector", true),
+                           params,
+                           "",
+                           [&]() {
+            writer += "builder.startVector({{size}}, numElems, {{align}})";
+        });
+    }
+
+    void GenerateAddField(std::string field_pos, FieldDef &field,
+                          CodeWriter &writer) const {
+        auto field_type = GenTypeBasic(field.value.type.base_type);
+        auto secondArg = MakeCamel(Esc(field.name), false) + ": " + field_type;
+        GenerateFunOneLine(writer, "add" + MakeCamel(Esc(field.name), true),
+                           "builder: FlatBufferBuilder, " + secondArg, "", [&](){
+            auto method = GenMethod(field.value.type);
+            writer.SetValue("field_name", MakeCamel(Esc(field.name), false));
+            writer.SetValue("method_name", method);
+            writer.SetValue("pos", field_pos);
+            writer.SetValue("default", GenFBBDefaultValue(field));
+            writer.SetValue("cast", GenFBBValueCast(field));
+
+            writer += "builder.add{{method_name}}({{pos}}, \\";
+            writer += "{{field_name}}{{cast}}, {{default}})";
+        });
+    }
+
+    static std::string ToSignedType(const Type & type) {
+        switch(type.base_type) {
+        case BASE_TYPE_UINT:
+            return GenTypeBasic(BASE_TYPE_INT);
+        case BASE_TYPE_ULONG:
+            return GenTypeBasic(BASE_TYPE_LONG);
+        case BASE_TYPE_UCHAR:
+        case BASE_TYPE_NONE:
+        case BASE_TYPE_UTYPE:
+            return GenTypeBasic(BASE_TYPE_CHAR);
+        case BASE_TYPE_USHORT:
+            return GenTypeBasic(BASE_TYPE_SHORT);
+        case BASE_TYPE_VECTOR:
+            return ToSignedType(type.VectorType());
+        default:
+            return GenTypeBasic(type.base_type);
+        }
+    }
+
+    static std::string FlexBufferBuilderCast(const std::string &method,
+                                      FieldDef &field,
+                                      bool isFirst) {
+        auto field_type = GenTypeBasic(field.value.type.base_type);
+        std::string to_type;
+        if (method == "Boolean")
+            to_type = "Boolean";
+        else if (method == "Long")
+            to_type = "Long";
+        else if (method == "Int" || method == "Offset" || method == "Struct")
+            to_type = "Int";
+        else if (method == "Byte" || method.empty())
+            to_type =  isFirst ? "Byte" : "Int";
+        else if (method == "Short")
+            to_type =  isFirst ? "Short" : "Int";
+        else if (method == "Double")
+            to_type =  "Double";
+        else if (method == "Float")
+            to_type =  isFirst ? "Float" : "Double";
+        else if (method == "UByte")
+
+        if (field_type != to_type)
+            return ".to" + to_type + "()";
+        return "";
+    }
+
+    // fun startMonster(builder: FlatBufferBuilder) = builder.startTable(11)
+    void GenerateStartStructMethod(StructDef &struct_def, CodeWriter &code) const {
+        GenerateFunOneLine(code, "start" + Esc(struct_def.name),
+                           "builder: FlatBufferBuilder", "", [&] () {
+            code += "builder.startTable("+ NumToString(struct_def.fields.vec.size()) + ")";
+        });
+    }
+
+    void GenerateTableCreator(StructDef &struct_def, CodeWriter &writer) const {
+        // Generate a method that creates a table in one go. This is only possible
+        // when the table has no struct fields, since those have to be created
+        // inline, and there's no way to do so in Java.
+        bool has_no_struct_fields = true;
+        int num_fields = 0;
+        auto fields_vec = struct_def.fields.vec;
+
+        for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+            auto &field = **it;
+            if (field.deprecated) continue;
+            if (IsStruct(field.value.type)) {
+                has_no_struct_fields = false;
+            } else {
+                num_fields++;
+            }
+        }
+        // JVM specifications restrict default constructor params to be < 255.
+        // Longs and doubles take up 2 units, so we set the limit to be < 127.
+        if (has_no_struct_fields && num_fields && num_fields < 127) {
+            // Generate a table constructor of the form:
+            // public static int createName(FlatBufferBuilder builder, args...)
+
+            auto name = "create" + Esc(struct_def.name);
+            std::stringstream params;
+            params << "builder: FlatBufferBuilder";
+            for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+                auto &field = **it;
+                if (field.deprecated) continue;
+                params << ", " << MakeCamel(Esc(field.name), false);
+                if (!IsScalar(field.value.type.base_type)){
+                    params << "Offset: ";
+                } else {
+                    params << ": ";
+                }
+                params << GenTypeBasic(field.value.type.base_type);
+            }
+
+            GenerateFun(writer, name, params.str(), "Int", [&]() {
+                writer.SetValue("vec_size", NumToString(fields_vec.size()));
+
+                writer += "builder.startTable({{vec_size}})";
+
+                auto sortbysize = struct_def.sortbysize;
+                auto largest = sortbysize ? sizeof(largest_scalar_t) : 1;
+                for (size_t size = largest; size; size /= 2) {
+                    for (auto it = fields_vec.rbegin(); it != fields_vec.rend();
+                         ++it) {
+                        auto &field = **it;
+                        auto base_type_size = SizeOf(field.value.type.base_type);
+                        if (!field.deprecated &&
+                                (!sortbysize || size == base_type_size)) {
+                            writer.SetValue("camel_field_name",
+                                          MakeCamel(Esc(field.name), true));
+                            writer.SetValue("field_name",
+                                          MakeCamel(Esc(field.name), false));
+
+                            writer += "add{{camel_field_name}}(builder, {{field_name}}\\";
+                            if (!IsScalar(field.value.type.base_type)){
+                                writer += "Offset\\";
+                            }
+                            writer += ")";
+                        }
+                    }
+                }
+              writer += "return end{{struct_name}}(builder)";
+            });
+        }
+
+    }
+    void GenerateBufferHasIdentifier(StructDef &struct_def,
+                                     CodeWriter &writer) const {
+        auto file_identifier = parser_.file_identifier_;
+        // Check if a buffer has the identifier.
+        if (parser_.root_struct_def_ != &struct_def || !file_identifier.length())
+            return;
+        auto name = MakeCamel(Esc(struct_def.name), false);
+        GenerateFunOneLine(writer, name + "BufferHasIdentifier",
+                           "_bb: ByteBuffer",
+                           "Boolean",
+                           [&]() {
+            writer += "__has_identifier(_bb, \"" + file_identifier + "\")";
+        });
+    }
+
+    void GenerateStructGetters(StructDef &struct_def, CodeWriter &writer) const {
+        auto fields_vec = struct_def.fields.vec;
+        FieldDef *key_field = nullptr;
+        for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+            auto &field = **it;
+            if (field.deprecated) continue;
+            if (field.key) key_field = &field;
+
+            GenerateComment(field.doc_comment, writer, &comment_config);
+
+            auto field_name = MakeCamel(Esc(field.name), false);
+            auto field_type = GenTypeGet(field.value.type);
+            auto field_default_value = GenDefaultValue(field);
+            auto return_type = GenTypeGet(field.value.type);
+            auto bbgetter = ByteBufferGetter(field.value.type, "bb");
+            auto ucast = CastToUsigned(field);
+            auto offset_val = NumToString(field.value.offset);
+            auto offset_prefix = "val o = __offset(" + offset_val
+                                 + "); return o != 0 ? ";
+            auto value_base_type = field.value.type.base_type;
+            // Most field accessors need to retrieve and test the field offset
+            // first, this is the offset value for that:
+            writer.SetValue("offset", NumToString(field.value.offset));
+            writer.SetValue("return_type", return_type);
+            writer.SetValue("field_type", field_type);
+            writer.SetValue("field_name", field_name);
+            writer.SetValue("field_default", field_default_value);
+            writer.SetValue("bbgetter", bbgetter);
+            writer.SetValue("ucast", ucast);
+
+            auto opt_ret_type = return_type + "?";
+            // Generate the accessors that don't do object reuse.
+            if (value_base_type == BASE_TYPE_STRUCT) {
+                // Calls the accessor that takes an accessor object with a
+                // new object.
+                // val pos
+                //     get() = pos(Vec3())
+                GenerateGetterOneLine(writer, field_name, opt_ret_type, [&](){
+                    writer += "{{field_name}}({{field_type}}())";
+                });
+            } else if (value_base_type == BASE_TYPE_VECTOR &&
+                       field.value.type.element == BASE_TYPE_STRUCT) {
+                // Accessors for vectors of structs also take accessor objects,
+                // this generates a variant without that argument.
+                // ex: fun weapons(j: Int) = weapons(Weapon(), j)
+                GenerateFunOneLine(writer, field_name, "j: Int", opt_ret_type, [&](){
+                    writer += "{{field_name}}({{return_type}}(), j)";
+                });
+            }
+
+            if (IsScalar(value_base_type)) {
+                if (struct_def.fixed) {
+                    GenerateGetterOneLine(writer, field_name, return_type, [&](){
+                        writer += "{{bbgetter}}(bb_pos + {{offset}}){{ucast}}";
+                    });
+                } else {
+                    GenerateGetter(writer, field_name, return_type, [&](){
+                        writer += "val o = __offset({{offset}})";
+                        writer += "return if(o != 0) {{bbgetter}}"
+                                  "(o + bb_pos){{ucast}} else "
+                                  "{{field_default}}";
+                    });
+                }
+            } else {
+                switch (value_base_type) {
+                case BASE_TYPE_STRUCT:
+                    if (struct_def.fixed) {
+                        // create getter with object reuse
+                        // ex:
+                        // fun pos(obj: Vec3) : Vec3? = obj.__assign(bb_pos + 4, bb)
+                        // ? adds nullability annotation
+                        GenerateFunOneLine(writer,
+                                           field_name, "obj: " + field_type ,
+                                           return_type + "?", [&](){
+                            writer += "obj.__assign(bb_pos + {{offset}}, bb)";
+                        });
+                    } else {
+                        // create getter with object reuse
+                        // ex:
+                        //  fun pos(obj: Vec3) : Vec3? {
+                        //      val o = __offset(4)
+                        //      return if(o != 0) {
+                        //          obj.__assign(o + bb_pos, bb)
+                        //      else {
+                        //          null
+                        //      }
+                        //  }
+                        // ? adds nullability annotation
+                        GenerateFun(writer, field_name, "obj: " + field_type,
+                                    return_type + "?", [&](){
+                            auto fixed = field.value.type.struct_def->fixed;
+
+                            writer.SetValue("seek", Indirect("o + bb_pos", fixed));
+                            OffsetWrapper(writer,
+                                          offset_val,
+                                          [&]() { writer += "obj.__assign({{seek}}, bb)"; },
+                                          [&]() { writer += "null"; });
+                        });
+                    }
+                    break;
+                case BASE_TYPE_STRING:
+                    // create string getter
+                    // e.g.
+                    // val Name : String?
+                    //     get() = {
+                    //         val o = __offset(10)
+                    //         return if (o != 0) __string(o + bb_pos) else null
+                    //     }
+                    // ? adds nullability annotation
+                    GenerateGetter(writer, field_name, return_type + "?", [&](){
+
+                        writer += "val o = __offset({{offset}})";
+                        writer += "return if (o != 0) __string(o + bb_pos) else null";
+                    });
+                    break;
+                case BASE_TYPE_VECTOR: {
+                    // e.g.
+                    // fun inventory(j: Int) : UByte {
+                    //     val o = __offset(14)
+                    //     return if (o != 0) {
+                    //         bb.get(__vector(o) + j * 1).toUByte()
+                    //     } else {
+                    //        0
+                    //     }
+                    // }
+
+                    auto vectortype = field.value.type.VectorType();
+                    std::string params = "j: Int";
+                    std::string nullable = IsScalar(vectortype.base_type) ? ""
+                                                                          : "?";
+
+                    if (vectortype.base_type == BASE_TYPE_STRUCT ||
+                            vectortype.base_type == BASE_TYPE_UNION) {
+                        params = "obj: " + field_type + ", j: Int";
+                    }
+
+
+                    writer.SetValue("toType", "YYYYY");
+
+                    auto ret_type = return_type + nullable;
+                    GenerateFun(writer, field_name, params, ret_type, [&](){
+                        auto inline_size = NumToString(InlineSize(vectortype));
+                        auto index = "__vector(o) + j * " + inline_size;
+                        auto not_found = NotFoundReturn(field.value.type.element);
+                        auto found = "";
+                        writer.SetValue("index", index);
+                        switch(vectortype.base_type) {
+                        case BASE_TYPE_STRUCT: {
+                            bool fixed = vectortype.struct_def->fixed;
+                            writer.SetValue("index", Indirect(index, fixed));
+                            found = "obj.__assign({{index}}, bb)";
+                            break;
+                        }
+                        case BASE_TYPE_UNION:
+                            found = "{{bbgetter}}(obj, {{index}} - bb_pos){{ucast}}";
+                            break;
+                        default:
+                            found = "{{bbgetter}}({{index}}){{ucast}}";
+                        }
+                        OffsetWrapper(writer, offset_val,
+                                      [&]() { writer += found; } ,
+                                      [&]() { writer += not_found; });
+                    });
+                    break;
+                }
+                case BASE_TYPE_UNION:
+                    GenerateFun(writer, field_name, "obj: " + field_type,
+                                return_type + "?", [&](){
+                        writer += OffsetWrapperOneLine(offset_val,
+                                                       bbgetter + "(obj, o)",
+                                                       "null");
+                    });
+                    break;
+                default:
+                    FLATBUFFERS_ASSERT(0);
+                }
+            }
+
+            if (value_base_type == BASE_TYPE_VECTOR) {
+                // Generate Lenght functions for vectors
+                GenerateGetter(writer, field_name + "Length", "Int", [&](){
+                    writer += OffsetWrapperOneLine(offset_val,
+                                                   "__vector_len(o)", "0");
+                });
+
+                // See if we should generate a by-key accessor.
+                if (field.value.type.element == BASE_TYPE_STRUCT &&
+                        !field.value.type.struct_def->fixed) {
+                    auto &sd = *field.value.type.struct_def;
+                    auto &fields = sd.fields.vec;
+                    for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+                        auto &kfield = **kit;
+                        if (kfield.key) {
+                            auto qualified_name = WrapInNameSpace(sd);
+                            auto name = MakeCamel(Esc(field.name), false) + "ByKey";
+                            auto params = "key: " + GenTypeGet(kfield.value.type);
+                            auto rtype = qualified_name + "?";
+                            GenerateFun(writer, name, params, rtype, [&] () {
+                                OffsetWrapper(writer, offset_val,
+                                [&] () {
+                                    writer += qualified_name +
+                                    ".__lookup_by_key(null, __vector(o), key, bb)";
+                                },
+                                [&] () {
+                                    writer += "null";
+                                });
+                            });
+
+                            auto param2 = "obj: " + qualified_name +
+                                    ", key: " +
+                                    GenTypeGet(kfield.value.type);
+                            GenerateFun(writer, name, param2, rtype, [&](){
+                                OffsetWrapper(writer, offset_val,
+                                [&] () {
+                                    writer += qualified_name +
+                                    ".__lookup_by_key(obj, __vector(o), key, bb)";
+                                },
+                                [&]() { writer += "null"; });
+                            });
+
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if ((value_base_type == BASE_TYPE_VECTOR &&
+                 IsScalar(field.value.type.VectorType().base_type)) ||
+                    value_base_type == BASE_TYPE_STRING) {
+
+                auto end_idx = NumToString(value_base_type == BASE_TYPE_STRING
+                                           ? 1
+                                           : InlineSize(field.value.type.VectorType()));
+                // Generate a ByteBuffer accessor for strings & vectors of scalars.
+                // e.g.
+                // val inventoryByteBuffer: ByteBuffer
+                //     get =  __vector_as_bytebuffer(14, 1)
+
+                GenerateGetterOneLine(writer, field_name + "AsByteBuffer",
+                                      "ByteBuffer", [&](){
+                    writer.SetValue("end", end_idx);
+                    writer += "__vector_as_bytebuffer({{offset}}, {{end}})";
+                });
+
+                // Generate a ByteBuffer accessor for strings & vectors of scalars.
+                // e.g.
+                // fun inventoryInByteBuffer(_bb: Bytebuffer):
+                //     ByteBuffer = __vector_as_bytebuffer(_bb, 14, 1)
+                GenerateFunOneLine(writer, field_name + "InByteBuffer",
+                                   "_bb: ByteBuffer", "ByteBuffer", [&](){
+                    writer.SetValue("end", end_idx);
+                    writer += "__vector_in_bytebuffer(_bb, {{offset}}, {{end}})";
+                });
+            }
+
+            // generate object accessors if is nested_flatbuffer
+            //fun testnestedflatbufferAsMonster() : Monster?
+            //{ return testnestedflatbufferAsMonster(new Monster()); }
+
+            if (field.nested_flatbuffer) {
+                auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
+                auto nested_method_name =
+                        field_name + "As" +
+                        field.nested_flatbuffer->name;
+
+                GenerateGetterOneLine(writer,
+                                      nested_method_name,
+                                      nested_type_name + "?", [&](){
+                    writer += nested_method_name + "(" + nested_type_name + "())";
+                });
+
+                GenerateFun(writer,
+                            nested_method_name,
+                            "obj: " + nested_type_name,
+                            nested_type_name + "?", [&](){
+                    OffsetWrapper(writer, offset_val,
+                                  [&]() { writer += "obj.__assign(__indirect(__vector(o)), bb)"; },
+                                  [&]() { writer += "null";});
+                });
+            }
+
+            // Generate mutators for scalar fields or vectors of scalars.
+            if (parser_.opts.mutable_buffer) {
+                auto value_type = field.value.type;
+                auto underlying_type = value_base_type == BASE_TYPE_VECTOR
+                        ? value_type.VectorType()
+                        : value_type;
+                auto name = "mutate" + MakeCamel(Esc(field.name), true);
+                auto size = NumToString(InlineSize(underlying_type));
+                auto params = Esc(field.name) + ": " + GenTypeGet(underlying_type);
+                // A vector mutator also needs the index of the vector element it should
+                // mutate.
+                if (value_base_type == BASE_TYPE_VECTOR)
+                    params.insert(0, "j: Int, ");
+
+                // Boolean parameters have to be explicitly converted to byte
+                // representation.
+                auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
+                        ? "(if(" + Esc(field.name) + ") 1 else 0).toByte()"
+                        : Esc(field.name);
+
+                auto setter_index = value_base_type == BASE_TYPE_VECTOR
+                        ? "__vector(o) + j * " + size
+                        : (struct_def.fixed
+                           ? "bb_pos + " + offset_val
+                           : "o + bb_pos");
+                if (IsScalar(value_base_type) || (value_base_type == BASE_TYPE_VECTOR &&
+                         IsScalar(value_type.VectorType().base_type))) {
+
+                    auto statements = [&] () {
+                        writer.SetValue("bbsetter", ByteBufferSetter(underlying_type));
+                        writer.SetValue("index", setter_index);
+                        writer.SetValue("params", setter_parameter);
+                        writer.SetValue("cast", CastToSigned(field));
+                        if (struct_def.fixed) {
+                            writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
+                        } else {
+                            OffsetWrapper(writer, offset_val, [&](){
+                                writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
+                                writer += "true";
+                            }, [&](){ writer += "false";});
+                        }
+                    };
+
+                    if (struct_def.fixed) {
+                        GenerateFunOneLine(writer, name, params, "ByteBuffer",
+                                    statements);
+                    } else {
+                        GenerateFun(writer, name, params, "Boolean",
+                                    statements);
+                    }
+                }
+            }
+        }
+        if (struct_def.has_key && !struct_def.fixed) {
+            // Key Comparison method
+            GenerateOverrideFun(
+                        writer,
+                        "keysCompare",
+                        "o1: Int, o2: Int, _bb: ByteBuffer", "Int", [&]() {
+                if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+                    writer.SetValue("offset", NumToString(key_field->value.offset));
+                    writer += " return compareStrings(__offset({{offset}}, o1, "
+                            "_bb), __offset({{offset}}, o2, _bb), _bb)";
+
+                } else {
+                    auto getter1 = GenLookupByKey(key_field, "_bb", "o1");
+                    auto getter2 = GenLookupByKey(key_field, "_bb", "o2");
+                    writer += "val val_1 = " + getter1;
+                    writer += "val val_2 = " + getter2;
+                    writer += "return (val_1 - val_2).sign";
+                }
+            });
+        }
+    }
+
+    static std::string CastToUsigned(const FieldDef &field) {
+        return CastToUsigned(field.value.type);
+    }
+
+    static std::string CastToUsigned(const Type type) {
+        switch (type.base_type) {
+        case BASE_TYPE_UINT:
+            return ".toUInt()";
+        case BASE_TYPE_UCHAR:
+        case BASE_TYPE_UTYPE:
+            return ".toUByte()";
+        case BASE_TYPE_USHORT:
+            return ".toUShort()";
+        case BASE_TYPE_ULONG:
+            return ".toULong()";
+        case BASE_TYPE_VECTOR:
+            return CastToUsigned(type.VectorType());
+        default:
+            return "";
+        }
+    }
+
+    static std::string CastToSigned(const FieldDef &field) {
+        return CastToSigned(field.value.type);
+    }
+
+    static std::string CastToSigned(const Type type) {
+        switch (type.base_type) {
+        case BASE_TYPE_UINT:
+            return ".toInt()";
+        case BASE_TYPE_UCHAR:
+        case BASE_TYPE_UTYPE:
+            return ".toByte()";
+        case BASE_TYPE_USHORT:
+            return ".toShort()";
+        case BASE_TYPE_ULONG:
+            return ".toLong()";
+        case BASE_TYPE_VECTOR:
+            return CastToSigned(type.VectorType());
+        default:
+            return "";
+        }
+    }
+
+    static std::string LiteralSuffix(const BaseType type) {
+        switch (type) {
+        case BASE_TYPE_UINT:
+        case BASE_TYPE_UCHAR:
+        case BASE_TYPE_UTYPE:
+        case BASE_TYPE_USHORT:
+            return "u";
+        case BASE_TYPE_ULONG:
+            return "UL";
+        case BASE_TYPE_LONG:
+            return "L";
+        default:
+            return "";
+        }
+    }
+
+    void GenerateCompanionObject(CodeWriter &code,
+                                 const std::function<void()> &callback) const {
+        code += "companion object {";
+        code.IncrementIdentLevel();
+        callback();
+        code.DecrementIdentLevel();
+        code += "}";
+    }
+
+    // Generate a documentation comment, if available.
+    void GenerateComment(const std::vector<std::string> &dc, CodeWriter &writer,
+                    const CommentConfig *config) const {
+      if (dc.begin() == dc.end()) {
+        // Don't output empty comment blocks with 0 lines of comment content.
+        return;
+      }
+
+      if (config != nullptr && config->first_line != nullptr) {
+        writer += std::string(config->first_line);
+      }
+      std::string line_prefix =
+          ((config != nullptr && config->content_line_prefix != nullptr)
+               ? config->content_line_prefix
+               : "///");
+      for (auto it = dc.begin(); it != dc.end(); ++it) {
+        writer += line_prefix + *it;
+      }
+      if (config != nullptr && config->last_line != nullptr) {
+        writer += std::string(config->last_line);
+      }
+    }
+
+    static void GenerateGetRootAsAccessors(const std::string &struct_name,
+                                           CodeWriter &writer) {
+        // Generate a special accessor for the table that when used as the root
+        // ex: fun getRootAsMonster(_bb: ByteBuffer): Monster {...}
+        writer.SetValue("gr_name", struct_name);
+        writer.SetValue("gr_method", "getRootAs" + struct_name);
+
+        // create convenience method that doesn't require an existing object
+        writer += "fun {{gr_method}}(_bb: ByteBuffer): {{gr_name}} = \\";
+        writer += "{{gr_method}}(_bb, {{gr_name}}())";
+
+        // create method that allows object reuse
+        // ex: fun Monster getRootAsMonster(_bb: ByteBuffer, obj: Monster) {...}
+        writer += "fun {{gr_method}}"
+                 "(_bb: ByteBuffer, obj: {{gr_name}}): {{gr_name}} {";
+        writer.IncrementIdentLevel();
+        writer += "_bb.order(ByteOrder.LITTLE_ENDIAN)";
+        writer += "return (obj.__assign(_bb.getInt(_bb.position())"
+                 " + _bb.position(), _bb))";
+        writer.DecrementIdentLevel();
+        writer += "}";
+    }
+
+    static void GenerateStaticConstructor(const StructDef &struct_def,
+                                          CodeWriter &code) {
+        // create a struct constructor function
+        auto params = StructConstructorParams(struct_def);
+        GenerateFun(code, "create" + Esc(struct_def.name), params, "Int", [&](){
+            GenStructBody(struct_def, code, "");
+            code += "return builder.offset()";
+        });
+    }
+
+    static std::string StructConstructorParams(const StructDef &struct_def,
+                                               const std::string &prefix = "") {
+        //builder: FlatBufferBuilder
+        std::stringstream out;
+        auto field_vec = struct_def.fields.vec;
+        if (prefix.empty()) {
+            out << "builder: FlatBufferBuilder";
+        }
+        for (auto it = field_vec.begin(); it != field_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.
+                out << StructConstructorParams(*field.value.type.struct_def,
+                                              prefix + (Esc(field.name) + "_"));
+            } else {
+                out << ", " << prefix << MakeCamel(Esc(field.name), false)
+                    << ": "
+                    << GenTypeBasic(field.value.type.base_type);
+            }
+        }
+        return out.str();
+    }
+
+    static void GeneratePropertyOneLine(CodeWriter &writer,
+                               const std::string &name,
+                               const std::string &type,
+                               const std::function<void()> &body) {
+        // Generates Kotlin getter for properties
+        // e.g.:
+        // val prop: Mytype = x
+        writer.SetValue("_name", name);
+        writer.SetValue("_type", type);
+        writer += "val {{_name}} : {{_type}} = \\";
+        body();
+    }
+    static void GenerateGetterOneLine(CodeWriter &writer,
+                               const std::string &name,
+                               const std::string &type,
+                               const std::function<void()> &body) {
+        // Generates Kotlin getter for properties
+        // e.g.:
+        // val prop: Mytype get() = x
+        writer.SetValue("_name", name);
+        writer.SetValue("_type", type);
+        writer += "val {{_name}} : {{_type}} get() = \\";
+        body();
+    }
+
+    static void GenerateGetter(CodeWriter &writer,
+                               const std::string &name,
+                               const std::string &type,
+                               const std::function<void()> &body) {
+        // Generates Kotlin getter for properties
+        // e.g.:
+        // val prop: Mytype
+        //     get() = {
+        //       return x
+        //     }
+        writer.SetValue("name", name);
+        writer.SetValue("type", type);
+        writer += "val {{name}} : {{type}}";
+        writer.IncrementIdentLevel();
+        writer += "get() {";
+        writer.IncrementIdentLevel();
+        body();
+        writer.DecrementIdentLevel();
+        writer += "}";
+        writer.DecrementIdentLevel();
+    }
+
+    static void GenerateFun(CodeWriter &writer,
+                            const std::string &name,
+                            const std::string &params,
+                            const std::string &returnType,
+                            const std::function<void()> &body) {
+        // Generates Kotlin function
+        // e.g.:
+        // fun path(j: Int): Vec3 {
+        //     return path(Vec3(), j)
+        // }
+        auto noreturn = returnType.empty();
+        writer.SetValue("name", name);
+        writer.SetValue("params", params);
+        writer.SetValue("return_type", noreturn ? "" : ": " + returnType);
+        writer += "fun {{name}}({{params}}) {{return_type}} {";
+        writer.IncrementIdentLevel();
+        body();
+        writer.DecrementIdentLevel();
+        writer += "}";
+    }
+
+    static void GenerateFunOneLine(CodeWriter &writer,
+                                   const std::string &name,
+                                   const std::string &params,
+                                   const std::string &returnType,
+                                   const std::function<void()> &body) {
+        // Generates Kotlin function
+        // e.g.:
+        // fun path(j: Int): Vec3 = return path(Vec3(), j)
+        writer.SetValue("name", name);
+        writer.SetValue("params", params);
+        writer.SetValue("return_type_p", returnType.empty() ? "" :
+                                                          " : " + returnType);
+        writer += "fun {{name}}({{params}}){{return_type_p}} = \\";
+        body();
+    }
+
+    static void GenerateOverrideFun(CodeWriter &writer,
+                                   const std::string &name,
+                                   const std::string &params,
+                                   const std::string &returnType,
+                                   const std::function<void()> &body) {
+        // Generates Kotlin function
+        // e.g.:
+        // override fun path(j: Int): Vec3 = return path(Vec3(), j)
+        writer += "override \\";
+        GenerateFun(writer, name, params, returnType, body);
+    }
+
+    static void GenerateOverrideFunOneLine(CodeWriter &writer,
+                                   const std::string &name,
+                                   const std::string &params,
+                                   const std::string &returnType,
+                                   const std::string &statement) {
+        // Generates Kotlin function
+        // e.g.:
+        // override fun path(j: Int): Vec3 = return path(Vec3(), j)
+        writer.SetValue("name", name);
+        writer.SetValue("params", params);
+        writer.SetValue("return_type", returnType.empty() ? "" :
+                                                          " : " + returnType);
+        writer += "override fun {{name}}({{params}}){{return_type}} = \\";
+        writer += statement;
+    }
+
+    static std::string OffsetWrapperOneLine(const std::string &offset,
+                                            const std::string &found,
+                                            const std::string &not_found) {
+        return "val o = __offset(" + offset + "); return if (o != 0) " + found +
+                " else " + not_found;
+    }
+
+    static void OffsetWrapper(CodeWriter &code,
+                       const std::string &offset,
+                       const std::function<void()> &found,
+                       const std::function<void()> &not_found) {
+        code += "val o = __offset(" + offset + ")";
+        code +="return if (o != 0) {";
+        code.IncrementIdentLevel();
+        found();
+        code.DecrementIdentLevel();
+        code += "} else {";
+        code.IncrementIdentLevel();
+        not_found();
+        code.DecrementIdentLevel();
+        code += "}";
+    }
+
+    static std::string Indirect(const std::string &index, bool fixed) {
+        // We apply __indirect() and struct is not fixed.
+        if (!fixed)
+            return "__indirect(" + index + ")";
+        return index;
+    }
+
+    static std::string NotFoundReturn(BaseType el) {
+        switch (el) {
+        case BASE_TYPE_FLOAT:
+           return "0.0f";
+         case BASE_TYPE_DOUBLE:
+            return "0.0";
+        case BASE_TYPE_BOOL:
+            return "false";
+        case BASE_TYPE_LONG:
+        case BASE_TYPE_INT:
+        case BASE_TYPE_CHAR:
+        case BASE_TYPE_SHORT:
+            return "0";
+        case BASE_TYPE_UINT:
+        case BASE_TYPE_UCHAR:
+        case BASE_TYPE_USHORT:
+        case BASE_TYPE_UTYPE:
+            return "0u";
+        case BASE_TYPE_ULONG:
+            return "0uL";
+        default:
+            return "null";
+        }
+    }
+
+    // This tracks the current namespace used to determine if a type need to be
+    // prefixed by its namespace
+    const Namespace *cur_name_space_;
+};
+}  // namespace kotlin
+
+bool GenerateKotlin(const Parser &parser, const std::string &path,
+                    const std::string &file_name) {
+    kotlin::KotlinGenerator generator(parser, path, file_name);
+    return generator.generate();
+}
+}  // namespace flatbuffers
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
diff --git a/src/idl_gen_lua.cpp b/src/idl_gen_lua.cpp
new file mode 100644
index 0000000..10df231
--- /dev/null
+++ b/src/idl_gen_lua.cpp
@@ -0,0 +1,731 @@
+/*
+ * Copyright 2014 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.
+ */
+
+ // independent from idl_parser, since this code is not needed for most clients
+
+#include <string>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#include <unordered_set>
+
+namespace flatbuffers {
+namespace lua {
+
+  // Hardcode spaces per indentation.
+  const CommentConfig def_comment = { nullptr, "--", nullptr };
+  const char * Indent = "    ";
+  const char * Comment = "-- ";
+  const char * End = "end\n";
+  const char * EndFunc = "end\n";
+  const char * SelfData = "self.view";
+  const char * SelfDataPos = "self.view.pos";
+  const char * SelfDataBytes = "self.view.bytes";
+
+  class LuaGenerator : public BaseGenerator {
+  public:
+    LuaGenerator(const Parser &parser, const std::string &path,
+      const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "" /* not used */,
+        "" /* not used */) {
+      static const char * const keywords[] = {
+        "and",
+        "break",
+        "do",
+        "else",
+        "elseif",
+        "end",
+        "false",
+        "for",
+        "function",
+        "goto",
+        "if",
+        "in",
+        "local",
+        "nil",
+        "not",
+        "or",
+        "repeat",
+        "return",
+        "then",
+        "true",
+        "until",
+        "while"
+      };
+      keywords_.insert(std::begin(keywords), std::end(keywords));
+    }
+
+    // Most field accessors need to retrieve and test the field offset first,
+    // this is the prefix code for that.
+    std::string OffsetPrefix(const FieldDef &field) {
+      return std::string(Indent) +
+        "local o = " + SelfData + ":Offset(" + NumToString(field.value.offset) + ")\n" +
+        Indent + "if o ~= 0 then\n";
+    }
+
+    // Begin a class declaration.
+    void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      code += "local " + NormalizedName(struct_def) + " = {} -- the module\n";
+      code += "local " + NormalizedMetaName(struct_def) + " = {} -- the class metatable\n";
+      code += "\n";
+    }
+
+    // Begin enum code with a class declaration.
+    void BeginEnum(const std::string &class_name, std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      code += "local " + class_name + " = {\n";
+    }
+
+    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 NormalizedMetaName(const Definition &definition) const {
+      return EscapeKeyword(definition.name) + "_mt";
+    }
+
+    // A single enum member.
+    void EnumMember(const EnumDef &enum_def, const EnumVal &ev, std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      code += std::string(Indent) + NormalizedName(ev) + " = " +
+              enum_def.ToString(ev) + ",\n";
+    }
+
+    // End enum code.
+    void EndEnum(std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      code += "}\n";
+    }
+
+    void GenerateNewObjectPrototype(const StructDef &struct_def,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+
+      code += "function " + NormalizedName(struct_def) + ".New()\n";
+      code += std::string(Indent) + "local o = {}\n";
+      code += std::string(Indent) + "setmetatable(o, {__index = " + NormalizedMetaName(struct_def) + "})\n";
+      code += std::string(Indent) + "return o\n";
+      code += EndFunc;
+    }
+
+    // Initialize a new struct or table from existing data.
+    void NewRootTypeFromBuffer(const StructDef &struct_def,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+
+      code += "function " + NormalizedName(struct_def) + ".GetRootAs" + NormalizedName(struct_def) + "(buf, offset)\n";
+      code += std::string(Indent) + "local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)\n";
+      code += std::string(Indent) + "local o = " + NormalizedName(struct_def) + ".New()\n";
+      code += std::string(Indent) + "o:Init(buf, n + offset)\n";
+      code += std::string(Indent) + "return o\n";
+      code += EndFunc;
+    }
+
+    // Initialize an existing object with other data, to avoid an allocation.
+    void InitializeExisting(const StructDef &struct_def,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+
+      GenReceiver(struct_def, code_ptr);
+      code += "Init(buf, pos)\n";
+      code += std::string(Indent) + SelfData + " = flatbuffers.view.New(buf, pos)\n";
+      code += EndFunc;
+    }
+
+    // Get the length of a vector.
+    void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+
+      GenReceiver(struct_def, code_ptr);
+      code += MakeCamel(NormalizedName(field)) + "Length()\n";
+      code += OffsetPrefix(field);
+      code += std::string(Indent) + Indent + "return " + SelfData + ":VectorLen(o)\n";
+      code += std::string(Indent) + End;
+      code += std::string(Indent) + "return 0\n";
+      code += EndFunc;
+    }
+
+    // Get the value of a struct's scalar.
+    void GetScalarFieldOfStruct(const StructDef &struct_def,
+      const FieldDef &field,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      std::string getter = GenGetter(field.value.type);
+      GenReceiver(struct_def, code_ptr);
+      code += MakeCamel(NormalizedName(field));
+      code += "()\n";
+      code += std::string(Indent) + "return " + getter;
+      code += std::string(SelfDataPos) + " + " + NumToString(field.value.offset) + ")\n";
+      code += EndFunc;
+    }
+
+    // Get the value of a table's scalar.
+    void GetScalarFieldOfTable(const StructDef &struct_def,
+      const FieldDef &field,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      std::string getter = GenGetter(field.value.type);
+      GenReceiver(struct_def, code_ptr);
+      code += MakeCamel(NormalizedName(field));
+      code += "()\n";
+      code += OffsetPrefix(field);
+      getter += std::string("o + ") + SelfDataPos + ")";
+      auto is_bool = field.value.type.base_type == BASE_TYPE_BOOL;
+      if (is_bool) {
+        getter = "(" + getter + " ~= 0)";
+      }
+      code += std::string(Indent) + Indent + "return " + getter + "\n";
+      code += std::string(Indent) + End;
+      std::string default_value;
+      if (is_bool) {
+        default_value = field.value.constant == "0" ? "false" : "true";
+      }
+      else {
+        default_value = field.value.constant;
+      }
+      code += std::string(Indent) + "return " + default_value + "\n";
+      code += EndFunc;
+    }
+
+    // Get a struct by initializing an existing struct.
+    // Specific to Struct.
+    void GetStructFieldOfStruct(const StructDef &struct_def,
+      const FieldDef &field,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      GenReceiver(struct_def, code_ptr);
+      code += MakeCamel(NormalizedName(field));
+      code += "(obj)\n";
+      code += std::string(Indent) + "obj:Init(" + SelfDataBytes + ", " + SelfDataPos + " + ";
+      code += NumToString(field.value.offset) + ")\n";
+      code += std::string(Indent) + "return obj\n";
+      code += EndFunc;
+    }
+
+    // Get a struct by initializing an existing struct.
+    // Specific to Table.
+    void GetStructFieldOfTable(const StructDef &struct_def,
+      const FieldDef &field,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      GenReceiver(struct_def, code_ptr);
+      code += MakeCamel(NormalizedName(field));
+      code += "()\n";
+      code += OffsetPrefix(field);
+      if (field.value.type.struct_def->fixed) {
+        code += std::string(Indent) + Indent + "local x = o + " + SelfDataPos + "\n";
+      }
+      else {
+        code += std::string(Indent) + Indent + "local x = " + SelfData + ":Indirect(o + " + SelfDataPos + ")\n";
+      }
+      code += std::string(Indent) + Indent + "local obj = require('" + TypeNameWithNamespace(field) + "').New()\n";
+      code += std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
+      code += std::string(Indent) + Indent + "return obj\n";
+      code += std::string(Indent) + End;
+      code += EndFunc;
+    }
+
+    // Get the value of a string.
+    void GetStringField(const StructDef &struct_def, const FieldDef &field,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      GenReceiver(struct_def, code_ptr);
+      code += MakeCamel(NormalizedName(field));
+      code += "()\n";
+      code += OffsetPrefix(field);
+      code += std::string(Indent) + Indent + "return " + GenGetter(field.value.type);
+      code += std::string("o + ") + SelfDataPos + ")\n";
+      code += std::string(Indent) + End;
+      code += EndFunc;
+    }
+
+    // Get the value of a union from an object.
+    void GetUnionField(const StructDef &struct_def, const FieldDef &field,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      GenReceiver(struct_def, code_ptr);
+      code += MakeCamel(NormalizedName(field)) + "()\n";
+      code += OffsetPrefix(field);
+
+      // TODO(rw): this works and is not the good way to it:
+      //bool is_native_table = TypeName(field) == "*flatbuffers.Table";
+      //if (is_native_table) {
+      //  code += std::string(Indent) + Indent + "from flatbuffers.table import Table\n";
+      //} else {
+      //  code += std::string(Indent) + Indent +
+      //  code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
+      //}
+      code += std::string(Indent) + Indent + "local obj = flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)\n";
+      code += std::string(Indent) + Indent + GenGetter(field.value.type) + "obj, o)\n";
+      code += std::string(Indent) + Indent + "return obj\n";
+      code += std::string(Indent) + End;
+      code += EndFunc;
+    }
+
+    // Get the value of a vector's struct member.
+    void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+      const FieldDef &field,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      auto vectortype = field.value.type.VectorType();
+
+      GenReceiver(struct_def, code_ptr);
+      code += MakeCamel(NormalizedName(field));
+      code += "(j)\n";
+      code += OffsetPrefix(field);
+      code += std::string(Indent) + Indent + "local x = " + SelfData + ":Vector(o)\n";
+      code += std::string(Indent) + Indent + "x = x + ((j-1) * ";
+      code += NumToString(InlineSize(vectortype)) + ")\n";
+      if (!(vectortype.struct_def->fixed)) {
+        code += std::string(Indent) + Indent + "x = " + SelfData + ":Indirect(x)\n";
+      }
+      code += std::string(Indent) + Indent + "local obj = require('" + TypeNameWithNamespace(field) + "').New()\n";
+      code += std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
+      code += std::string(Indent) + Indent + "return obj\n";
+      code += std::string(Indent) + End;
+      code += EndFunc;
+    }
+
+    // Get the value of a vector's non-struct member. Uses a named return
+    // argument to conveniently set the zero value for the result.
+    void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
+      const FieldDef &field,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      auto vectortype = field.value.type.VectorType();
+
+      GenReceiver(struct_def, code_ptr);
+      code += MakeCamel(NormalizedName(field));
+      code += "(j)\n";
+      code += OffsetPrefix(field);
+      code += std::string(Indent) + Indent + "local a = " + SelfData + ":Vector(o)\n";
+      code += std::string(Indent) + Indent;
+      code += "return " + GenGetter(field.value.type);
+      code += "a + ((j-1) * ";
+      code += NumToString(InlineSize(vectortype)) + "))\n";
+      code += std::string(Indent) + End;
+      if (vectortype.base_type == BASE_TYPE_STRING) {
+        code += std::string(Indent) + "return ''\n";
+      }
+      else {
+        code += std::string(Indent) + "return 0\n";
+      }
+      code += EndFunc;
+    }
+
+    // Begin the creator function signature.
+    void BeginBuilderArgs(const StructDef &struct_def,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+
+      code += "function " + NormalizedName(struct_def) + ".Create" + NormalizedName(struct_def);
+      code += "(builder";
+    }
+
+    // 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 += std::string(", ") + nameprefix;
+          code += MakeCamel(NormalizedName(field), false);
+        }
+      }
+    }
+
+    // End the creator function signature.
+    void EndBuilderArgs(std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      code += ")\n";
+    }
+
+    // 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 += std::string(Indent) + "builder:Prep(" + NumToString(struct_def.minalign) + ", ";
+      code += 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 += std::string(Indent) + "builder: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 += std::string(Indent) + "builder:Prepend" + GenMethod(field) + "(";
+          code += nameprefix + MakeCamel(NormalizedName(field), false) + ")\n";
+        }
+      }
+    }
+
+    void EndBuilderBody(std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      code += std::string(Indent) + "return builder:Offset()\n";
+      code += EndFunc;
+    }
+
+    // Get the value of a table's starting offset.
+    void GetStartOfTable(const StructDef &struct_def,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      code += "function " + NormalizedName(struct_def) + ".Start";
+      code += "(builder) ";
+      code += "builder:StartObject(";
+      code += NumToString(struct_def.fields.vec.size());
+      code += ") end\n";
+    }
+
+    // Set the value of a table's field.
+    void BuildFieldOfTable(const StructDef &struct_def,
+      const FieldDef &field, const size_t offset,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      code += "function " + NormalizedName(struct_def) + ".Add" + MakeCamel(NormalizedName(field));
+      code += "(builder, ";
+      code += MakeCamel(NormalizedName(field), false);
+      code += ") ";
+      code += "builder:Prepend";
+      code += GenMethod(field) + "Slot(";
+      code += NumToString(offset) + ", ";
+      // todo: i don't need to cast in Lua, but am I missing something?
+    //    if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
+    //      code += "flatbuffers.N.UOffsetTFlags.py_type";
+    //      code += "(";
+    //      code += MakeCamel(NormalizedName(field), false) + ")";
+    //    } else {
+      code += MakeCamel(NormalizedName(field), false);
+      //    }
+      code += ", " + field.value.constant;
+      code += ") end\n";
+    }
+
+    // Set the value of one of the members of a table's vector.
+    void BuildVectorOfTable(const StructDef &struct_def,
+      const FieldDef &field, std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      code += "function " + NormalizedName(struct_def) + ".Start";
+      code += MakeCamel(NormalizedName(field));
+      code += "Vector(builder, numElems) return builder:StartVector(";
+      auto vector_type = field.value.type.VectorType();
+      auto alignment = InlineAlignment(vector_type);
+      auto elem_size = InlineSize(vector_type);
+      code += NumToString(elem_size);
+      code += ", numElems, " + NumToString(alignment);
+      code += ") end\n";
+    }
+
+    // Get the offset of the end of a table.
+    void GetEndOffsetOnTable(const StructDef &struct_def,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      code += "function " + NormalizedName(struct_def) + ".End";
+      code += "(builder) ";
+      code += "return builder:EndObject() end\n";
+    }
+
+    // Generate the receiver for function signatures.
+    void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      code += "function " + NormalizedMetaName(struct_def) + ":";
+    }
+
+    // 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, &def_comment);
+      if (IsScalar(field.value.type.base_type)) {
+        if (struct_def.fixed) {
+          GetScalarFieldOfStruct(struct_def, field, code_ptr);
+        }
+        else {
+          GetScalarFieldOfTable(struct_def, field, code_ptr);
+        }
+      }
+      else {
+        switch (field.value.type.base_type) {
+        case BASE_TYPE_STRUCT:
+          if (struct_def.fixed) {
+            GetStructFieldOfStruct(struct_def, field, code_ptr);
+          }
+          else {
+            GetStructFieldOfTable(struct_def, field, code_ptr);
+          }
+          break;
+        case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break;
+        case BASE_TYPE_VECTOR: {
+          auto vectortype = field.value.type.VectorType();
+          if (vectortype.base_type == BASE_TYPE_STRUCT) {
+            GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
+          }
+          else {
+            GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
+          }
+          break;
+        }
+        case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
+        default: FLATBUFFERS_ASSERT(0);
+        }
+      }
+      if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+        GetVectorLen(struct_def, field, code_ptr);
+      }
+    }
+
+    // Generate table constructors, conditioned on its members' types.
+    void GenTableBuilders(const StructDef &struct_def,
+      std::string *code_ptr) {
+      GetStartOfTable(struct_def, code_ptr);
+
+      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();
+        BuildFieldOfTable(struct_def, field, offset, code_ptr);
+        if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+          BuildVectorOfTable(struct_def, field, code_ptr);
+        }
+      }
+
+      GetEndOffsetOnTable(struct_def, code_ptr);
+    }
+
+    // Generate struct or table methods.
+    void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+      if (struct_def.generated) return;
+
+      GenComment(struct_def.doc_comment, code_ptr, &def_comment);
+      BeginClass(struct_def, code_ptr);
+
+      GenerateNewObjectPrototype(struct_def, code_ptr);
+
+      if (!struct_def.fixed) {
+        // Generate a special accessor for the table that has been declared as
+        // the root type.
+        NewRootTypeFromBuffer(struct_def, code_ptr);
+      }
+
+      // Generate the Init method that sets the field in a pre-existing
+      // accessor object. This is to allow object reuse.
+      InitializeExisting(struct_def, code_ptr);
+      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);
+      }
+
+      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;
+
+      GenComment(enum_def.doc_comment, code_ptr, &def_comment);
+      BeginEnum(NormalizedName(enum_def), code_ptr);
+      for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+           ++it) {
+        auto &ev = **it;
+        GenComment(ev.doc_comment, code_ptr, &def_comment, Indent);
+        EnumMember(enum_def, ev, code_ptr);
+      }
+      EndEnum(code_ptr);
+    }
+
+    // Returns the function name that is able to read a value of the given type.
+    std::string GenGetter(const Type &type) {
+      switch (type.base_type) {
+      case BASE_TYPE_STRING: return std::string(SelfData) + ":String(";
+      case BASE_TYPE_UNION: return  std::string(SelfData) + ":Union(";
+      case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+      default:
+        return std::string(SelfData) + ":Get(flatbuffers.N." +
+          MakeCamel(GenTypeGet(type)) + ", ";
+      }
+    }
+
+    // Returns the method name for use with add/put calls.
+    std::string GenMethod(const FieldDef &field) {
+      return IsScalar(field.value.type.base_type)
+        ? MakeCamel(GenTypeBasic(field.value.type))
+        : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
+    }
+
+    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];
+    }
+
+    std::string GenTypePointer(const Type &type) {
+      switch (type.base_type) {
+      case BASE_TYPE_STRING: return "string";
+      case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+      case BASE_TYPE_STRUCT: return type.struct_def->name;
+      case BASE_TYPE_UNION:
+        // fall through
+      default: return "*flatbuffers.Table";
+      }
+    }
+
+    std::string GenTypeGet(const Type &type) {
+      return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+    }
+
+    std::string GetNamespace(const Type &type) {
+      return type.struct_def->defined_namespace->GetFullyQualifiedName(type.struct_def->name);
+    }
+
+    std::string TypeName(const FieldDef &field) {
+      return GenTypeGet(field.value.type);
+    }
+
+    std::string TypeNameWithNamespace(const FieldDef &field) {
+      return GetNamespace(field.value.type);
+    }
+
+    // Create a struct with a builder and the struct's arguments.
+    void GenStructBuilder(const StructDef &struct_def,
+      std::string *code_ptr) {
+      BeginBuilderArgs(struct_def, code_ptr);
+      StructBuilderArgs(struct_def, "", code_ptr);
+      EndBuilderArgs(code_ptr);
+
+      StructBuilderBody(struct_def, "", code_ptr);
+      EndBuilderBody(code_ptr);
+    }
+
+    bool generate() {
+      if (!generateEnums()) return false;
+      if (!generateStructs()) return false;
+      return true;
+    }
+
+  private:
+    bool generateEnums() {
+      for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+        ++it) {
+        auto &enum_def = **it;
+        std::string enumcode;
+        GenEnum(enum_def, &enumcode);
+        if (!SaveType(enum_def, enumcode, false)) return false;
+      }
+      return true;
+    }
+
+    bool generateStructs() {
+      for (auto it = parser_.structs_.vec.begin();
+        it != parser_.structs_.vec.end(); ++it) {
+        auto &struct_def = **it;
+        std::string declcode;
+        GenStruct(struct_def, &declcode);
+        if (!SaveType(struct_def, declcode, true)) return false;
+      }
+      return true;
+    }
+
+    // Begin by declaring namespace and imports.
+    void BeginFile(const std::string &name_space_name, const bool needs_imports,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      code += std::string(Comment) + FlatBuffersGeneratedWarning() + "\n\n";
+      code += std::string(Comment) + "namespace: " + name_space_name + "\n\n";
+      if (needs_imports) {
+        code += "local flatbuffers = require('flatbuffers')\n\n";
+      }
+    }
+
+    // Save out the generated code for a Lua Table type.
+    bool SaveType(const Definition &def, const std::string &classcode,
+      bool needs_imports) {
+      if (!classcode.length()) return true;
+
+      std::string namespace_dir = path_;
+      auto &namespaces = def.defined_namespace->components;
+      for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+        if (it != namespaces.begin()) namespace_dir += kPathSeparator;
+        namespace_dir += *it;
+        //std::string init_py_filename = namespace_dir + "/__init__.py";
+        //SaveFile(init_py_filename.c_str(), "", false);
+      }
+
+      std::string code = "";
+      BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
+      code += classcode;
+      code += "\n";
+      code += "return " + NormalizedName(def) + " " + Comment + "return the module";
+      std::string filename =
+        NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".lua";
+      return SaveFile(filename.c_str(), code, false);
+    }
+  private:
+    std::unordered_set<std::string> keywords_;
+  };
+
+}  // namespace lua
+
+bool GenerateLua(const Parser &parser, const std::string &path,
+  const std::string &file_name) {
+  lua::LuaGenerator generator(parser, path, file_name);
+  return generator.generate();
+}
+
+}  // namespace flatbuffers
diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp
new file mode 100644
index 0000000..9d81415
--- /dev/null
+++ b/src/idl_gen_php.cpp
@@ -0,0 +1,940 @@
+/*
+ * Copyright 2014 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.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include <string>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+namespace php {
+// Hardcode spaces per indentation.
+const std::string Indent = "    ";
+class PhpGenerator : public BaseGenerator {
+ public:
+  PhpGenerator(const Parser &parser, const std::string &path,
+               const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "\\", "\\") {}
+  bool generate() {
+    if (!GenerateEnums()) return false;
+    if (!GenerateStructs()) return false;
+    return true;
+  }
+
+ private:
+  bool GenerateEnums() {
+    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+         ++it) {
+      auto &enum_def = **it;
+      std::string enumcode;
+      GenEnum(enum_def, &enumcode);
+      if (!SaveType(enum_def, enumcode, false)) return false;
+    }
+    return true;
+  }
+
+  bool GenerateStructs() {
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      auto &struct_def = **it;
+      std::string declcode;
+      GenStruct(struct_def, &declcode);
+      if (!SaveType(struct_def, declcode, true)) return false;
+    }
+    return true;
+  }
+
+  // Begin by declaring namespace and imports.
+  void BeginFile(const std::string &name_space_name, const bool needs_imports,
+                 std::string *code_ptr) {
+    auto &code = *code_ptr;
+    code += "<?php\n";
+    code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
+
+    if (!name_space_name.empty()) {
+      code += "namespace " + name_space_name + ";\n\n";
+    }
+
+    if (needs_imports) {
+      code += "use \\Google\\FlatBuffers\\Struct;\n";
+      code += "use \\Google\\FlatBuffers\\Table;\n";
+      code += "use \\Google\\FlatBuffers\\ByteBuffer;\n";
+      code += "use \\Google\\FlatBuffers\\FlatBufferBuilder;\n";
+      code += "\n";
+    }
+  }
+
+  // Save out the generated code for a Php Table type.
+  bool SaveType(const Definition &def, const std::string &classcode,
+                bool needs_imports) {
+    if (!classcode.length()) return true;
+
+    std::string code = "";
+    BeginFile(FullNamespace("\\", *def.defined_namespace), needs_imports,
+              &code);
+    code += classcode;
+
+    std::string filename =
+        NamespaceDir(*def.defined_namespace) + def.name + ".php";
+    return SaveFile(filename.c_str(), code, false);
+  }
+
+  // Begin a class declaration.
+  static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    if (struct_def.fixed) {
+      code += "class " + struct_def.name + " extends Struct\n";
+    } else {
+      code += "class " + struct_def.name + " extends Table\n";
+    }
+    code += "{\n";
+  }
+
+  static void EndClass(std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "}\n";
+  }
+
+  // Begin enum code with a class declaration.
+  static void BeginEnum(const std::string &class_name, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "class " + class_name + "\n{\n";
+  }
+
+  // A single enum member.
+  static void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
+                         std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += Indent + "const ";
+    code += ev.name;
+    code += " = ";
+    code += enum_def.ToString(ev) + ";\n";
+  }
+
+  // End enum code.
+  static void EndEnum(std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "}\n";
+  }
+
+  // Initialize a new struct or table from existing data.
+  static void NewRootTypeFromBuffer(const StructDef &struct_def,
+                                    std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += Indent + "/**\n";
+    code += Indent + " * @param ByteBuffer $bb\n";
+    code += Indent + " * @return " + struct_def.name + "\n";
+    code += Indent + " */\n";
+    code += Indent + "public static function getRootAs";
+    code += struct_def.name;
+    code += "(ByteBuffer $bb)\n";
+    code += Indent + "{\n";
+
+    code += Indent + Indent + "$obj = new " + struct_def.name + "();\n";
+    code += Indent + Indent;
+    code += "return ($obj->init($bb->getInt($bb->getPosition())";
+    code += " + $bb->getPosition(), $bb));\n";
+    code += Indent + "}\n\n";
+  }
+
+  // Initialize an existing object with other data, to avoid an allocation.
+  static void InitializeExisting(const StructDef &struct_def,
+                                 std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += Indent + "/**\n";
+    code += Indent + " * @param int $_i offset\n";
+    code += Indent + " * @param ByteBuffer $_bb\n";
+    code += Indent + " * @return " + struct_def.name + "\n";
+    code += Indent + " **/\n";
+    code += Indent + "public function init($_i, ByteBuffer $_bb)\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$this->bb_pos = $_i;\n";
+    code += Indent + Indent + "$this->bb = $_bb;\n";
+    code += Indent + Indent + "return $this;\n";
+    code += Indent + "}\n\n";
+  }
+
+  // Get the length of a vector.
+  static void GetVectorLen(const FieldDef &field, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += Indent + "/**\n";
+    code += Indent + " * @return int\n";
+    code += Indent + " */\n";
+    code += Indent + "public function get";
+    code += MakeCamel(field.name) + "Length()\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$o = $this->__offset(";
+    code += NumToString(field.value.offset) + ");\n";
+    code += Indent + Indent;
+    code += "return $o != 0 ? $this->__vector_len($o) : 0;\n";
+    code += Indent + "}\n\n";
+  }
+
+  // Get a [ubyte] vector as a byte array.
+  static void GetUByte(const FieldDef &field, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += Indent + "/**\n";
+    code += Indent + " * @return string\n";
+    code += Indent + " */\n";
+    code += Indent + "public function get";
+    code += MakeCamel(field.name) + "Bytes()\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "return $this->__vector_as_bytes(";
+    code += NumToString(field.value.offset) + ");\n";
+    code += Indent + "}\n\n";
+  }
+
+  // Get the value of a struct's scalar.
+  static void GetScalarFieldOfStruct(const FieldDef &field,
+                                     std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    std::string getter = GenGetter(field.value.type);
+
+    code += Indent + "/**\n";
+    code += Indent + " * @return ";
+    code += GenTypeGet(field.value.type) + "\n";
+    code += Indent + " */\n";
+    code += Indent + "public function " + getter;
+    code += MakeCamel(field.name) + "()\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "return ";
+
+    code += "$this->bb->get";
+    code += MakeCamel(GenTypeGet(field.value.type));
+    code += "($this->bb_pos + ";
+    code += NumToString(field.value.offset) + ")";
+    code += ";\n";
+
+    code += Indent + "}\n\n";
+  }
+
+  // Get the value of a table's scalar.
+  void GetScalarFieldOfTable(const FieldDef &field, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += Indent + "/**\n";
+    code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+    code += Indent + " */\n";
+    code += Indent + "public function get";
+    code += MakeCamel(field.name);
+    code += "()\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$o = $this->__offset(" +
+            NumToString(field.value.offset) + ");\n" + Indent + Indent +
+            "return $o != 0 ? ";
+    code += "$this->bb->get";
+    code += MakeCamel(GenTypeGet(field.value.type)) + "($o + $this->bb_pos)";
+    code += " : " + GenDefaultValue(field.value) + ";\n";
+    code += Indent + "}\n\n";
+  }
+
+  // Get a struct by initializing an existing struct.
+  // Specific to Struct.
+  void GetStructFieldOfStruct(const FieldDef &field, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += Indent + "/**\n";
+    code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+    code += Indent + " */\n";
+    code += Indent + "public function get";
+    code += MakeCamel(field.name) + "()\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$obj = new ";
+    code += GenTypeGet(field.value.type) + "();\n";
+    code += Indent + Indent + "$obj->init($this->bb_pos + ";
+    code += NumToString(field.value.offset) + ", $this->bb);";
+    code += "\n" + Indent + Indent + "return $obj;\n";
+    code += Indent + "}\n\n";
+  }
+
+  // Get a struct by initializing an existing struct.
+  // Specific to Table.
+  void GetStructFieldOfTable(const FieldDef &field, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += Indent + "public function get";
+    code += MakeCamel(field.name);
+    code += "()\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$obj = new ";
+    code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
+    code += Indent + Indent + "$o = $this->__offset(" +
+            NumToString(field.value.offset) + ");\n";
+    code += Indent + Indent;
+    code += "return $o != 0 ? $obj->init(";
+    if (field.value.type.struct_def->fixed) {
+      code += "$o + $this->bb_pos, $this->bb) : ";
+    } else {
+      code += "$this->__indirect($o + $this->bb_pos), $this->bb) : ";
+    }
+    code += GenDefaultValue(field.value) + ";\n";
+    code += Indent + "}\n\n";
+  }
+
+  // Get the value of a string.
+  void GetStringField(const FieldDef &field, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += Indent + "public function get";
+    code += MakeCamel(field.name);
+    code += "()\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$o = $this->__offset(" +
+            NumToString(field.value.offset) + ");\n";
+    code += Indent + Indent;
+    code += "return $o != 0 ? $this->__string($o + $this->bb_pos) : ";
+    code += GenDefaultValue(field.value) + ";\n";
+    code += Indent + "}\n\n";
+  }
+
+  // Get the value of a union from an object.
+  void GetUnionField(const FieldDef &field, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += Indent + "/**\n";
+    code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
+    code += Indent + " */\n";
+    code += Indent + "public function get";
+    code += MakeCamel(field.name) + "($obj)\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$o = $this->__offset(" +
+            NumToString(field.value.offset) + ");\n";
+    code += Indent + Indent;
+    code += "return $o != 0 ? $this->__union($obj, $o) : null;\n";
+    code += Indent + "}\n\n";
+  }
+
+  // Get the value of a vector's struct member.
+  void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+                                 const FieldDef &field, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    auto vectortype = field.value.type.VectorType();
+
+    code += Indent + "/**\n";
+    code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
+    code += Indent + " */\n";
+    code += Indent + "public function get";
+    code += MakeCamel(field.name);
+    code += "($j)\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$o = $this->__offset(" +
+            NumToString(field.value.offset) + ");\n";
+    code += Indent + Indent + "$obj = new ";
+    code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
+
+    switch (field.value.type.base_type) {
+      case BASE_TYPE_STRUCT:
+        if (struct_def.fixed) {
+          code += Indent + Indent;
+          code += "return $o != 0 ? $obj->init($this->bb_pos +" +
+                  NumToString(field.value.offset) + ", $this->bb) : null;\n";
+        } else {
+          code += Indent + Indent + "return $o != 0 ? $obj->init(";
+          code += field.value.type.struct_def->fixed
+                      ? "$o + $this->bb_pos"
+                      : "$this->__indirect($o + $this->bb_pos)";
+          code += ", $this->bb) : null;\n";
+        }
+        break;
+      case BASE_TYPE_STRING:
+        code += "// base_type_string\n";
+        // TODO(chobie): do we need this?
+        break;
+      case BASE_TYPE_VECTOR:
+        if (vectortype.base_type == BASE_TYPE_STRUCT) {
+          code += Indent + Indent + "return $o != 0 ? $obj->init(";
+          if (vectortype.struct_def->fixed) {
+            code += "$this->__vector($o) + $j *";
+            code += NumToString(InlineSize(vectortype));
+          } else {
+            code += "$this->__indirect($this->__vector($o) + $j * ";
+            code += NumToString(InlineSize(vectortype)) + ")";
+          }
+          code += ", $this->bb) : null;\n";
+        }
+        break;
+      case BASE_TYPE_UNION:
+        code += Indent + Indent + "return $o != 0 ? $this->";
+        code += GenGetter(field.value.type) + "($obj, $o); null;\n";
+        break;
+      default: break;
+    }
+
+    code += Indent + "}\n\n";
+  }
+
+  // Get the value of a vector's non-struct member. Uses a named return
+  // argument to conveniently set the zero value for the result.
+  void GetMemberOfVectorOfNonStruct(const FieldDef &field,
+                                    std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    auto vectortype = field.value.type.VectorType();
+
+    code += Indent + "/**\n";
+    code += Indent + " * @param int offset\n";
+    code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+    code += Indent + " */\n";
+    code += Indent + "public function get";
+    code += MakeCamel(field.name);
+    code += "($j)\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$o = $this->__offset(" +
+            NumToString(field.value.offset) + ");\n";
+
+    if (field.value.type.VectorType().base_type == BASE_TYPE_STRING) {
+      code += Indent + Indent;
+      code += "return $o != 0 ? $this->__string($this->__vector($o) + $j * ";
+      code += NumToString(InlineSize(vectortype)) + ") : ";
+      code += GenDefaultValue(field.value) + ";\n";
+    } else {
+      code += Indent + Indent + "return $o != 0 ? $this->bb->get";
+      code += MakeCamel(GenTypeGet(field.value.type));
+      code += "($this->__vector($o) + $j * ";
+      code += NumToString(InlineSize(vectortype)) + ") : ";
+      code += GenDefaultValue(field.value) + ";\n";
+    }
+    code += Indent + "}\n\n";
+  }
+
+  // Get the value of a vector's union member. Uses a named return
+  // argument to conveniently set the zero value for the result.
+  void GetMemberOfVectorOfUnion(const FieldDef &field, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    auto vectortype = field.value.type.VectorType();
+
+    code += Indent + "/**\n";
+    code += Indent + " * @param int offset\n";
+    code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+    code += Indent + " */\n";
+    code += Indent + "public function get";
+    code += MakeCamel(field.name);
+    code += "($j, $obj)\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$o = $this->__offset(" +
+            NumToString(field.value.offset) + ");\n";
+    code += Indent + Indent + "return $o != 0 ? ";
+    code += "$this->__union($obj, $this->__vector($o) + $j * ";
+    code += NumToString(InlineSize(vectortype)) + " - $this->bb_pos) : null;\n";
+    code += Indent + "}\n\n";
+  }
+
+  // Recursively generate arguments for a constructor, to deal with nested
+  // structs.
+  static 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 + (field.name + "_")).c_str(), code_ptr);
+      } else {
+        std::string &code = *code_ptr;
+        code += std::string(", $") + nameprefix;
+        code += MakeCamel(field.name, false);
+      }
+    }
+  }
+
+  // Recursively generate struct construction statements and instert manual
+  // padding.
+  static void StructBuilderBody(const StructDef &struct_def,
+                                const char *nameprefix, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += Indent + Indent + "$builder->prep(";
+    code += NumToString(struct_def.minalign) + ", ";
+    code += 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 += Indent + Indent + "$builder->pad(";
+        code += NumToString(field.padding) + ");\n";
+      }
+      if (IsStruct(field.value.type)) {
+        StructBuilderBody(*field.value.type.struct_def,
+                          (nameprefix + (field.name + "_")).c_str(), code_ptr);
+      } else {
+        code += Indent + Indent + "$builder->put" + GenMethod(field) + "($";
+        code += nameprefix + MakeCamel(field.name, false) + ");\n";
+      }
+    }
+  }
+
+  // Get the value of a table's starting offset.
+  static void GetStartOfTable(const StructDef &struct_def,
+                              std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += Indent + "/**\n";
+    code += Indent + " * @param FlatBufferBuilder $builder\n";
+    code += Indent + " * @return void\n";
+    code += Indent + " */\n";
+    code += Indent + "public static function start" + struct_def.name;
+    code += "(FlatBufferBuilder $builder)\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$builder->StartObject(";
+    code += NumToString(struct_def.fields.vec.size());
+    code += ");\n";
+    code += Indent + "}\n\n";
+
+    code += Indent + "/**\n";
+    code += Indent + " * @param FlatBufferBuilder $builder\n";
+    code += Indent + " * @return " + struct_def.name + "\n";
+    code += Indent + " */\n";
+    code += Indent + "public static function create" + struct_def.name;
+    code += "(FlatBufferBuilder $builder, ";
+
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+
+      if (field.deprecated) continue;
+      code += "$" + field.name;
+      if (!(it == (--struct_def.fields.vec.end()))) { code += ", "; }
+    }
+    code += ")\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$builder->startObject(";
+    code += NumToString(struct_def.fields.vec.size());
+    code += ");\n";
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (field.deprecated) continue;
+
+      code += Indent + Indent + "self::add";
+      code += MakeCamel(field.name) + "($builder, $" + field.name + ");\n";
+    }
+
+    code += Indent + Indent + "$o = $builder->endObject();\n";
+
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (!field.deprecated && field.required) {
+        code += Indent + Indent + "$builder->required($o, ";
+        code += NumToString(field.value.offset);
+        code += ");  // " + field.name + "\n";
+      }
+    }
+    code += Indent + Indent + "return $o;\n";
+    code += Indent + "}\n\n";
+  }
+
+  // Set the value of a table's field.
+  static void BuildFieldOfTable(const FieldDef &field, const size_t offset,
+                                std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += Indent + "/**\n";
+    code += Indent + " * @param FlatBufferBuilder $builder\n";
+    code += Indent + " * @param " + GenTypeBasic(field.value.type) + "\n";
+    code += Indent + " * @return void\n";
+    code += Indent + " */\n";
+    code += Indent + "public static function ";
+    code += "add" + MakeCamel(field.name);
+    code += "(FlatBufferBuilder $builder, ";
+    code += "$" + MakeCamel(field.name, false);
+    code += ")\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$builder->add";
+    code += GenMethod(field) + "X(";
+    code += NumToString(offset) + ", ";
+
+    code += "$" + MakeCamel(field.name, false);
+    code += ", ";
+
+    if (field.value.type.base_type == BASE_TYPE_BOOL) {
+      code += "false";
+    } else {
+      code += field.value.constant;
+    }
+    code += ");\n";
+    code += Indent + "}\n\n";
+  }
+
+  // Set the value of one of the members of a table's vector.
+  static void BuildVectorOfTable(const FieldDef &field, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    auto vector_type = field.value.type.VectorType();
+    auto alignment = InlineAlignment(vector_type);
+    auto elem_size = InlineSize(vector_type);
+    code += Indent + "/**\n";
+    code += Indent + " * @param FlatBufferBuilder $builder\n";
+    code += Indent + " * @param array offset array\n";
+    code += Indent + " * @return int vector offset\n";
+    code += Indent + " */\n";
+    code += Indent + "public static function create";
+    code += MakeCamel(field.name);
+    code += "Vector(FlatBufferBuilder $builder, array $data)\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$builder->startVector(";
+    code += NumToString(elem_size);
+    code += ", count($data), " + NumToString(alignment);
+    code += ");\n";
+    code += Indent + Indent;
+    code += "for ($i = count($data) - 1; $i >= 0; $i--) {\n";
+    if (IsScalar(field.value.type.VectorType().base_type)) {
+      code += Indent + Indent + Indent;
+      code += "$builder->put";
+      code += MakeCamel(GenTypeBasic(field.value.type.VectorType()));
+      code += "($data[$i]);\n";
+    } else {
+      code += Indent + Indent + Indent;
+      code += "$builder->putOffset($data[$i]);\n";
+    }
+    code += Indent + Indent + "}\n";
+    code += Indent + Indent + "return $builder->endVector();\n";
+    code += Indent + "}\n\n";
+
+    code += Indent + "/**\n";
+    code += Indent + " * @param FlatBufferBuilder $builder\n";
+    code += Indent + " * @param int $numElems\n";
+    code += Indent + " * @return void\n";
+    code += Indent + " */\n";
+    code += Indent + "public static function start";
+    code += MakeCamel(field.name);
+    code += "Vector(FlatBufferBuilder $builder, $numElems)\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$builder->startVector(";
+    code += NumToString(elem_size);
+    code += ", $numElems, " + NumToString(alignment);
+    code += ");\n";
+    code += Indent + "}\n\n";
+  }
+
+  // Get the offset of the end of a table.
+  void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += Indent + "/**\n";
+    code += Indent + " * @param FlatBufferBuilder $builder\n";
+    code += Indent + " * @return int table offset\n";
+    code += Indent + " */\n";
+    code += Indent + "public static function end" + struct_def.name;
+    code += "(FlatBufferBuilder $builder)\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "$o = $builder->endObject();\n";
+
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (!field.deprecated && field.required) {
+        code += Indent + Indent + "$builder->required($o, ";
+        code += NumToString(field.value.offset);
+        code += ");  // " + field.name + "\n";
+      }
+    }
+    code += Indent + Indent + "return $o;\n";
+    code += Indent + "}\n";
+
+    if (parser_.root_struct_def_ == &struct_def) {
+      code += "\n";
+      code += Indent + "public static function finish";
+      code += struct_def.name;
+      code += "Buffer(FlatBufferBuilder $builder, $offset)\n";
+      code += Indent + "{\n";
+      code += Indent + Indent + "$builder->finish($offset";
+
+      if (parser_.file_identifier_.length())
+        code += ", \"" + parser_.file_identifier_ + "\"";
+      code += ");\n";
+      code += Indent + "}\n";
+    }
+  }
+
+  // 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, Indent.c_str());
+
+    if (IsScalar(field.value.type.base_type)) {
+      if (struct_def.fixed) {
+        GetScalarFieldOfStruct(field, code_ptr);
+      } else {
+        GetScalarFieldOfTable(field, code_ptr);
+      }
+    } else {
+      switch (field.value.type.base_type) {
+        case BASE_TYPE_STRUCT:
+          if (struct_def.fixed) {
+            GetStructFieldOfStruct(field, code_ptr);
+          } else {
+            GetStructFieldOfTable(field, code_ptr);
+          }
+          break;
+        case BASE_TYPE_STRING: GetStringField(field, code_ptr); break;
+        case BASE_TYPE_VECTOR: {
+          auto vectortype = field.value.type.VectorType();
+          if (vectortype.base_type == BASE_TYPE_UNION) {
+            GetMemberOfVectorOfUnion(field, code_ptr);
+          } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
+            GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
+          } else {
+            GetMemberOfVectorOfNonStruct(field, code_ptr);
+          }
+          break;
+        }
+        case BASE_TYPE_UNION: GetUnionField(field, code_ptr); break;
+        default: FLATBUFFERS_ASSERT(0);
+      }
+    }
+    if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+      GetVectorLen(field, code_ptr);
+      if (field.value.type.element == BASE_TYPE_UCHAR) {
+        GetUByte(field, code_ptr);
+      }
+    }
+  }
+
+  // Generate table constructors, conditioned on its members' types.
+  void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
+    GetStartOfTable(struct_def, code_ptr);
+
+    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();
+      if (field.value.type.base_type == BASE_TYPE_UNION) {
+        std::string &code = *code_ptr;
+        code += Indent + "public static function add";
+        code += MakeCamel(field.name);
+        code += "(FlatBufferBuilder $builder, $offset)\n";
+        code += Indent + "{\n";
+        code += Indent + Indent + "$builder->addOffsetX(";
+        code += NumToString(offset) + ", $offset, 0);\n";
+        code += Indent + "}\n\n";
+      } else {
+        BuildFieldOfTable(field, offset, code_ptr);
+      }
+      if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+        BuildVectorOfTable(field, code_ptr);
+      }
+    }
+
+    GetEndOffsetOnTable(struct_def, code_ptr);
+  }
+
+  // Generate struct or table methods.
+  void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+    if (struct_def.generated) return;
+
+    GenComment(struct_def.doc_comment, code_ptr, nullptr);
+    BeginClass(struct_def, code_ptr);
+
+    if (!struct_def.fixed) {
+      // Generate a special accessor for the table that has been declared as
+      // the root type.
+      NewRootTypeFromBuffer(struct_def, code_ptr);
+    }
+
+    std::string &code = *code_ptr;
+    if (!struct_def.fixed) {
+      if (parser_.file_identifier_.length()) {
+        // Return the identifier
+        code += Indent + "public static function " + struct_def.name;
+        code += "Identifier()\n";
+        code += Indent + "{\n";
+        code += Indent + Indent + "return \"";
+        code += parser_.file_identifier_ + "\";\n";
+        code += Indent + "}\n\n";
+
+        // Check if a buffer has the identifier.
+        code += Indent + "public static function " + struct_def.name;
+        code += "BufferHasIdentifier(ByteBuffer $buf)\n";
+        code += Indent + "{\n";
+        code += Indent + Indent + "return self::";
+        code += "__has_identifier($buf, self::";
+        code += struct_def.name + "Identifier());\n";
+        code += Indent + "}\n\n";
+      }
+
+      if (parser_.file_extension_.length()) {
+        // Return the extension
+        code += Indent + "public static function " + struct_def.name;
+        code += "Extension()\n";
+        code += Indent + "{\n";
+        code += Indent + Indent + "return \"" + parser_.file_extension_;
+        code += "\";\n";
+        code += Indent + "}\n\n";
+      }
+    }
+
+    // Generate the Init method that sets the field in a pre-existing
+    // accessor object. This is to allow object reuse.
+    InitializeExisting(struct_def, code_ptr);
+    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);
+    }
+
+    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);
+    }
+    EndClass(code_ptr);
+  }
+
+  // Generate enum declarations.
+  static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+    if (enum_def.generated) return;
+
+    GenComment(enum_def.doc_comment, code_ptr, nullptr);
+    BeginEnum(enum_def.name, code_ptr);
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      auto &ev = **it;
+      GenComment(ev.doc_comment, code_ptr, nullptr, Indent.c_str());
+      EnumMember(enum_def, ev, code_ptr);
+    }
+
+    std::string &code = *code_ptr;
+    code += "\n";
+    code += Indent + "private static $names = array(\n";
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      auto &ev = **it;
+      code += Indent + Indent + enum_def.name + "::" + ev.name + "=>" + "\"" + ev.name + "\",\n";
+    }
+
+    code += Indent + ");\n\n";
+    code += Indent + "public static function Name($e)\n";
+    code += Indent + "{\n";
+    code += Indent + Indent + "if (!isset(self::$names[$e])) {\n";
+    code += Indent + Indent + Indent + "throw new \\Exception();\n";
+    code += Indent + Indent + "}\n";
+    code += Indent + Indent + "return self::$names[$e];\n";
+    code += Indent + "}\n";
+    EndEnum(code_ptr);
+  }
+
+  // Returns the function name that is able to read a value of the given type.
+  static std::string GenGetter(const Type &type) {
+    switch (type.base_type) {
+      case BASE_TYPE_STRING: return "__string";
+      case BASE_TYPE_STRUCT: return "__struct";
+      case BASE_TYPE_UNION: return "__union";
+      case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+      default: return "Get";
+    }
+  }
+
+  // Returns the method name for use with add/put calls.
+  static std::string GenMethod(const FieldDef &field) {
+    return IsScalar(field.value.type.base_type)
+               ? MakeCamel(GenTypeBasic(field.value.type))
+               : (IsStruct(field.value.type) ? "Struct" : "Offset");
+  }
+
+  static 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) \
+            #NTYPE,
+                FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+        #undef FLATBUFFERS_TD
+      // clang-format on
+    };
+    return ctypename[type.base_type];
+  }
+
+  std::string GenDefaultValue(const Value &value) {
+    if (value.type.enum_def) {
+      if (auto val = value.type.enum_def->FindByValue(value.constant)) {
+        return WrapInNameSpace(*value.type.enum_def) + "::" + val->name;
+      }
+    }
+
+    switch (value.type.base_type) {
+      case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
+
+      case BASE_TYPE_STRING: return "null";
+
+      case BASE_TYPE_LONG:
+      case BASE_TYPE_ULONG:
+        if (value.constant != "0") {
+          int64_t constant = StringToInt(value.constant.c_str());
+          return NumToString(constant);
+        }
+        return "0";
+
+      default: return value.constant;
+    }
+  }
+
+  static std::string GenTypePointer(const Type &type) {
+    switch (type.base_type) {
+      case BASE_TYPE_STRING: return "string";
+      case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+      case BASE_TYPE_STRUCT: return type.struct_def->name;
+      case BASE_TYPE_UNION:
+        // fall through
+      default: return "Table";
+    }
+  }
+
+  static std::string GenTypeGet(const Type &type) {
+    return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+  }
+
+  // Create a struct with a builder and the struct's arguments.
+  static void GenStructBuilder(const StructDef &struct_def,
+                               std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "\n";
+    code += Indent + "/**\n";
+    code += Indent + " * @return int offset\n";
+    code += Indent + " */\n";
+    code += Indent + "public static function create" + struct_def.name;
+    code += "(FlatBufferBuilder $builder";
+    StructBuilderArgs(struct_def, "", code_ptr);
+    code += ")\n";
+    code += Indent + "{\n";
+
+    StructBuilderBody(struct_def, "", code_ptr);
+
+    code += Indent + Indent + "return $builder->offset();\n";
+    code += Indent + "}\n";
+  }
+};
+}  // namespace php
+
+bool GeneratePhp(const Parser &parser, const std::string &path,
+                 const std::string &file_name) {
+  php::PhpGenerator generator(parser, path, file_name);
+  return generator.generate();
+}
+}  // namespace flatbuffers
diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp
new file mode 100644
index 0000000..c8db359
--- /dev/null
+++ b/src/idl_gen_python.cpp
@@ -0,0 +1,823 @@
+/*
+ * Copyright 2014 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.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include <string>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#include <unordered_set>
+
+namespace flatbuffers {
+namespace python {
+
+// Hardcode spaces per indentation.
+const CommentConfig def_comment = { nullptr, "#", nullptr };
+const std::string Indent = "    ";
+
+class PythonGenerator : public BaseGenerator {
+ public:
+  PythonGenerator(const Parser &parser, const std::string &path,
+                  const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "" /* not used */,
+                      "" /* not used */),
+        float_const_gen_("float('nan')", "float('inf')", "float('-inf')") {
+    static const char * const keywords[] = {
+      "False",
+      "None",
+      "True",
+      "and",
+      "as",
+      "assert",
+      "break",
+      "class",
+      "continue",
+      "def",
+      "del",
+      "elif",
+      "else",
+      "except",
+      "finally",
+      "for",
+      "from",
+      "global",
+      "if",
+      "import",
+      "in",
+      "is",
+      "lambda",
+      "nonlocal",
+      "not",
+      "or",
+      "pass",
+      "raise",
+      "return",
+      "try",
+      "while",
+      "with",
+      "yield"
+    };
+    keywords_.insert(std::begin(keywords), std::end(keywords));
+  }
+
+  // Most field accessors need to retrieve and test the field offset first,
+  // this is the prefix code for that.
+  std::string OffsetPrefix(const FieldDef &field) {
+    return "\n" + Indent + Indent +
+          "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
+          "(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
+          Indent + Indent + "if o != 0:\n";
+  }
+
+  // Begin a class declaration.
+  void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "class " + NormalizedName(struct_def) + "(object):\n";
+    code += Indent + "__slots__ = ['_tab']";
+    code += "\n\n";
+  }
+
+  // Begin enum code with a class declaration.
+  void BeginEnum(const std::string &class_name, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "class " + class_name + "(object):\n";
+  }
+
+  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);
+  }
+
+  // A single enum member.
+  void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
+                  std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += Indent;
+    code += NormalizedName(ev);
+    code += " = ";
+    code += enum_def.ToString(ev) + "\n";
+  }
+
+  // End enum code.
+  void EndEnum(std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "\n";
+  }
+
+  // Initialize a new struct or table from existing data.
+  void NewRootTypeFromBuffer(const StructDef &struct_def,
+                             std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += Indent + "@classmethod\n";
+    code += Indent + "def GetRootAs";
+    code += NormalizedName(struct_def);
+    code += "(cls, buf, offset):";
+    code += "\n";
+    code += Indent + Indent;
+    code += "n = flatbuffers.encode.Get";
+    code += "(flatbuffers.packer.uoffset, buf, offset)\n";
+    code += Indent + Indent + "x = " + NormalizedName(struct_def) + "()\n";
+    code += Indent + Indent + "x.Init(buf, n + offset)\n";
+    code += Indent + Indent + "return x\n";
+    code += "\n";
+  }
+
+  // Initialize an existing object with other data, to avoid an allocation.
+  void InitializeExisting(const StructDef &struct_def,
+                          std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    GenReceiver(struct_def, code_ptr);
+    code += "Init(self, buf, pos):\n";
+    code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n";
+    code += "\n";
+  }
+
+  // Get the length of a vector.
+  void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
+                    std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    GenReceiver(struct_def, code_ptr);
+    code += MakeCamel(NormalizedName(field)) + "Length(self";
+    code += "):" + OffsetPrefix(field);
+    code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n";
+    code += Indent + Indent + "return 0\n\n";
+  }
+
+  // Get the value of a struct's scalar.
+  void GetScalarFieldOfStruct(const StructDef &struct_def,
+                              const FieldDef &field,
+                              std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    std::string getter = GenGetter(field.value.type);
+    GenReceiver(struct_def, code_ptr);
+    code += MakeCamel(NormalizedName(field));
+    code += "(self): return " + getter;
+    code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
+    code += NumToString(field.value.offset) + "))\n";
+  }
+
+  // Get the value of a table's scalar.
+  void GetScalarFieldOfTable(const StructDef &struct_def,
+                             const FieldDef &field,
+                             std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    std::string getter = GenGetter(field.value.type);
+    GenReceiver(struct_def, code_ptr);
+    code += MakeCamel(NormalizedName(field));
+    code += "(self):";
+    code += OffsetPrefix(field);
+    getter += "o + self._tab.Pos)";
+    auto is_bool = IsBool(field.value.type.base_type);
+    if (is_bool) {
+      getter = "bool(" + getter + ")";
+    }
+    code += Indent + Indent + Indent + "return " + getter + "\n";
+    std::string default_value;
+    if (is_bool) {
+      default_value = field.value.constant == "0" ? "False" : "True";
+    } else {
+      default_value = IsFloat(field.value.type.base_type)
+                          ? float_const_gen_.GenFloatConstant(field)
+                          : field.value.constant;
+    }
+    code += Indent + Indent + "return " + default_value + "\n\n";
+  }
+
+  // Get a struct by initializing an existing struct.
+  // Specific to Struct.
+  void GetStructFieldOfStruct(const StructDef &struct_def,
+                              const FieldDef &field,
+                              std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    GenReceiver(struct_def, code_ptr);
+    code += MakeCamel(NormalizedName(field));
+    code += "(self, obj):\n";
+    code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
+    code += NumToString(field.value.offset) + ")";
+    code += "\n" + Indent + Indent + "return obj\n\n";
+  }
+
+  // Get the value of a fixed size array.
+  void GetArrayOfStruct(const StructDef &struct_def, const FieldDef &field,
+                        std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    const auto vec_type = field.value.type.VectorType();
+    GenReceiver(struct_def, code_ptr);
+    code += MakeCamel(NormalizedName(field));
+    if (IsStruct(vec_type)) {
+      code += "(self, obj, i):\n";
+      code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
+      code += NumToString(field.value.offset) + " + i * ";
+      code += NumToString(InlineSize(vec_type));
+      code += ")\n" + Indent + Indent + "return obj\n\n";
+    } else {
+      auto getter = GenGetter(vec_type);
+      code += "(self): return [" + getter;
+      code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
+      code += NumToString(field.value.offset) + " + i * ";
+      code += NumToString(InlineSize(vec_type));
+      code += ")) for i in range(";
+      code += NumToString(field.value.type.fixed_length) + ")]\n";
+    }
+  }
+
+  // Get a struct by initializing an existing struct.
+  // Specific to Table.
+  void GetStructFieldOfTable(const StructDef &struct_def,
+                             const FieldDef &field,
+                             std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    GenReceiver(struct_def, code_ptr);
+    code += MakeCamel(NormalizedName(field));
+    code += "(self):";
+    code += OffsetPrefix(field);
+    if (field.value.type.struct_def->fixed) {
+      code += Indent + Indent + Indent + "x = o + self._tab.Pos\n";
+    } else {
+      code += Indent + Indent + Indent;
+      code += "x = self._tab.Indirect(o + self._tab.Pos)\n";
+    }
+    code += Indent + Indent + Indent;
+    code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
+    code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
+    code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
+    code += Indent + Indent + Indent + "return obj\n";
+    code += Indent + Indent + "return None\n\n";
+  }
+
+  // Get the value of a string.
+  void GetStringField(const StructDef &struct_def, const FieldDef &field,
+                      std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    GenReceiver(struct_def, code_ptr);
+    code += MakeCamel(NormalizedName(field));
+    code += "(self):";
+    code += OffsetPrefix(field);
+    code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
+    code += "o + self._tab.Pos)\n";
+    code += Indent + Indent + "return None\n\n";
+  }
+
+  // Get the value of a union from an object.
+  void GetUnionField(const StructDef &struct_def, const FieldDef &field,
+                     std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    GenReceiver(struct_def, code_ptr);
+    code += MakeCamel(NormalizedName(field)) + "(self):";
+    code += OffsetPrefix(field);
+
+    // TODO(rw): this works and is not the good way to it:
+    bool is_native_table = TypeName(field) == "*flatbuffers.Table";
+    if (is_native_table) {
+      code += Indent + Indent + Indent + "from flatbuffers.table import Table\n";
+    } else {
+      code += Indent + Indent + Indent;
+      code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
+    }
+    code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
+    code += Indent + Indent + Indent + GenGetter(field.value.type);
+    code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n";
+    code += Indent + Indent + "return None\n\n";
+  }
+
+  // Get the value of a vector's struct member.
+  void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+                                 const FieldDef &field,
+                                 std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    auto vectortype = field.value.type.VectorType();
+
+    GenReceiver(struct_def, code_ptr);
+    code += MakeCamel(NormalizedName(field));
+    code += "(self, j):" + OffsetPrefix(field);
+    code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n";
+    code += Indent + Indent + Indent;
+    code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * ";
+    code += NumToString(InlineSize(vectortype)) + "\n";
+    if (!(vectortype.struct_def->fixed)) {
+      code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n";
+    }
+    code += Indent + Indent + Indent;
+    code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
+    code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
+    code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
+    code += Indent + Indent + Indent + "return obj\n";
+    code += Indent + Indent + "return None\n\n";
+  }
+
+  // Get the value of a vector's non-struct member. Uses a named return
+  // argument to conveniently set the zero value for the result.
+  void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
+                                    const FieldDef &field,
+                                    std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    auto vectortype = field.value.type.VectorType();
+
+    GenReceiver(struct_def, code_ptr);
+    code += MakeCamel(NormalizedName(field));
+    code += "(self, j):";
+    code += OffsetPrefix(field);
+    code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n";
+    code += Indent + Indent + Indent;
+    code += "return " + GenGetter(field.value.type);
+    code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * ";
+    code += NumToString(InlineSize(vectortype)) + "))\n";
+    if (vectortype.base_type == BASE_TYPE_STRING) {
+      code += Indent + Indent + "return \"\"\n";
+    } else {
+      code += Indent + Indent + "return 0\n";
+    }
+    code += "\n";
+  }
+
+  // Returns a non-struct vector as a numpy array. Much faster
+  // than iterating over the vector element by element.
+  void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
+                                   const FieldDef &field,
+                                   std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    auto vectortype = field.value.type.VectorType();
+
+    // Currently, we only support accessing as numpy array if
+    // the vector type is a scalar.
+    if (!(IsScalar(vectortype.base_type))) { return; }
+
+    GenReceiver(struct_def, code_ptr);
+    code += MakeCamel(NormalizedName(field)) + "AsNumpy(self):";
+    code += OffsetPrefix(field);
+
+    code += Indent + Indent + Indent;
+    code += "return ";
+    code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
+    code += MakeCamel(GenTypeGet(field.value.type));
+    code += "Flags, o)\n";
+
+    if (vectortype.base_type == BASE_TYPE_STRING) {
+      code += Indent + Indent + "return \"\"\n";
+    } else {
+      code += Indent + Indent + "return 0\n";
+    }
+    code += "\n";
+  }
+
+  // Begin the creator function signature.
+  void BeginBuilderArgs(const StructDef &struct_def,
+                        std::string *code_ptr) {
+    std::string &code = *code_ptr;
+
+    code += "\n";
+    code += "def Create" + NormalizedName(struct_def);
+    code += "(builder";
+  }
+
+  // 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;
+      const auto &field_type = field.value.type;
+      const auto &type =
+          IsArray(field_type) ? field_type.VectorType() : field_type;
+      if (IsStruct(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_type.struct_def,
+                          (nameprefix + (NormalizedName(field) + "_")).c_str(),
+                          code_ptr);
+      } else {
+        std::string &code = *code_ptr;
+        code += std::string(", ") + nameprefix;
+        code += MakeCamel(NormalizedName(field), false);
+      }
+    }
+  }
+
+  // End the creator function signature.
+  void EndBuilderArgs(std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "):\n";
+  }
+
+  // Recursively generate struct construction statements and instert manual
+  // padding.
+  void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
+                         std::string *code_ptr, size_t index = 0,
+                         bool in_array = false) {
+    std::string &code = *code_ptr;
+    std::string indent(index * 4, ' ');
+    code +=
+        indent + "    builder.Prep(" + NumToString(struct_def.minalign) + ", ";
+    code += NumToString(struct_def.bytesize) + ")\n";
+    for (auto it = struct_def.fields.vec.rbegin();
+        it != struct_def.fields.vec.rend(); ++it) {
+      auto &field = **it;
+      const auto &field_type = field.value.type;
+      const auto &type =
+          IsArray(field_type) ? field_type.VectorType() : field_type;
+      if (field.padding)
+        code +=
+            indent + "    builder.Pad(" + NumToString(field.padding) + ")\n";
+      if (IsStruct(field_type)) {
+        StructBuilderBody(*field_type.struct_def,
+                          (nameprefix + (NormalizedName(field) + "_")).c_str(),
+                          code_ptr, index, in_array);
+      } else {
+        const auto index_var = "_idx" + NumToString(index);
+        if (IsArray(field_type)) {
+          code += indent + "    for " + index_var + " in range(";
+          code += NumToString(field_type.fixed_length);
+          code += " , 0, -1):\n";
+          in_array = true;
+        }
+        if (IsStruct(type)) {
+          StructBuilderBody(
+              *field_type.struct_def,
+              (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr,
+              index + 1, in_array);
+        } else {
+          code += IsArray(field_type) ? "    " : "";
+          code += indent + "    builder.Prepend" + GenMethod(field) + "(";
+          code += nameprefix + MakeCamel(NormalizedName(field), false);
+          size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
+          for (size_t i = 0; in_array && i < array_cnt; i++) {
+            code += "[_idx" + NumToString(i) + "-1]";
+          }
+          code += ")\n";
+        }
+      }
+    }
+  }
+
+  void EndBuilderBody(std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "    return builder.Offset()\n";
+  }
+
+  // Get the value of a table's starting offset.
+  void GetStartOfTable(const StructDef &struct_def,
+                       std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "def " + NormalizedName(struct_def) + "Start";
+    code += "(builder): ";
+    code += "builder.StartObject(";
+    code += NumToString(struct_def.fields.vec.size());
+    code += ")\n";
+  }
+
+  // Set the value of a table's field.
+  void BuildFieldOfTable(const StructDef &struct_def,
+                         const FieldDef &field, const size_t offset,
+                         std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "def " + NormalizedName(struct_def) + "Add" + MakeCamel(NormalizedName(field));
+    code += "(builder, ";
+    code += MakeCamel(NormalizedName(field), false);
+    code += "): ";
+    code += "builder.Prepend";
+    code += GenMethod(field) + "Slot(";
+    code += NumToString(offset) + ", ";
+    if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
+      code += "flatbuffers.number_types.UOffsetTFlags.py_type";
+      code += "(";
+      code += MakeCamel(NormalizedName(field), false) + ")";
+    } else {
+      code += MakeCamel(NormalizedName(field), false);
+    }
+    code += ", ";
+    code += IsFloat(field.value.type.base_type)
+                ? float_const_gen_.GenFloatConstant(field)
+                : field.value.constant;
+    code += ")\n";
+  }
+
+  // Set the value of one of the members of a table's vector.
+  void BuildVectorOfTable(const StructDef &struct_def,
+                          const FieldDef &field, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "def " + NormalizedName(struct_def) + "Start";
+    code += MakeCamel(NormalizedName(field));
+    code += "Vector(builder, numElems): return builder.StartVector(";
+    auto vector_type = field.value.type.VectorType();
+    auto alignment = InlineAlignment(vector_type);
+    auto elem_size = InlineSize(vector_type);
+    code += NumToString(elem_size);
+    code += ", numElems, " + NumToString(alignment);
+    code += ")\n";
+  }
+
+  // Get the offset of the end of a table.
+  void GetEndOffsetOnTable(const StructDef &struct_def,
+                           std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "def " + NormalizedName(struct_def) + "End";
+    code += "(builder): ";
+    code += "return builder.EndObject()\n";
+  }
+
+  // Generate the receiver for function signatures.
+  void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += Indent + "# " + NormalizedName(struct_def) + "\n";
+    code += Indent + "def ";
+  }
+
+  // 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, &def_comment, Indent.c_str());
+    if (IsScalar(field.value.type.base_type)) {
+      if (struct_def.fixed) {
+        GetScalarFieldOfStruct(struct_def, field, code_ptr);
+      } else {
+        GetScalarFieldOfTable(struct_def, field, code_ptr);
+      }
+    } else if (IsArray(field.value.type)) {
+      GetArrayOfStruct(struct_def, field, code_ptr);
+    } else {
+      switch (field.value.type.base_type) {
+        case BASE_TYPE_STRUCT:
+          if (struct_def.fixed) {
+            GetStructFieldOfStruct(struct_def, field, code_ptr);
+          } else {
+            GetStructFieldOfTable(struct_def, field, code_ptr);
+          }
+          break;
+        case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break;
+        case BASE_TYPE_VECTOR: {
+          auto vectortype = field.value.type.VectorType();
+          if (vectortype.base_type == BASE_TYPE_STRUCT) {
+            GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
+          } else {
+            GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
+            GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
+          }
+          break;
+        }
+        case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
+        default: FLATBUFFERS_ASSERT(0);
+      }
+    }
+    if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+      GetVectorLen(struct_def, field, code_ptr);
+    }
+  }
+
+  // Generate table constructors, conditioned on its members' types.
+  void GenTableBuilders(const StructDef &struct_def,
+                        std::string *code_ptr) {
+    GetStartOfTable(struct_def, code_ptr);
+
+    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();
+      BuildFieldOfTable(struct_def, field, offset, code_ptr);
+      if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+        BuildVectorOfTable(struct_def, field, code_ptr);
+      }
+    }
+
+    GetEndOffsetOnTable(struct_def, code_ptr);
+  }
+
+  // Generate function to check for proper file identifier
+  void GenHasFileIdentifier(const StructDef &struct_def,
+                            std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    std::string escapedID;
+    // In the event any of file_identifier characters are special(NULL, \, etc),
+    // problems occur. To prevent this, convert all chars to their hex-escaped
+    // equivalent.
+    for (auto it = parser_.file_identifier_.begin();
+         it != parser_.file_identifier_.end(); ++it) {
+      escapedID += "\\x" + IntToStringHex(*it, 2);
+    }
+
+    code += Indent + "@classmethod\n";
+    code += Indent + "def " + NormalizedName(struct_def);
+    code += "BufferHasIdentifier(cls, buf, offset, size_prefixed=False):";
+    code += "\n";
+    code += Indent + Indent;
+    code += "return flatbuffers.util.BufferHasIdentifier(buf, offset, b\"";
+    code += escapedID;
+    code += "\", size_prefixed=size_prefixed)\n";
+    code += "\n";
+  }
+  
+  // Generate struct or table methods.
+  void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+    if (struct_def.generated) return;
+
+    GenComment(struct_def.doc_comment, code_ptr, &def_comment);
+    BeginClass(struct_def, code_ptr);
+    if (!struct_def.fixed) {
+      // Generate a special accessor for the table that has been declared as
+      // the root type.
+      NewRootTypeFromBuffer(struct_def, code_ptr);
+      if (parser_.file_identifier_.length()){
+        // Generate a special function to test file_identifier
+        GenHasFileIdentifier(struct_def, code_ptr);
+      }
+    }
+    // Generate the Init method that sets the field in a pre-existing
+    // accessor object. This is to allow object reuse.
+    InitializeExisting(struct_def, code_ptr);
+    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);
+    }
+
+    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;
+
+    GenComment(enum_def.doc_comment, code_ptr, &def_comment);
+    BeginEnum(NormalizedName(enum_def), code_ptr);
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      auto &ev = **it;
+      GenComment(ev.doc_comment, code_ptr, &def_comment, Indent.c_str());
+      EnumMember(enum_def, ev, code_ptr);
+    }
+    EndEnum(code_ptr);
+  }
+
+  // Returns the function name that is able to read a value of the given type.
+  std::string GenGetter(const Type &type) {
+    switch (type.base_type) {
+      case BASE_TYPE_STRING: return "self._tab.String(";
+      case BASE_TYPE_UNION: return "self._tab.Union(";
+      case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+      default:
+        return "self._tab.Get(flatbuffers.number_types." +
+              MakeCamel(GenTypeGet(type)) + "Flags, ";
+    }
+  }
+
+  // Returns the method name for use with add/put calls.
+  std::string GenMethod(const FieldDef &field) {
+    return (IsScalar(field.value.type.base_type) || IsArray(field.value.type))
+               ? MakeCamel(GenTypeBasic(field.value.type))
+               : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
+  }
+
+  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[IsArray(type) ? type.VectorType().base_type
+                                   : type.base_type];
+  }
+
+  std::string GenTypePointer(const Type &type) {
+    switch (type.base_type) {
+      case BASE_TYPE_STRING: return "string";
+      case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+      case BASE_TYPE_STRUCT: return type.struct_def->name;
+      case BASE_TYPE_UNION:
+        // fall through
+      default: return "*flatbuffers.Table";
+    }
+  }
+
+  std::string GenTypeGet(const Type &type) {
+    return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+  }
+
+  std::string TypeName(const FieldDef &field) {
+    return GenTypeGet(field.value.type);
+  }
+
+  // Create a struct with a builder and the struct's arguments.
+  void GenStructBuilder(const StructDef &struct_def,
+                              std::string *code_ptr) {
+    BeginBuilderArgs(struct_def, code_ptr);
+    StructBuilderArgs(struct_def, "", code_ptr);
+    EndBuilderArgs(code_ptr);
+
+    StructBuilderBody(struct_def, "", code_ptr);
+    EndBuilderBody(code_ptr);
+  }
+
+  bool generate() {
+    if (!generateEnums()) return false;
+    if (!generateStructs()) return false;
+    return true;
+  }
+
+ private:
+  bool generateEnums() {
+    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+         ++it) {
+      auto &enum_def = **it;
+      std::string enumcode;
+      GenEnum(enum_def, &enumcode);
+      if (!SaveType(enum_def, enumcode, false)) return false;
+    }
+    return true;
+  }
+
+  bool generateStructs() {
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      auto &struct_def = **it;
+      std::string declcode;
+      GenStruct(struct_def, &declcode);
+      if (!SaveType(struct_def, declcode, true)) return false;
+    }
+    return true;
+  }
+
+  // Begin by declaring namespace and imports.
+  void BeginFile(const std::string &name_space_name, const bool needs_imports,
+                 std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
+    code += "# namespace: " + name_space_name + "\n\n";
+    if (needs_imports) { code += "import flatbuffers\n\n"; }
+  }
+
+  // Save out the generated code for a Python Table type.
+  bool SaveType(const Definition &def, const std::string &classcode,
+                bool needs_imports) {
+    if (!classcode.length()) return true;
+
+    std::string namespace_dir = path_;
+    auto &namespaces = def.defined_namespace->components;
+    for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+      if (it != namespaces.begin()) namespace_dir += kPathSeparator;
+      namespace_dir += *it;
+      std::string init_py_filename = namespace_dir + "/__init__.py";
+      SaveFile(init_py_filename.c_str(), "", false);
+    }
+
+    std::string code = "";
+    BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
+    code += classcode;
+    std::string filename =
+        NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".py";
+    return SaveFile(filename.c_str(), code, false);
+  }
+ private:
+  std::unordered_set<std::string> keywords_;
+  const SimpleFloatConstantGenerator float_const_gen_;
+};
+
+}  // namespace python
+
+bool GeneratePython(const Parser &parser, const std::string &path,
+                    const std::string &file_name) {
+  python::PythonGenerator generator(parser, path, file_name);
+  return generator.generate();
+}
+
+}  // namespace flatbuffers
diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp
new file mode 100644
index 0000000..936ac83
--- /dev/null
+++ b/src/idl_gen_rust.cpp
@@ -0,0 +1,1825 @@
+/*
+ * 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.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+static std::string GeneratedFileName(const std::string &path,
+                                     const std::string &file_name) {
+  return path + file_name + "_generated.rs";
+}
+
+// Convert a camelCaseIdentifier or CamelCaseIdentifier to a
+// snake_case_indentifier.
+std::string MakeSnakeCase(const std::string &in) {
+  std::string s;
+  for (size_t i = 0; i < in.length(); i++) {
+    if (i == 0) {
+      s += static_cast<char>(tolower(in[0]));
+    } else if (in[i] == '_') {
+      s += '_';
+    } else if (!islower(in[i])) {
+      // Prevent duplicate underscores for Upper_Snake_Case strings
+      // and UPPERCASE strings.
+      if (islower(in[i - 1])) {
+        s += '_';
+      }
+      s += static_cast<char>(tolower(in[i]));
+    } else {
+      s += in[i];
+    }
+  }
+  return s;
+}
+
+// Convert a string to all uppercase.
+std::string MakeUpper(const std::string &in) {
+  std::string s;
+  for (size_t i = 0; i < in.length(); i++) {
+    s += static_cast<char>(toupper(in[i]));
+  }
+  return s;
+}
+
+// Encapsulate all logical field types in this enum. This allows us to write
+// field logic based on type switches, instead of branches on the properties
+// set on the Type.
+// TODO(rw): for backwards compatibility, we can't use a strict `enum class`
+//           declaration here. could we use the `-Wswitch-enum` warning to
+//           achieve the same effect?
+enum FullType {
+  ftInteger = 0,
+  ftFloat = 1,
+  ftBool = 2,
+
+  ftStruct = 3,
+  ftTable = 4,
+
+  ftEnumKey = 5,
+  ftUnionKey = 6,
+
+  ftUnionValue = 7,
+
+  // TODO(rw): bytestring?
+  ftString = 8,
+
+  ftVectorOfInteger = 9,
+  ftVectorOfFloat = 10,
+  ftVectorOfBool = 11,
+  ftVectorOfEnumKey = 12,
+  ftVectorOfStruct = 13,
+  ftVectorOfTable = 14,
+  ftVectorOfString = 15,
+  ftVectorOfUnionValue = 16,
+};
+
+// Convert a Type to a FullType (exhaustive).
+FullType GetFullType(const Type &type) {
+  // N.B. The order of these conditionals matters for some types.
+
+  if (type.base_type == BASE_TYPE_STRING) {
+    return ftString;
+  } else if (type.base_type == BASE_TYPE_STRUCT) {
+    if (type.struct_def->fixed) {
+      return ftStruct;
+    } else {
+      return ftTable;
+    }
+  } else if (type.base_type == BASE_TYPE_VECTOR) {
+    switch (GetFullType(type.VectorType())) {
+      case ftInteger: {
+        return ftVectorOfInteger;
+      }
+      case ftFloat: {
+        return ftVectorOfFloat;
+      }
+      case ftBool: {
+        return ftVectorOfBool;
+      }
+      case ftStruct: {
+        return ftVectorOfStruct;
+      }
+      case ftTable: {
+        return ftVectorOfTable;
+      }
+      case ftString: {
+        return ftVectorOfString;
+      }
+      case ftEnumKey: {
+        return ftVectorOfEnumKey;
+      }
+      case ftUnionKey:
+      case ftUnionValue: {
+        FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported");
+        break;
+      }
+      default: {
+        FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
+      }
+    }
+  } else if (type.enum_def != nullptr) {
+    if (type.enum_def->is_union) {
+      if (type.base_type == BASE_TYPE_UNION) {
+        return ftUnionValue;
+      } else if (IsInteger(type.base_type)) {
+        return ftUnionKey;
+      } else {
+        FLATBUFFERS_ASSERT(false && "unknown union field type");
+      }
+    } else {
+      return ftEnumKey;
+    }
+  } else if (IsScalar(type.base_type)) {
+    if (IsBool(type.base_type)) {
+      return ftBool;
+    } else if (IsInteger(type.base_type)) {
+      return ftInteger;
+    } else if (IsFloat(type.base_type)) {
+      return ftFloat;
+    } else {
+      FLATBUFFERS_ASSERT(false && "unknown number type");
+    }
+  }
+
+  FLATBUFFERS_ASSERT(false && "completely unknown type");
+
+  // this is only to satisfy the compiler's return analysis.
+  return ftBool;
+}
+
+// If the second parameter is false then wrap the first with Option<...>
+std::string WrapInOptionIfNotRequired(std::string s, bool required) {
+  if (required) {
+    return s;
+  } else {
+    return "Option<" + s + ">";
+  }
+}
+
+// If the second parameter is false then add .unwrap()
+std::string AddUnwrapIfRequired(std::string s, bool required) {
+  if (required) {
+    return s + ".unwrap()";
+  } else {
+    return s;
+  }
+}
+
+namespace rust {
+
+class RustGenerator : public BaseGenerator {
+ public:
+  RustGenerator(const Parser &parser, const std::string &path,
+                const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "", "::"),
+        cur_name_space_(nullptr) {
+    const char *keywords[] = {
+      // list taken from:
+      // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html
+      //
+      // we write keywords one per line so that we can easily compare them with
+      // changes to that webpage in the future.
+
+      // currently-used keywords
+      "as",
+      "break",
+      "const",
+      "continue",
+      "crate",
+      "else",
+      "enum",
+      "extern",
+      "false",
+      "fn",
+      "for",
+      "if",
+      "impl",
+      "in",
+      "let",
+      "loop",
+      "match",
+      "mod",
+      "move",
+      "mut",
+      "pub",
+      "ref",
+      "return",
+      "Self",
+      "self",
+      "static",
+      "struct",
+      "super",
+      "trait",
+      "true",
+      "type",
+      "unsafe",
+      "use",
+      "where",
+      "while",
+
+      // future possible keywords
+      "abstract",
+      "alignof",
+      "become",
+      "box",
+      "do",
+      "final",
+      "macro",
+      "offsetof",
+      "override",
+      "priv",
+      "proc",
+      "pure",
+      "sizeof",
+      "typeof",
+      "unsized",
+      "virtual",
+      "yield",
+
+      // other rust terms we should not use
+      "std",
+      "usize",
+      "isize",
+      "u8",
+      "i8",
+      "u16",
+      "i16",
+      "u32",
+      "i32",
+      "u64",
+      "i64",
+      "u128",
+      "i128",
+      "f32",
+      "f64",
+
+      // These are terms the code generator can implement on types.
+      //
+      // In Rust, the trait resolution rules (as described at
+      // https://github.com/rust-lang/rust/issues/26007) mean that, as long
+      // as we impl table accessors as inherent methods, we'll never create
+      // conflicts with these keywords. However, that's a fairly nuanced
+      // implementation detail, and how we implement methods could change in
+      // the future. as a result, we proactively block these out as reserved
+      // words.
+      "follow",
+      "push",
+      "size",
+      "alignment",
+      "to_little_endian",
+      "from_little_endian",
+      nullptr };
+    for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+  }
+
+  // Iterate through all definitions we haven't generated code for (enums,
+  // structs, and tables) and output them to a single file.
+  bool generate() {
+    code_.Clear();
+    code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+    assert(!cur_name_space_);
+
+    // Generate imports for the global scope in case no namespace is used
+    // in the schema file.
+    GenNamespaceImports(0);
+    code_ += "";
+
+    // Generate all code in their namespaces, once, because Rust does not
+    // permit re-opening modules.
+    //
+    // TODO(rw): Use a set data structure to reduce namespace evaluations from
+    //           O(n**2) to O(n).
+    for (auto ns_it = parser_.namespaces_.begin();
+         ns_it != parser_.namespaces_.end();
+         ++ns_it) {
+      const auto &ns = *ns_it;
+
+      // Generate code for all the enum declarations.
+      for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+           ++it) {
+        const auto &enum_def = **it;
+        if (enum_def.defined_namespace != ns) { continue; }
+        if (!enum_def.generated) {
+          SetNameSpace(enum_def.defined_namespace);
+          GenEnum(enum_def);
+        }
+      }
+
+      // Generate code for all structs.
+      for (auto it = parser_.structs_.vec.begin();
+           it != parser_.structs_.vec.end(); ++it) {
+        const auto &struct_def = **it;
+        if (struct_def.defined_namespace != ns) { continue; }
+        if (struct_def.fixed && !struct_def.generated) {
+          SetNameSpace(struct_def.defined_namespace);
+          GenStruct(struct_def);
+        }
+      }
+
+      // Generate code for all tables.
+      for (auto it = parser_.structs_.vec.begin();
+           it != parser_.structs_.vec.end(); ++it) {
+        const auto &struct_def = **it;
+        if (struct_def.defined_namespace != ns) { continue; }
+        if (!struct_def.fixed && !struct_def.generated) {
+          SetNameSpace(struct_def.defined_namespace);
+          GenTable(struct_def);
+        }
+      }
+
+      // Generate global helper functions.
+      if (parser_.root_struct_def_) {
+        auto &struct_def = *parser_.root_struct_def_;
+        if (struct_def.defined_namespace != ns) { continue; }
+        SetNameSpace(struct_def.defined_namespace);
+        GenRootTableFuncs(struct_def);
+      }
+    }
+    if (cur_name_space_) SetNameSpace(nullptr);
+
+    const auto file_path = GeneratedFileName(path_, file_name_);
+    const auto final_code = code_.ToString();
+    return SaveFile(file_path.c_str(), final_code, false);
+  }
+
+ private:
+  CodeWriter code_;
+
+  std::set<std::string> keywords_;
+
+  // This tracks the current namespace so we can insert namespace declarations.
+  const Namespace *cur_name_space_;
+
+  const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+  // Determine if a Type needs a lifetime template parameter when used in the
+  // Rust builder args.
+  bool TableBuilderTypeNeedsLifetime(const Type &type) const {
+    switch (GetFullType(type)) {
+      case ftInteger:
+      case ftFloat:
+      case ftBool:
+      case ftEnumKey:
+      case ftUnionKey:
+      case ftUnionValue: { return false; }
+      default: { return true; }
+    }
+  }
+
+  // Determine if a table args rust type needs a lifetime template parameter.
+  bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const {
+    FLATBUFFERS_ASSERT(!struct_def.fixed);
+
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (field.deprecated) {
+        continue;
+      }
+
+      if (TableBuilderTypeNeedsLifetime(field.value.type)) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  // Determine if a Type needs to be copied (for endian safety) when used in a
+  // Struct.
+  bool StructMemberAccessNeedsCopy(const Type &type) const {
+    switch (GetFullType(type)) {
+      case ftInteger:  // requires endian swap
+      case ftFloat: // requires endian swap
+      case ftBool: // no endian-swap, but do the copy for UX consistency
+      case ftEnumKey: { return true; } // requires endian swap
+      case ftStruct: { return false; } // no endian swap
+      default: {
+        // logic error: no other types can be struct members.
+        FLATBUFFERS_ASSERT(false && "invalid struct member type");
+        return false; // only to satisfy compiler's return analysis
+      }
+    }
+  }
+
+  std::string EscapeKeyword(const std::string &name) const {
+    return keywords_.find(name) == keywords_.end() ? name : name + "_";
+  }
+
+  std::string Name(const Definition &def) const {
+    return EscapeKeyword(def.name);
+  }
+
+  std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
+
+  std::string WrapInNameSpace(const Definition &def) const {
+    return WrapInNameSpace(def.defined_namespace, Name(def));
+  }
+  std::string WrapInNameSpace(const Namespace *ns,
+                              const std::string &name) const {
+    if (CurrentNameSpace() == ns) return name;
+    std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns);
+    return prefix + name;
+  }
+
+  // Determine the namespace traversal needed from the Rust crate root.
+  // This may be useful in the future for referring to included files, but is
+  // currently unused.
+  std::string GetAbsoluteNamespaceTraversal(const Namespace *dst) const {
+    std::stringstream stream;
+
+    stream << "::";
+    for (auto d = dst->components.begin(); d != dst->components.end(); ++d) {
+      stream << MakeSnakeCase(*d) + "::";
+    }
+    return stream.str();
+  }
+
+  // Determine the relative namespace traversal needed to reference one
+  // namespace from another namespace. This is useful because it does not force
+  // the user to have a particular file layout. (If we output absolute
+  // namespace paths, that may require users to organize their Rust crates in a
+  // particular way.)
+  std::string GetRelativeNamespaceTraversal(const Namespace *src,
+                                            const Namespace *dst) const {
+    // calculate the path needed to reference dst from src.
+    // example: f(A::B::C, A::B::C) -> (none)
+    // example: f(A::B::C, A::B)    -> super::
+    // example: f(A::B::C, A::B::D) -> super::D
+    // example: f(A::B::C, A)       -> super::super::
+    // example: f(A::B::C, D)       -> super::super::super::D
+    // example: f(A::B::C, D::E)    -> super::super::super::D::E
+    // example: f(A, D::E)          -> super::D::E
+    // does not include leaf object (typically a struct type).
+
+    size_t i = 0;
+    std::stringstream stream;
+
+    auto s = src->components.begin();
+    auto d = dst->components.begin();
+    for(;;) {
+      if (s == src->components.end()) { break; }
+      if (d == dst->components.end()) { break; }
+      if (*s != *d) { break; }
+      ++s;
+      ++d;
+      ++i;
+    }
+
+    for (; s != src->components.end(); ++s) {
+      stream << "super::";
+    }
+    for (; d != dst->components.end(); ++d) {
+      stream << MakeSnakeCase(*d) + "::";
+    }
+    return stream.str();
+  }
+
+  // Generate a comment from the schema.
+  void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
+    std::string text;
+    ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
+    code_ += text + "\\";
+  }
+
+  // Return a Rust type from the table in idl.h.
+  std::string GetTypeBasic(const Type &type) const {
+    switch (GetFullType(type)) {
+      case ftInteger:
+      case ftFloat:
+      case ftBool:
+      case ftEnumKey:
+      case ftUnionKey: { break; }
+      default: { FLATBUFFERS_ASSERT(false && "incorrect type given");}
+    }
+
+    // clang-format off
+    static const char * const ctypename[] = {
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
+                           RTYPE, KTYPE) \
+            #RTYPE,
+        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+    #undef FLATBUFFERS_TD
+      // clang-format on
+    };
+
+    if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
+    return ctypename[type.base_type];
+  }
+
+  // Look up the native type for an enum. This will always be an integer like
+  // u8, i32, etc.
+  std::string GetEnumTypeForDecl(const Type &type) {
+    const auto ft = GetFullType(type);
+    if (!(ft == ftEnumKey || ft == ftUnionKey)) {
+      FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
+    }
+
+    static const char *ctypename[] = {
+    // clang-format off
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
+                           RTYPE, KTYPE) \
+            #RTYPE,
+        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+    #undef FLATBUFFERS_TD
+      // clang-format on
+    };
+
+    // Enums can be bools, but their Rust representation must be a u8, as used
+    // in the repr attribute (#[repr(bool)] is an invalid attribute).
+    if (type.base_type == BASE_TYPE_BOOL) return "u8";
+    return ctypename[type.base_type];
+  }
+
+  // Return a Rust type for any type (scalar, table, struct) specifically for
+  // using a FlatBuffer.
+  std::string GetTypeGet(const Type &type) const {
+    switch (GetFullType(type)) {
+      case ftInteger:
+      case ftFloat:
+      case ftBool:
+      case ftEnumKey:
+      case ftUnionKey: {
+        return GetTypeBasic(type); }
+      case ftTable: {
+        return WrapInNameSpace(type.struct_def->defined_namespace,
+                               type.struct_def->name) + "<'a>"; }
+      default: {
+        return WrapInNameSpace(type.struct_def->defined_namespace,
+                               type.struct_def->name); }
+    }
+  }
+
+  std::string GetEnumValUse(const EnumDef &enum_def,
+                            const EnumVal &enum_val) const {
+    return Name(enum_def) + "::" + Name(enum_val);
+  }
+
+  // Generate an enum declaration,
+  // an enum string lookup table,
+  // an enum match function,
+  // and an enum array of values
+  void GenEnum(const EnumDef &enum_def) {
+    code_.SetValue("ENUM_NAME", Name(enum_def));
+    code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
+
+    GenComment(enum_def.doc_comment);
+    code_ += "#[allow(non_camel_case_types)]";
+    code_ += "#[repr({{BASE_TYPE}})]";
+    code_ += "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]";
+    code_ += "pub enum " + Name(enum_def) + " {";
+
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      const auto &ev = **it;
+
+      GenComment(ev.doc_comment, "  ");
+      code_.SetValue("KEY", Name(ev));
+      code_.SetValue("VALUE", enum_def.ToString(ev));
+      code_ += "  {{KEY}} = {{VALUE}},";
+    }
+    const EnumVal *minv = enum_def.MinValue();
+    const EnumVal *maxv = enum_def.MaxValue();
+    FLATBUFFERS_ASSERT(minv && maxv);
+
+    code_ += "";
+    code_ += "}";
+    code_ += "";
+
+    code_.SetValue("ENUM_NAME", Name(enum_def));
+    code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
+    code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
+    code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv));
+    code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv));
+
+    // Generate enum constants, and impls for Follow, EndianScalar, and Push.
+    code_ += "const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
+    code_ += "{{ENUM_MIN_BASE_VALUE}};";
+    code_ += "const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
+    code_ += "{{ENUM_MAX_BASE_VALUE}};";
+    code_ += "";
+    code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
+    code_ += "  type Inner = Self;";
+    code_ += "  #[inline]";
+    code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+    code_ += "    flatbuffers::read_scalar_at::<Self>(buf, loc)";
+    code_ += "  }";
+    code_ += "}";
+    code_ += "";
+    code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
+    code_ += "  #[inline]";
+    code_ += "  fn to_little_endian(self) -> Self {";
+    code_ += "    let n = {{BASE_TYPE}}::to_le(self as {{BASE_TYPE}});";
+    code_ += "    let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
+    code_ += "    unsafe { *p }";
+    code_ += "  }";
+    code_ += "  #[inline]";
+    code_ += "  fn from_little_endian(self) -> Self {";
+    code_ += "    let n = {{BASE_TYPE}}::from_le(self as {{BASE_TYPE}});";
+    code_ += "    let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
+    code_ += "    unsafe { *p }";
+    code_ += "  }";
+    code_ += "}";
+    code_ += "";
+    code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
+    code_ += "    type Output = {{ENUM_NAME}};";
+    code_ += "    #[inline]";
+    code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
+    code_ += "        flatbuffers::emplace_scalar::<{{ENUM_NAME}}>"
+             "(dst, *self);";
+    code_ += "    }";
+    code_ += "}";
+    code_ += "";
+
+    // Generate an array of all enumeration values.
+    auto num_fields = NumToString(enum_def.size());
+    code_ += "#[allow(non_camel_case_types)]";
+    code_ += "const ENUM_VALUES_{{ENUM_NAME_CAPS}}:[{{ENUM_NAME}}; " +
+              num_fields + "] = [";
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      const auto &ev = **it;
+      auto value = GetEnumValUse(enum_def, ev);
+      auto suffix = *it != enum_def.Vals().back() ? "," : "";
+      code_ += "  " + value + suffix;
+    }
+    code_ += "];";
+    code_ += "";
+
+    // Generate a string table for enum values.
+    // Problem is, if values are very sparse that could generate really big
+    // tables. Ideally in that case we generate a map lookup instead, but for
+    // the moment we simply don't output a table at all.
+    auto range = enum_def.Distance();
+    // Average distance between values above which we consider a table
+    // "too sparse". Change at will.
+    static const uint64_t kMaxSparseness = 5;
+    if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
+      code_ += "#[allow(non_camel_case_types)]";
+      code_ += "const ENUM_NAMES_{{ENUM_NAME_CAPS}}:[&'static str; " +
+               NumToString(range + 1) + "] = [";
+
+      auto val = enum_def.Vals().front();
+      for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+           ++it) {
+        auto ev = *it;
+        for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
+          code_ += "    \"\",";
+        }
+        val = ev;
+        auto suffix = *it != enum_def.Vals().back() ? "," : "";
+        code_ += "    \"" + Name(*ev) + "\"" + suffix;
+      }
+      code_ += "];";
+      code_ += "";
+
+      code_ +=
+          "pub fn enum_name_{{ENUM_NAME_SNAKE}}(e: {{ENUM_NAME}}) -> "
+          "&'static str {";
+
+      code_ += "  let index = e as {{BASE_TYPE}}\\";
+      if (enum_def.MinValue()->IsNonZero()) {
+        auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
+        code_ += " - " + vals + " as {{BASE_TYPE}}\\";
+      }
+      code_ += ";";
+
+      code_ += "  ENUM_NAMES_{{ENUM_NAME_CAPS}}[index as usize]";
+      code_ += "}";
+      code_ += "";
+    }
+
+    if (enum_def.is_union) {
+      // Generate tyoesafe offset(s) for unions
+      code_.SetValue("NAME", Name(enum_def));
+      code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
+      code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
+    }
+  }
+
+  std::string GetFieldOffsetName(const FieldDef &field) {
+    return "VT_" + MakeUpper(Name(field));
+  }
+
+  std::string GetDefaultConstant(const FieldDef &field) {
+    return field.value.type.base_type == BASE_TYPE_FLOAT
+               ? field.value.constant + ""
+               : field.value.constant;
+  }
+
+  std::string GetDefaultScalarValue(const FieldDef &field) {
+    switch (GetFullType(field.value.type)) {
+      case ftInteger: { return GetDefaultConstant(field); }
+      case ftFloat: { return GetDefaultConstant(field); }
+      case ftBool: {
+        return field.value.constant == "0" ? "false" : "true";
+      }
+      case ftUnionKey:
+      case ftEnumKey: {
+        auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
+        assert(ev);
+        return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
+                               GetEnumValUse(*field.value.type.enum_def, *ev));
+      }
+
+      // All pointer-ish types have a default value of None, because they are
+      // wrapped in Option.
+      default: { return "None"; }
+    }
+  }
+
+  // Create the return type for fields in the *BuilderArgs structs that are
+  // used to create Tables.
+  //
+  // Note: we could make all inputs to the BuilderArgs be an Option, as well
+  // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
+  // know if the value is default or not, because there are three ways to
+  // return a default value:
+  // 1) return a stored value that happens to be the default,
+  // 2) return a hardcoded value because the relevant vtable field is not in
+  //    the vtable, or
+  // 3) return a hardcoded value because the vtable field value is set to zero.
+  std::string TableBuilderArgsDefnType(const FieldDef &field,
+                                       const std::string &lifetime) {
+    const Type& type = field.value.type;
+
+    switch (GetFullType(type)) {
+      case ftInteger:
+      case ftFloat:
+      case ftBool: {
+        const auto typname = GetTypeBasic(type);
+        return typname;
+      }
+      case ftStruct: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return "Option<&" + lifetime + " " + typname + ">";
+      }
+      case ftTable: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime + \
+               ">>>";
+      }
+      case ftString: {
+        return "Option<flatbuffers::WIPOffset<&" + lifetime + " str>>";
+      }
+      case ftEnumKey:
+      case ftUnionKey: {
+        const auto typname = WrapInNameSpace(*type.enum_def);
+        return typname;
+      }
+      case ftUnionValue: {
+        return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
+      }
+
+      case ftVectorOfInteger:
+      case ftVectorOfFloat: {
+        const auto typname = GetTypeBasic(type.VectorType());
+        return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+               lifetime + ",  " + typname + ">>>";
+      }
+      case ftVectorOfBool: {
+        return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+               lifetime + ", bool>>>";
+      }
+      case ftVectorOfEnumKey: {
+        const auto typname = WrapInNameSpace(*type.enum_def);
+        return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+               lifetime + ", " + typname + ">>>";
+      }
+      case ftVectorOfStruct: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+               lifetime + ", " + typname + ">>>";
+      }
+      case ftVectorOfTable: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+               lifetime + ", flatbuffers::ForwardsUOffset<" + typname + \
+               "<" + lifetime + ">>>>>";
+      }
+      case ftVectorOfString: {
+        return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+               lifetime + ", flatbuffers::ForwardsUOffset<&" + lifetime + \
+               " str>>>>";
+      }
+      case ftVectorOfUnionValue: {
+        const auto typname = WrapInNameSpace(*type.enum_def) + \
+                             "UnionTableOffset";
+        return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+               lifetime + ", flatbuffers::ForwardsUOffset<"
+               "flatbuffers::Table<" + lifetime + ">>>>";
+      }
+    }
+    return "INVALID_CODE_GENERATION"; // for return analysis
+  }
+
+  std::string TableBuilderArgsDefaultValue(const FieldDef &field) {
+    return GetDefaultScalarValue(field);
+  }
+  std::string TableBuilderAddFuncDefaultValue(const FieldDef &field) {
+    // All branches of switch do the same action!
+    switch (GetFullType(field.value.type)) {
+      case ftUnionKey:
+      case ftEnumKey: {
+        const std::string basetype = GetTypeBasic(field.value.type); //<- never used
+        return GetDefaultScalarValue(field);
+      }
+
+      default: { return GetDefaultScalarValue(field); }
+    }
+  }
+
+  std::string TableBuilderArgsAddFuncType(const FieldDef &field,
+                                          const std::string &lifetime) {
+    const Type& type = field.value.type;
+
+    switch (GetFullType(field.value.type)) {
+      case ftVectorOfStruct: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+               ", " + typname + ">>";
+      }
+      case ftVectorOfTable: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+               ", flatbuffers::ForwardsUOffset<" + typname + \
+               "<" + lifetime + ">>>>";
+      }
+      case ftVectorOfInteger:
+      case ftVectorOfFloat: {
+        const auto typname = GetTypeBasic(type.VectorType());
+        return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+               ", " + typname + ">>";
+      }
+      case ftVectorOfBool: {
+        return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+               ", bool>>";
+      }
+      case ftVectorOfString: {
+        return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+               ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
+      }
+      case ftVectorOfEnumKey: {
+        const auto typname = WrapInNameSpace(*type.enum_def);
+        return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+               ", " + typname + ">>";
+      }
+      case ftVectorOfUnionValue: {
+        return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+               ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + \
+               lifetime + ">>>";
+      }
+      case ftEnumKey: {
+        const auto typname = WrapInNameSpace(*type.enum_def);
+        return typname;
+      }
+      case ftStruct: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return "&" + lifetime + " " + typname + "";
+      }
+      case ftTable: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
+      }
+      case ftInteger:
+      case ftFloat: {
+        const auto typname = GetTypeBasic(type);
+        return typname;
+      }
+      case ftBool: {
+        return "bool";
+      }
+      case ftString: {
+        return "flatbuffers::WIPOffset<&" + lifetime + " str>";
+      }
+      case ftUnionKey: {
+        const auto typname = WrapInNameSpace(*type.enum_def);
+        return typname;
+      }
+      case ftUnionValue: {
+        return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
+      }
+    }
+
+    return "INVALID_CODE_GENERATION"; // for return analysis
+  }
+
+  std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
+    const Type& type = field.value.type;
+
+    switch (GetFullType(field.value.type)) {
+      case ftInteger:
+      case ftFloat: {
+        const auto typname = GetTypeBasic(field.value.type);
+        return "self.fbb_.push_slot::<" + typname + ">";
+      }
+      case ftBool: {
+        return "self.fbb_.push_slot::<bool>";
+      }
+
+      case ftEnumKey:
+      case ftUnionKey: {
+        const auto underlying_typname = GetTypeBasic(type);
+        return "self.fbb_.push_slot::<" + underlying_typname + ">";
+      }
+
+      case ftStruct: {
+        const std::string typname = WrapInNameSpace(*type.struct_def);
+        return "self.fbb_.push_slot_always::<&" + typname + ">";
+      }
+      case ftTable: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" + \
+               typname +  ">>";
+      }
+
+      case ftUnionValue:
+      case ftString:
+      case ftVectorOfInteger:
+      case ftVectorOfFloat:
+      case ftVectorOfBool:
+      case ftVectorOfEnumKey:
+      case ftVectorOfStruct:
+      case ftVectorOfTable:
+      case ftVectorOfString:
+      case ftVectorOfUnionValue: {
+        return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
+      }
+    }
+    return "INVALID_CODE_GENERATION"; // for return analysis
+  }
+
+  std::string GenTableAccessorFuncReturnType(const FieldDef &field,
+                                             const std::string &lifetime) {
+    const Type& type = field.value.type;
+
+    switch (GetFullType(field.value.type)) {
+      case ftInteger:
+      case ftFloat: {
+        const auto typname = GetTypeBasic(type);
+        return typname;
+      }
+      case ftBool: {
+        return "bool";
+      }
+      case ftStruct: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return WrapInOptionIfNotRequired("&" + lifetime + " " + typname, field.required);
+      }
+      case ftTable: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">", field.required);
+      }
+      case ftEnumKey:
+      case ftUnionKey: {
+        const auto typname = WrapInNameSpace(*type.enum_def);
+        return typname;
+      }
+
+      case ftUnionValue: {
+        return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">", field.required);
+      }
+      case ftString: {
+         return WrapInOptionIfNotRequired("&" + lifetime + " str", field.required);
+      }
+      case ftVectorOfInteger:
+      case ftVectorOfFloat: {
+        const auto typname = GetTypeBasic(type.VectorType());
+        if (IsOneByte(type.VectorType().base_type)) {
+          return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
+        }
+        return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
+      }
+      case ftVectorOfBool: {
+        return WrapInOptionIfNotRequired("&" + lifetime + " [bool]", field.required);
+      }
+      case ftVectorOfEnumKey: {
+        const auto typname = WrapInNameSpace(*type.enum_def);
+        return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
+      }
+      case ftVectorOfStruct: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
+      }
+      case ftVectorOfTable: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", flatbuffers::ForwardsUOffset<" + \
+               typname + "<" + lifetime + ">>>", field.required);
+      }
+      case ftVectorOfString: {
+        return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", flatbuffers::ForwardsUOffset<&" + \
+               lifetime + " str>>", field.required);
+      }
+      case ftVectorOfUnionValue: {
+        FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
+        // TODO(rw): when we do support these, we should consider using the
+        //           Into trait to convert tables to typesafe union values.
+        return "INVALID_CODE_GENERATION"; // for return analysis
+      }
+    }
+    return "INVALID_CODE_GENERATION"; // for return analysis
+  }
+
+  std::string GenTableAccessorFuncBody(const FieldDef &field,
+                                       const std::string &lifetime,
+                                       const std::string &offset_prefix) {
+    const std::string offset_name = offset_prefix + "::" + \
+                                    GetFieldOffsetName(field);
+    const Type& type = field.value.type;
+
+    switch (GetFullType(field.value.type)) {
+      case ftInteger:
+      case ftFloat:
+      case ftBool: {
+        const auto typname = GetTypeBasic(type);
+        const auto default_value = GetDefaultScalarValue(field);
+        return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" + \
+               default_value + ")).unwrap()";
+      }
+      case ftStruct: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return AddUnwrapIfRequired("self._tab.get::<" + typname + ">(" + offset_name + ", None)", field.required);
+      }
+      case ftTable: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + \
+               typname + "<" + lifetime + ">>>(" + offset_name + ", None)", field.required);
+      }
+      case ftUnionValue: {
+        return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
+               "flatbuffers::Table<" + lifetime + ">>>(" + offset_name + \
+               ", None)", field.required);
+      }
+      case ftUnionKey:
+      case ftEnumKey: {
+        const auto underlying_typname = GetTypeBasic(type); //<- never used
+        const auto typname = WrapInNameSpace(*type.enum_def);
+        const auto default_value = GetDefaultScalarValue(field);
+        return "self._tab.get::<" + typname + ">(" + offset_name + \
+               ", Some(" + default_value + ")).unwrap()";
+      }
+      case ftString: {
+        return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" + \
+               offset_name + ", None)", field.required);
+      }
+
+      case ftVectorOfInteger:
+      case ftVectorOfFloat: {
+        const auto typname = GetTypeBasic(type.VectorType());
+        std::string s = "self._tab.get::<flatbuffers::ForwardsUOffset<"
+                        "flatbuffers::Vector<" + lifetime + ", " + typname + \
+                        ">>>(" + offset_name + ", None)";
+        // single-byte values are safe to slice
+        if (IsOneByte(type.VectorType().base_type)) {
+          s += ".map(|v| v.safe_slice())";
+        }
+        return AddUnwrapIfRequired(s, field.required);
+      }
+      case ftVectorOfBool: {
+        return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
+               "flatbuffers::Vector<" + lifetime + ", bool>>>(" + \
+               offset_name + ", None).map(|v| v.safe_slice())", field.required);
+      }
+      case ftVectorOfEnumKey: {
+        const auto typname = WrapInNameSpace(*type.enum_def);
+        return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
+               "flatbuffers::Vector<" + lifetime + ", " + typname + ">>>(" + \
+               offset_name + ", None)", field.required);
+      }
+      case ftVectorOfStruct: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
+               "flatbuffers::Vector<" + typname + ">>>(" + \
+               offset_name + ", None).map(|v| v.safe_slice() )", field.required);
+      }
+      case ftVectorOfTable: {
+        const auto typname = WrapInNameSpace(*type.struct_def);
+        return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
+               "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" + typname + \
+               "<" + lifetime + ">>>>>(" + offset_name + ", None)", field.required);
+      }
+      case ftVectorOfString: {
+        return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
+               "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" + \
+               lifetime + " str>>>>(" + offset_name + ", None)", field.required);
+      }
+      case ftVectorOfUnionValue: {
+        FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
+        return "INVALID_CODE_GENERATION"; // for return analysis
+      }
+    }
+    return "INVALID_CODE_GENERATION"; // for return analysis
+  }
+
+  bool TableFieldReturnsOption(const Type& type) {
+    switch (GetFullType(type)) {
+      case ftInteger:
+      case ftFloat:
+      case ftBool:
+      case ftEnumKey:
+      case ftUnionKey:
+        return false;
+      default: return true;
+    }
+  }
+
+  // Generate an accessor struct, builder struct, and create function for a
+  // table.
+  void GenTable(const StructDef &struct_def) {
+    code_.SetValue("STRUCT_NAME", Name(struct_def));
+    code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
+    code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def)));
+
+    // Generate an offset type, the base type, the Follow impl, and the
+    // init_from_table impl.
+    code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
+    code_ += "#[derive(Copy, Clone, Debug, PartialEq)]";
+    code_ += "";
+
+    GenComment(struct_def.doc_comment);
+
+    code_ += "pub struct {{STRUCT_NAME}}<'a> {";
+    code_ += "  pub _tab: flatbuffers::Table<'a>,";
+    code_ += "}";
+    code_ += "";
+    code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {";
+    code_ += "    type Inner = {{STRUCT_NAME}}<'a>;";
+    code_ += "    #[inline]";
+    code_ += "    fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+    code_ += "        Self {";
+    code_ += "            _tab: flatbuffers::Table { buf: buf, loc: loc },";
+    code_ += "        }";
+    code_ += "    }";
+    code_ += "}";
+    code_ += "";
+    code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
+    code_ += "    #[inline]";
+    code_ += "    pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
+             "Self {";
+    code_ += "        {{STRUCT_NAME}} {";
+    code_ += "            _tab: table,";
+    code_ += "        }";
+    code_ += "    }";
+
+    // Generate a convenient create* function that uses the above builder
+    // to create a table in one function call.
+    code_.SetValue("MAYBE_US",
+        struct_def.fields.vec.size() == 0 ? "_" : "");
+    code_.SetValue("MAYBE_LT",
+        TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
+    code_ += "    #[allow(unused_mut)]";
+    code_ += "    pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
+    code_ += "        _fbb: "
+             "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
+    code_ += "        {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
+             " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
+
+    code_ += "      let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
+    for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
+         size; size /= 2) {
+      for (auto it = struct_def.fields.vec.rbegin();
+           it != struct_def.fields.vec.rend(); ++it) {
+        const auto &field = **it;
+        // TODO(rw): fully understand this sortbysize usage
+        if (!field.deprecated && (!struct_def.sortbysize ||
+                                  size == SizeOf(field.value.type.base_type))) {
+          code_.SetValue("FIELD_NAME", Name(field));
+          if (TableFieldReturnsOption(field.value.type)) {
+            code_ += "      if let Some(x) = args.{{FIELD_NAME}} "
+                     "{ builder.add_{{FIELD_NAME}}(x); }";
+          } else {
+            code_ += "      builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
+          }
+        }
+      }
+    }
+    code_ += "      builder.finish()";
+    code_ += "    }";
+    code_ += "";
+
+    // Generate field id constants.
+    if (struct_def.fields.vec.size() > 0) {
+      for (auto it = struct_def.fields.vec.begin();
+           it != struct_def.fields.vec.end(); ++it) {
+        const auto &field = **it;
+        if (field.deprecated) {
+          // Deprecated fields won't be accessible.
+          continue;
+        }
+
+        code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
+        code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
+        code_ += "    pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
+                 "{{OFFSET_VALUE}};";
+      }
+      code_ += "";
+    }
+
+    // Generate the accessors. Each has one of two forms:
+    //
+    // If a value can be None:
+    //   pub fn name(&'a self) -> Option<user_facing_type> {
+    //     self._tab.get::<internal_type>(offset, defaultval)
+    //   }
+    //
+    // If a value is always Some:
+    //   pub fn name(&'a self) -> user_facing_type {
+    //     self._tab.get::<internal_type>(offset, defaultval).unwrap()
+    //   }
+    const auto offset_prefix = Name(struct_def);
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (field.deprecated) {
+        // Deprecated fields won't be accessible.
+        continue;
+      }
+
+      code_.SetValue("FIELD_NAME", Name(field));
+      code_.SetValue("RETURN_TYPE",
+                     GenTableAccessorFuncReturnType(field, "'a"));
+      code_.SetValue("FUNC_BODY",
+                     GenTableAccessorFuncBody(field, "'a", offset_prefix));
+
+      GenComment(field.doc_comment, "  ");
+      code_ += "  #[inline]";
+      code_ += "  pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
+      code_ += "    {{FUNC_BODY}}";
+      code_ += "  }";
+
+      // Generate a comparison function for this field if it is a key.
+      if (field.key) {
+        GenKeyFieldMethods(field);
+      }
+
+      // Generate a nested flatbuffer field, if applicable.
+      auto nested = field.attributes.Lookup("nested_flatbuffer");
+      if (nested) {
+        std::string qualified_name = nested->constant;
+        auto nested_root = parser_.LookupStruct(nested->constant);
+        if (nested_root == nullptr) {
+          qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
+              nested->constant);
+          nested_root = parser_.LookupStruct(qualified_name);
+        }
+        FLATBUFFERS_ASSERT(nested_root);  // Guaranteed to exist by parser.
+        (void)nested_root;
+
+        code_.SetValue("OFFSET_NAME",
+                       offset_prefix + "::" + GetFieldOffsetName(field));
+        code_ += "  pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> "
+                 " Option<{{STRUCT_NAME}}<'a>> {";
+        code_ += "     match self.{{FIELD_NAME}}() {";
+        code_ += "         None => { None }";
+        code_ += "         Some(data) => {";
+        code_ += "             use self::flatbuffers::Follow;";
+        code_ += "             Some(<flatbuffers::ForwardsUOffset"
+                 "<{{STRUCT_NAME}}<'a>>>::follow(data, 0))";
+        code_ += "         },";
+        code_ += "     }";
+        code_ += "  }";
+      }
+    }
+
+    // Explicit specializations for union accessors
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
+        continue;
+      }
+
+      auto u = field.value.type.enum_def;
+
+      code_.SetValue("FIELD_NAME", Name(field));
+
+      for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
+        auto &ev = **u_it;
+        if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
+
+        auto table_init_type = WrapInNameSpace(
+          ev.union_type.struct_def->defined_namespace,
+          ev.union_type.struct_def->name);
+
+          code_.SetValue("U_ELEMENT_ENUM_TYPE",
+              WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
+        code_.SetValue("U_ELEMENT_TABLE_TYPE", table_init_type);
+        code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
+
+        code_ += "  #[inline]";
+        code_ += "  #[allow(non_snake_case)]";
+        code_ += "  pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> "
+                 "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
+        code_ += "    if self.{{FIELD_NAME}}_type() == {{U_ELEMENT_ENUM_TYPE}} {";
+        code_ += "      self.{{FIELD_NAME}}().map(|u| "
+                 "{{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
+        code_ += "    } else {";
+        code_ += "      None";
+        code_ += "    }";
+        code_ += "  }";
+        code_ += "";
+      }
+    }
+
+    code_ += "}";  // End of table impl.
+    code_ += "";
+
+    // Generate an args struct:
+    code_.SetValue("MAYBE_LT",
+        TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
+    code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (!field.deprecated) {
+        code_.SetValue("PARAM_NAME", Name(field));
+        code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a "));
+        code_ += "    pub {{PARAM_NAME}}: {{PARAM_TYPE}},";
+      }
+    }
+    code_ += "}";
+
+    // Generate an impl of Default for the *Args type:
+    code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
+    code_ += "    #[inline]";
+    code_ += "    fn default() -> Self {";
+    code_ += "        {{STRUCT_NAME}}Args {";
+    for (auto it = struct_def.fields.vec.begin();
+        it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (!field.deprecated) {
+        code_.SetValue("PARAM_VALUE", TableBuilderArgsDefaultValue(field));
+        code_.SetValue("REQ", field.required ? " // required field" : "");
+        code_.SetValue("PARAM_NAME", Name(field));
+        code_ += "            {{PARAM_NAME}}: {{PARAM_VALUE}},{{REQ}}";
+      }
+    }
+    code_ += "        }";
+    code_ += "    }";
+    code_ += "}";
+
+    // Generate a builder struct:
+    code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
+    code_ += "  fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
+    code_ += "  start_: flatbuffers::WIPOffset<"
+             "flatbuffers::TableUnfinishedWIPOffset>,";
+    code_ += "}";
+
+    // Generate builder functions:
+    code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (!field.deprecated) {
+        const bool is_scalar = IsScalar(field.value.type.base_type);
+
+        std::string offset = GetFieldOffsetName(field);
+
+        // Generate functions to add data, which take one of two forms.
+        //
+        // If a value has a default:
+        //   fn add_x(x_: type) {
+        //     fbb_.push_slot::<type>(offset, x_, Some(default));
+        //   }
+        //
+        // If a value does not have a default:
+        //   fn add_x(x_: type) {
+        //     fbb_.push_slot_always::<type>(offset, x_);
+        //   }
+        code_.SetValue("FIELD_NAME", Name(field));
+        code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
+        code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
+        code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
+        code_ += "  #[inline]";
+        code_ += "  pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
+                 "{{FIELD_TYPE}}) {";
+        if (is_scalar) {
+          code_.SetValue("FIELD_DEFAULT_VALUE",
+                         TableBuilderAddFuncDefaultValue(field));
+          code_ += "    {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
+                   "{{FIELD_DEFAULT_VALUE}});";
+        } else {
+          code_ += "    {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
+        }
+        code_ += "  }";
+      }
+    }
+
+    // Struct initializer (all fields required);
+    code_ += "  #[inline]";
+    code_ +=
+        "  pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
+        "{{STRUCT_NAME}}Builder<'a, 'b> {";
+    code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
+    code_ += "    let start = _fbb.start_table();";
+    code_ += "    {{STRUCT_NAME}}Builder {";
+    code_ += "      fbb_: _fbb,";
+    code_ += "      start_: start,";
+    code_ += "    }";
+    code_ += "  }";
+
+    // finish() function.
+    code_ += "  #[inline]";
+    code_ += "  pub fn finish(self) -> "
+             "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
+    code_ += "    let o = self.fbb_.end_table(self.start_);";
+
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (!field.deprecated && field.required) {
+        code_.SetValue("FIELD_NAME", MakeSnakeCase(Name(field)));
+        code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
+        code_ += "    self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
+                 "\"{{FIELD_NAME}}\");";
+      }
+    }
+    code_ += "    flatbuffers::WIPOffset::new(o.value())";
+    code_ += "  }";
+    code_ += "}";
+    code_ += "";
+  }
+
+  // Generate functions to compare tables and structs by key. This function
+  // must only be called if the field key is defined.
+  void GenKeyFieldMethods(const FieldDef &field) {
+    FLATBUFFERS_ASSERT(field.key);
+
+    code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
+
+    code_ += "  #[inline]";
+    code_ += "  pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
+             " bool {";
+    code_ += "    self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
+    code_ += "  }";
+    code_ += "";
+    code_ += "  #[inline]";
+    code_ += "  pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
+             " ::std::cmp::Ordering {";
+    code_ += "    let key = self.{{FIELD_NAME}}();";
+    code_ += "    key.cmp(&val)";
+    code_ += "  }";
+  }
+
+  // Generate functions for accessing the root table object. This function
+  // must only be called if the root table is defined.
+  void GenRootTableFuncs(const StructDef &struct_def) {
+    FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
+    auto name = Name(struct_def);
+
+    code_.SetValue("STRUCT_NAME", name);
+    code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name));
+    code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name)));
+
+    // The root datatype accessors:
+    code_ += "#[inline]";
+    code_ +=
+        "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
+        " -> {{STRUCT_NAME}}<'a> {";
+    code_ += "  flatbuffers::get_root::<{{STRUCT_NAME}}<'a>>(buf)";
+    code_ += "}";
+    code_ += "";
+
+    code_ += "#[inline]";
+    code_ += "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
+             "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
+    code_ += "  flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>"
+             "(buf)";
+    code_ += "}";
+    code_ += "";
+
+    if (parser_.file_identifier_.length()) {
+      // Declare the identifier
+      code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &'static str\\";
+      code_ += " = \"" + parser_.file_identifier_ + "\";";
+      code_ += "";
+
+      // Check if a buffer has the identifier.
+      code_ += "#[inline]";
+      code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
+      code_ += "(buf: &[u8]) -> bool {";
+      code_ += "  return flatbuffers::buffer_has_identifier(buf, \\";
+      code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false);";
+      code_ += "}";
+      code_ += "";
+      code_ += "#[inline]";
+      code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
+      code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
+      code_ += "  return flatbuffers::buffer_has_identifier(buf, \\";
+      code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true);";
+      code_ += "}";
+      code_ += "";
+    }
+
+    if (parser_.file_extension_.length()) {
+      // Return the extension
+      code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &'static str = \\";
+      code_ += "\"" + parser_.file_extension_ + "\";";
+      code_ += "";
+    }
+
+    // Finish a buffer with a given root object:
+    code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
+    code_ += "#[inline]";
+    code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>(";
+    code_ += "    fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
+    code_ += "    root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
+    if (parser_.file_identifier_.length()) {
+      code_ += "  fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
+    } else {
+      code_ += "  fbb.finish(root, None);";
+    }
+    code_ += "}";
+    code_ += "";
+    code_ += "#[inline]";
+    code_ += "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
+             "<'a, 'b>("
+             "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
+             "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
+    if (parser_.file_identifier_.length()) {
+      code_ += "  fbb.finish_size_prefixed(root, "
+               "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
+    } else {
+      code_ += "  fbb.finish_size_prefixed(root, None);";
+    }
+    code_ += "}";
+  }
+
+  static void GenPadding(
+      const FieldDef &field, std::string *code_ptr, int *id,
+      const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
+    if (field.padding) {
+      for (int i = 0; i < 4; i++) {
+        if (static_cast<int>(field.padding) & (1 << i)) {
+          f((1 << i) * 8, code_ptr, id);
+        }
+      }
+      assert(!(field.padding & ~0xF));
+    }
+  }
+
+  static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
+    *code_ptr += "  padding" + NumToString((*id)++) + "__: u" + \
+                 NumToString(bits) + ",";
+  }
+
+  static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
+    (void)bits;
+    *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
+  }
+
+  // Generate an accessor struct with constructor for a flatbuffers struct.
+  void GenStruct(const StructDef &struct_def) {
+    // Generates manual padding and alignment.
+    // Variables are private because they contain little endian data on all
+    // platforms.
+    GenComment(struct_def.doc_comment);
+    code_.SetValue("ALIGN", NumToString(struct_def.minalign));
+    code_.SetValue("STRUCT_NAME", Name(struct_def));
+
+    code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}";
+    code_ += "#[repr(C, align({{ALIGN}}))]";
+
+    // PartialEq is useful to derive because we can correctly compare structs
+    // for equality by just comparing their underlying byte data. This doesn't
+    // hold for PartialOrd/Ord.
+    code_ += "#[derive(Clone, Copy, Debug, PartialEq)]";
+    code_ += "pub struct {{STRUCT_NAME}} {";
+
+    int padding_id = 0;
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
+      code_.SetValue("FIELD_NAME", Name(field));
+      code_ += "  {{FIELD_NAME}}_: {{FIELD_TYPE}},";
+
+      if (field.padding) {
+        std::string padding;
+        GenPadding(field, &padding, &padding_id, PaddingDefinition);
+        code_ += padding;
+      }
+    }
+
+    code_ += "} // pub struct {{STRUCT_NAME}}";
+
+    // Generate impls for SafeSliceAccess (because all structs are endian-safe),
+    // Follow for the value type, Follow for the reference type, Push for the
+    // value type, and Push for the reference type.
+    code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
+    code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
+    code_ += "  type Inner = &'a {{STRUCT_NAME}};";
+    code_ += "  #[inline]";
+    code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+    code_ += "    <&'a {{STRUCT_NAME}}>::follow(buf, loc)";
+    code_ += "  }";
+    code_ += "}";
+    code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {";
+    code_ += "  type Inner = &'a {{STRUCT_NAME}};";
+    code_ += "  #[inline]";
+    code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+    code_ += "    flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)";
+    code_ += "  }";
+    code_ += "}";
+    code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {";
+    code_ += "    type Output = {{STRUCT_NAME}};";
+    code_ += "    #[inline]";
+    code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
+    code_ += "        let src = unsafe {";
+    code_ += "            ::std::slice::from_raw_parts("
+             "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
+    code_ += "        };";
+    code_ += "        dst.copy_from_slice(src);";
+    code_ += "    }";
+    code_ += "}";
+    code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {";
+    code_ += "    type Output = {{STRUCT_NAME}};";
+    code_ += "";
+    code_ += "    #[inline]";
+    code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
+    code_ += "        let src = unsafe {";
+    code_ += "            ::std::slice::from_raw_parts("
+             "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
+    code_ += "        };";
+    code_ += "        dst.copy_from_slice(src);";
+    code_ += "    }";
+    code_ += "}";
+    code_ += "";
+    code_ += "";
+
+    // Generate a constructor that takes all fields as arguments.
+    code_ += "impl {{STRUCT_NAME}} {";
+    std::string arg_list;
+    std::string init_list;
+    padding_id = 0;
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      const auto member_name = Name(field) + "_";
+      const auto reference = StructMemberAccessNeedsCopy(field.value.type)
+                             ? "" : "&'a ";
+      const auto arg_name = "_" + Name(field);
+      const auto arg_type = reference + GetTypeGet(field.value.type);
+
+      if (it != struct_def.fields.vec.begin()) {
+        arg_list += ", ";
+      }
+      arg_list += arg_name + ": ";
+      arg_list += arg_type;
+      init_list += "      " + member_name;
+      if (StructMemberAccessNeedsCopy(field.value.type)) {
+        init_list += ": " + arg_name + ".to_little_endian(),\n";
+      } else {
+        init_list += ": *" + arg_name + ",\n";
+      }
+    }
+
+    code_.SetValue("ARG_LIST", arg_list);
+    code_.SetValue("INIT_LIST", init_list);
+    code_ += "  pub fn new<'a>({{ARG_LIST}}) -> Self {";
+    code_ += "    {{STRUCT_NAME}} {";
+    code_ += "{{INIT_LIST}}";
+    padding_id = 0;
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (field.padding) {
+        std::string padding;
+        GenPadding(field, &padding, &padding_id, PaddingInitializer);
+        code_ += "      " + padding;
+      }
+    }
+    code_ += "    }";
+    code_ += "  }";
+
+    // Generate accessor methods for the struct.
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+
+      auto field_type = TableBuilderArgsAddFuncType(field, "'a");
+      auto member = "self." + Name(field) + "_";
+      auto value = StructMemberAccessNeedsCopy(field.value.type) ?
+        member + ".from_little_endian()" : member;
+
+      code_.SetValue("FIELD_NAME", Name(field));
+      code_.SetValue("FIELD_TYPE", field_type);
+      code_.SetValue("FIELD_VALUE", value);
+      code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
+
+      GenComment(field.doc_comment, "  ");
+      code_ += "  pub fn {{FIELD_NAME}}<'a>(&'a self) -> {{FIELD_TYPE}} {";
+      code_ += "    {{REF}}{{FIELD_VALUE}}";
+      code_ += "  }";
+
+      // Generate a comparison function for this field if it is a key.
+      if (field.key) {
+        GenKeyFieldMethods(field);
+      }
+    }
+    code_ += "}";
+    code_ += "";
+  }
+
+  void GenNamespaceImports(const int white_spaces) {
+      std::string indent = std::string(white_spaces, ' ');
+      code_ += "";
+      code_ += indent + "use std::mem;";
+      code_ += indent + "use std::cmp::Ordering;";
+      code_ += "";
+      code_ += indent + "extern crate flatbuffers;";
+      code_ += indent + "use self::flatbuffers::EndianScalar;";
+  }
+
+  // Set up the correct namespace. This opens a namespace if the current
+  // namespace is different from the target namespace. This function
+  // closes and opens the namespaces only as necessary.
+  //
+  // The file must start and end with an empty (or null) namespace so that
+  // namespaces are properly opened and closed.
+  void SetNameSpace(const Namespace *ns) {
+    if (cur_name_space_ == ns) { return; }
+
+    // Compute the size of the longest common namespace prefix.
+    // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
+    // the common prefix is A::B:: and we have old_size = 4, new_size = 5
+    // and common_prefix_size = 2
+    size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
+    size_t new_size = ns ? ns->components.size() : 0;
+
+    size_t common_prefix_size = 0;
+    while (common_prefix_size < old_size && common_prefix_size < new_size &&
+           ns->components[common_prefix_size] ==
+               cur_name_space_->components[common_prefix_size]) {
+      common_prefix_size++;
+    }
+
+    // Close cur_name_space in reverse order to reach the common prefix.
+    // In the previous example, D then C are closed.
+    for (size_t j = old_size; j > common_prefix_size; --j) {
+      code_ += "}  // pub mod " + cur_name_space_->components[j - 1];
+    }
+    if (old_size != common_prefix_size) { code_ += ""; }
+
+    // open namespace parts to reach the ns namespace
+    // in the previous example, E, then F, then G are opened
+    for (auto j = common_prefix_size; j != new_size; ++j) {
+      code_ += "#[allow(unused_imports, dead_code)]";
+      code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {";
+      // Generate local namespace imports.
+      GenNamespaceImports(2);
+    }
+    if (new_size != common_prefix_size) { code_ += ""; }
+
+    cur_name_space_ = ns;
+  }
+};
+
+}  // namespace rust
+
+bool GenerateRust(const Parser &parser, const std::string &path,
+                  const std::string &file_name) {
+  rust::RustGenerator generator(parser, path, file_name);
+  return generator.generate();
+}
+
+std::string RustMakeRule(const Parser &parser, const std::string &path,
+                         const std::string &file_name) {
+  std::string filebase =
+      flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+  std::string make_rule = GeneratedFileName(path, filebase) + ": ";
+
+  auto included_files = parser.GetIncludedFilesRecursive(file_name);
+  for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+    make_rule += " " + *it;
+  }
+  return make_rule;
+}
+
+}  // namespace flatbuffers
+
+// TODO(rw): Generated code should import other generated files.
+// TODO(rw): Generated code should refer to namespaces in included files in a
+//           way that makes them referrable.
+// TODO(rw): Generated code should indent according to nesting level.
+// TODO(rw): Generated code should generate endian-safe Debug impls.
+// TODO(rw): Generated code could use a Rust-only enum type to access unions,
+//           instead of making the user use _type() to manually switch.
diff --git a/src/idl_gen_text.cpp b/src/idl_gen_text.cpp
new file mode 100644
index 0000000..9825dce
--- /dev/null
+++ b/src/idl_gen_text.cpp
@@ -0,0 +1,378 @@
+/*
+ * Copyright 2014 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.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/flexbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+static bool GenStruct(const StructDef &struct_def, const Table *table,
+                      int indent, const IDLOptions &opts, std::string *_text);
+
+// If indentation is less than 0, that indicates we don't want any newlines
+// either.
+const char *NewLine(const IDLOptions &opts) {
+  return opts.indent_step >= 0 ? "\n" : "";
+}
+
+int Indent(const IDLOptions &opts) { return std::max(opts.indent_step, 0); }
+
+// Output an identifier with or without quotes depending on strictness.
+void OutputIdentifier(const std::string &name, const IDLOptions &opts,
+                      std::string *_text) {
+  std::string &text = *_text;
+  if (opts.strict_json) text += "\"";
+  text += name;
+  if (opts.strict_json) text += "\"";
+}
+
+// Print (and its template specialization below for pointers) generate text
+// for a single FlatBuffer value into JSON format.
+// The general case for scalars:
+template<typename T>
+bool Print(T val, Type type, int /*indent*/, Type * /*union_type*/,
+           const IDLOptions &opts, std::string *_text) {
+  std::string &text = *_text;
+  if (type.enum_def && opts.output_enum_identifiers) {
+    std::vector<EnumVal const *> enum_values;
+    if (auto ev = type.enum_def->ReverseLookup(static_cast<int64_t>(val))) {
+      enum_values.push_back(ev);
+    } else if (val && type.enum_def->attributes.Lookup("bit_flags")) {
+      for (auto it = type.enum_def->Vals().begin(),
+                e = type.enum_def->Vals().end();
+           it != e; ++it) {
+        if ((*it)->GetAsUInt64() & static_cast<uint64_t>(val))
+          enum_values.push_back(*it);
+      }
+    }
+    if (!enum_values.empty()) {
+      text += '\"';
+      for (auto it = enum_values.begin(), e = enum_values.end(); it != e; ++it)
+        text += (*it)->name + ' ';
+      text[text.length() - 1] = '\"';
+      return true;
+    }
+  }
+
+  if (type.base_type == BASE_TYPE_BOOL) {
+    text += val != 0 ? "true" : "false";
+  } else {
+    text += NumToString(val);
+  }
+
+  return true;
+}
+
+// Print a vector or an array of JSON values, comma seperated, wrapped in "[]".
+template<typename T, typename Container>
+bool PrintContainer(const Container &c, size_t size, Type type, int indent,
+                    const IDLOptions &opts, std::string *_text) {
+  std::string &text = *_text;
+  text += "[";
+  text += NewLine(opts);
+  for (uoffset_t i = 0; i < size; i++) {
+    if (i) {
+      if (!opts.protobuf_ascii_alike) text += ",";
+      text += NewLine(opts);
+    }
+    text.append(indent + Indent(opts), ' ');
+    if (IsStruct(type)) {
+      if (!Print(reinterpret_cast<const void *>(c.Data() +
+                                                i * type.struct_def->bytesize),
+                 type, indent + Indent(opts), nullptr, opts, _text)) {
+        return false;
+      }
+    } else {
+      if (!Print(c[i], type, indent + Indent(opts), nullptr, opts, _text)) {
+        return false;
+      }
+    }
+  }
+  text += NewLine(opts);
+  text.append(indent, ' ');
+  text += "]";
+  return true;
+}
+
+template<typename T>
+bool PrintVector(const Vector<T> &v, Type type, int indent,
+                 const IDLOptions &opts, std::string *_text) {
+  return PrintContainer<T, Vector<T>>(v, v.size(), type, indent, opts, _text);
+}
+
+// Print an array a sequence of JSON values, comma separated, wrapped in "[]".
+template<typename T>
+bool PrintArray(const Array<T, 0xFFFF> &a, size_t size, Type type, int indent,
+                const IDLOptions &opts, std::string *_text) {
+  return PrintContainer<T, Array<T, 0xFFFF>>(a, size, type, indent, opts,
+                                             _text);
+}
+
+// Specialization of Print above for pointer types.
+template<>
+bool Print<const void *>(const void *val, Type type, int indent,
+                         Type *union_type, const IDLOptions &opts,
+                         std::string *_text) {
+  switch (type.base_type) {
+    case BASE_TYPE_UNION:
+      // If this assert hits, you have an corrupt buffer, a union type field
+      // was not present or was out of range.
+      FLATBUFFERS_ASSERT(union_type);
+      return Print<const void *>(val, *union_type, indent, nullptr, opts,
+                                 _text);
+    case BASE_TYPE_STRUCT:
+      if (!GenStruct(*type.struct_def, reinterpret_cast<const Table *>(val),
+                     indent, opts, _text)) {
+        return false;
+      }
+      break;
+    case BASE_TYPE_STRING: {
+      auto s = reinterpret_cast<const String *>(val);
+      if (!EscapeString(s->c_str(), s->size(), _text, opts.allow_non_utf8,
+                        opts.natural_utf8)) {
+        return false;
+      }
+      break;
+    }
+    case BASE_TYPE_VECTOR: {
+      const auto vec_type = type.VectorType();
+      // Call PrintVector above specifically for each element type:
+      // clang-format off
+      switch (vec_type.base_type) {
+        #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+          CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+          case BASE_TYPE_ ## ENUM: \
+            if (!PrintVector<CTYPE>( \
+                  *reinterpret_cast<const Vector<CTYPE> *>(val), \
+                  vec_type, indent, opts, _text)) { \
+              return false; \
+            } \
+            break;
+          FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+        #undef FLATBUFFERS_TD
+      }
+      // clang-format on
+      break;
+    }
+    case BASE_TYPE_ARRAY: {
+      const auto vec_type = type.VectorType();
+      // Call PrintArray above specifically for each element type:
+      // clang-format off
+      switch (vec_type.base_type) {
+        #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+        CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+        case BASE_TYPE_ ## ENUM: \
+          if (!PrintArray<CTYPE>( \
+              *reinterpret_cast<const Array<CTYPE, 0xFFFF> *>(val), \
+              type.fixed_length, \
+              vec_type, indent, opts, _text)) { \
+          return false; \
+          } \
+          break;
+        FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
+        FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
+        #undef FLATBUFFERS_TD
+        case BASE_TYPE_ARRAY: FLATBUFFERS_ASSERT(0);
+      }
+      // clang-format on
+      break;
+    }
+    default: FLATBUFFERS_ASSERT(0);
+  }
+  return true;
+}
+
+template<typename T> static T GetFieldDefault(const FieldDef &fd) {
+  T val;
+  auto check = StringToNumber(fd.value.constant.c_str(), &val);
+  (void)check;
+  FLATBUFFERS_ASSERT(check);
+  return val;
+}
+
+// Generate text for a scalar field.
+template<typename T>
+static bool GenField(const FieldDef &fd, const Table *table, bool fixed,
+                     const IDLOptions &opts, int indent, std::string *_text) {
+  return Print(
+      fixed ? reinterpret_cast<const Struct *>(table)->GetField<T>(
+                  fd.value.offset)
+            : table->GetField<T>(fd.value.offset, GetFieldDefault<T>(fd)),
+      fd.value.type, indent, nullptr, opts, _text);
+}
+
+static bool GenStruct(const StructDef &struct_def, const Table *table,
+                      int indent, const IDLOptions &opts, std::string *_text);
+
+// Generate text for non-scalar field.
+static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
+                           int indent, Type *union_type, const IDLOptions &opts,
+                           std::string *_text) {
+  const void *val = nullptr;
+  if (fixed) {
+    // The only non-scalar fields in structs are structs or arrays.
+    FLATBUFFERS_ASSERT(IsStruct(fd.value.type) || IsArray(fd.value.type));
+    val = reinterpret_cast<const Struct *>(table)->GetStruct<const void *>(
+        fd.value.offset);
+  } else if (fd.flexbuffer) {
+    auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
+    auto root = flexbuffers::GetRoot(vec->data(), vec->size());
+    root.ToString(true, opts.strict_json, *_text);
+    return true;
+  } else if (fd.nested_flatbuffer) {
+    auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
+    auto root = GetRoot<Table>(vec->data());
+    return GenStruct(*fd.nested_flatbuffer, root, indent, opts, _text);
+  } else {
+    val = IsStruct(fd.value.type)
+              ? table->GetStruct<const void *>(fd.value.offset)
+              : table->GetPointer<const void *>(fd.value.offset);
+  }
+  return Print(val, fd.value.type, indent, union_type, opts, _text);
+}
+
+// Generate text for a struct or table, values separated by commas, indented,
+// and bracketed by "{}"
+static bool GenStruct(const StructDef &struct_def, const Table *table,
+                      int indent, const IDLOptions &opts, std::string *_text) {
+  std::string &text = *_text;
+  text += "{";
+  int fieldout = 0;
+  Type *union_type = nullptr;
+  for (auto it = struct_def.fields.vec.begin();
+       it != struct_def.fields.vec.end(); ++it) {
+    FieldDef &fd = **it;
+    auto is_present = struct_def.fixed || table->CheckField(fd.value.offset);
+    auto output_anyway = opts.output_default_scalars_in_json &&
+                         IsScalar(fd.value.type.base_type) && !fd.deprecated;
+    if (is_present || output_anyway) {
+      if (fieldout++) {
+        if (!opts.protobuf_ascii_alike) text += ",";
+      }
+      text += NewLine(opts);
+      text.append(indent + Indent(opts), ' ');
+      OutputIdentifier(fd.name, opts, _text);
+      if (!opts.protobuf_ascii_alike ||
+          (fd.value.type.base_type != BASE_TYPE_STRUCT &&
+           fd.value.type.base_type != BASE_TYPE_VECTOR))
+        text += ":";
+      text += " ";
+      switch (fd.value.type.base_type) {
+          // clang-format off
+          #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+            CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+            case BASE_TYPE_ ## ENUM: \
+              if (!GenField<CTYPE>(fd, table, struct_def.fixed, \
+                                   opts, indent + Indent(opts), _text)) { \
+                return false; \
+              } \
+              break;
+          FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
+        #undef FLATBUFFERS_TD
+        // Generate drop-thru case statements for all pointer types:
+        #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+          CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+          case BASE_TYPE_ ## ENUM:
+          FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
+          FLATBUFFERS_GEN_TYPE_ARRAY(FLATBUFFERS_TD)
+        #undef FLATBUFFERS_TD
+            if (!GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
+                                union_type, opts, _text)) {
+              return false;
+            }
+            break;
+          // clang-format on
+      }
+      if (fd.value.type.base_type == BASE_TYPE_UTYPE) {
+        auto enum_val = fd.value.type.enum_def->ReverseLookup(
+            table->GetField<uint8_t>(fd.value.offset, 0), true);
+        union_type = enum_val ? &enum_val->union_type : nullptr;
+      }
+    }
+  }
+  text += NewLine(opts);
+  text.append(indent, ' ');
+  text += "}";
+  return true;
+}
+
+// Generate a text representation of a flatbuffer in JSON format.
+bool GenerateTextFromTable(const Parser &parser, const void *table,
+                           const std::string &table_name, std::string *_text) {
+  auto struct_def = parser.LookupStruct(table_name);
+  if (struct_def == nullptr) {
+    return false;
+  }
+  auto &text = *_text;
+  text.reserve(1024);  // Reduce amount of inevitable reallocs.
+  auto root = static_cast<const Table *>(table);
+  if (!GenStruct(*struct_def, root, 0, parser.opts, &text)) {
+    return false;
+  }
+  text += NewLine(parser.opts);
+  return true;
+}
+
+// Generate a text representation of a flatbuffer in JSON format.
+bool GenerateText(const Parser &parser, const void *flatbuffer,
+                  std::string *_text) {
+  std::string &text = *_text;
+  FLATBUFFERS_ASSERT(parser.root_struct_def_);  // call SetRootType()
+  text.reserve(1024);               // Reduce amount of inevitable reallocs.
+  auto root = parser.opts.size_prefixed ?
+      GetSizePrefixedRoot<Table>(flatbuffer) : GetRoot<Table>(flatbuffer);
+  if (!GenStruct(*parser.root_struct_def_, root, 0, parser.opts, _text)) {
+    return false;
+  }
+  text += NewLine(parser.opts);
+  return true;
+}
+
+std::string TextFileName(const std::string &path,
+                         const std::string &file_name) {
+  return path + file_name + ".json";
+}
+
+bool GenerateTextFile(const Parser &parser, const std::string &path,
+                      const std::string &file_name) {
+  if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
+  std::string text;
+  if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &text)) {
+    return false;
+  }
+  return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(), text,
+                               false);
+}
+
+std::string TextMakeRule(const Parser &parser, const std::string &path,
+                         const std::string &file_name) {
+  if (!parser.builder_.GetSize() || !parser.root_struct_def_) return "";
+  std::string filebase =
+      flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+  std::string make_rule = TextFileName(path, filebase) + ": " + file_name;
+  auto included_files =
+      parser.GetIncludedFilesRecursive(parser.root_struct_def_->file);
+  for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+    make_rule += " " + *it;
+  }
+  return make_rule;
+}
+
+}  // namespace flatbuffers
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp
new file mode 100644
index 0000000..31b315c
--- /dev/null
+++ b/src/idl_parser.cpp
@@ -0,0 +1,3518 @@
+/*
+ * Copyright 2014 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 <algorithm>
+#include <list>
+#include <string>
+#include <utility>
+
+#include <cmath>
+
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+// Reflects the version at the compiling time of binary(lib/dll/so).
+const char *FLATBUFFERS_VERSION() {
+  // clang-format off
+  return
+      FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "."
+      FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "."
+      FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION);
+  // clang-format on
+}
+
+const double kPi = 3.14159265358979323846;
+
+const char *const kTypeNames[] = {
+// clang-format off
+  #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+    CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+    IDLTYPE,
+    FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+  #undef FLATBUFFERS_TD
+  // clang-format on
+  nullptr
+};
+
+const char kTypeSizes[] = {
+// clang-format off
+  #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+      CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+      sizeof(CTYPE),
+    FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+  #undef FLATBUFFERS_TD
+  // clang-format on
+};
+
+// The enums in the reflection schema should match the ones we use internally.
+// Compare the last element to check if these go out of sync.
+static_assert(BASE_TYPE_UNION == static_cast<BaseType>(reflection::Union),
+              "enums don't match");
+
+// Any parsing calls have to be wrapped in this macro, which automates
+// handling of recursive error checking a bit. It will check the received
+// CheckedError object, and return straight away on error.
+#define ECHECK(call)           \
+  {                            \
+    auto ce = (call);          \
+    if (ce.Check()) return ce; \
+  }
+
+// These two functions are called hundreds of times below, so define a short
+// form:
+#define NEXT() ECHECK(Next())
+#define EXPECT(tok) ECHECK(Expect(tok))
+
+static bool ValidateUTF8(const std::string &str) {
+  const char *s = &str[0];
+  const char *const sEnd = s + str.length();
+  while (s < sEnd) {
+    if (FromUTF8(&s) < 0) { return false; }
+  }
+  return true;
+}
+
+// Convert an underscore_based_indentifier in to camelCase.
+// Also uppercases the first character if first is true.
+std::string MakeCamel(const std::string &in, bool first) {
+  std::string s;
+  for (size_t i = 0; i < in.length(); i++) {
+    if (!i && first)
+      s += static_cast<char>(toupper(in[0]));
+    else if (in[i] == '_' && i + 1 < in.length())
+      s += static_cast<char>(toupper(in[++i]));
+    else
+      s += in[i];
+  }
+  return s;
+}
+
+void DeserializeDoc( std::vector<std::string> &doc,
+                     const Vector<Offset<String>> *documentation) {
+  if (documentation == nullptr) return;
+  for (uoffset_t index = 0; index < documentation->size(); index++)
+    doc.push_back(documentation->Get(index)->str());
+}
+
+void Parser::Message(const std::string &msg) {
+  if (!error_.empty()) error_ += "\n";  // log all warnings and errors
+  error_ += file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : "";
+  // clang-format off
+
+  #ifdef _WIN32  // MSVC alike
+    error_ +=
+        "(" + NumToString(line_) + ", " + NumToString(CursorPosition()) + ")";
+  #else  // gcc alike
+    if (file_being_parsed_.length()) error_ += ":";
+    error_ += NumToString(line_) + ": " + NumToString(CursorPosition());
+  #endif
+  // clang-format on
+  error_ += ": " + msg;
+}
+
+void Parser::Warning(const std::string &msg) { Message("warning: " + msg); }
+
+CheckedError Parser::Error(const std::string &msg) {
+  Message("error: " + msg);
+  return CheckedError(true);
+}
+
+inline CheckedError NoError() { return CheckedError(false); }
+
+CheckedError Parser::RecurseError() {
+  return Error("maximum parsing recursion of " +
+               NumToString(FLATBUFFERS_MAX_PARSING_DEPTH) + " reached");
+}
+
+template<typename F> CheckedError Parser::Recurse(F f) {
+  if (recurse_protection_counter >= (FLATBUFFERS_MAX_PARSING_DEPTH))
+    return RecurseError();
+  recurse_protection_counter++;
+  auto ce = f();
+  recurse_protection_counter--;
+  return ce;
+}
+
+template<typename T> std::string TypeToIntervalString() {
+  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
+         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
+}
+
+// atot: template version of atoi/atof: convert a string to an instance of T.
+template<typename T>
+inline CheckedError atot(const char *s, Parser &parser, T *val) {
+  auto done = StringToNumber(s, val);
+  if (done) return NoError();
+  if (0 == *val)
+    return parser.Error("invalid number: \"" + std::string(s) + "\"");
+  else
+    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
+                        ", constant does not fit " + TypeToIntervalString<T>());
+}
+template<>
+inline CheckedError atot<Offset<void>>(const char *s, Parser &parser,
+                                       Offset<void> *val) {
+  (void)parser;
+  *val = Offset<void>(atoi(s));
+  return NoError();
+}
+
+std::string Namespace::GetFullyQualifiedName(const std::string &name,
+                                             size_t max_components) const {
+  // Early exit if we don't have a defined namespace.
+  if (components.empty() || !max_components) { return name; }
+  std::string stream_str;
+  for (size_t i = 0; i < std::min(components.size(), max_components); i++) {
+    if (i) { stream_str += '.'; }
+    stream_str += std::string(components[i]);
+  }
+  if (name.length()) {
+    stream_str += '.';
+    stream_str += name;
+  }
+  return stream_str;
+}
+
+// Declare tokens we'll use. Single character tokens are represented by their
+// ascii character code (e.g. '{'), others above 256.
+// clang-format off
+#define FLATBUFFERS_GEN_TOKENS(TD) \
+  TD(Eof, 256, "end of file") \
+  TD(StringConstant, 257, "string constant") \
+  TD(IntegerConstant, 258, "integer constant") \
+  TD(FloatConstant, 259, "float constant") \
+  TD(Identifier, 260, "identifier")
+#ifdef __GNUC__
+__extension__  // Stop GCC complaining about trailing comma with -Wpendantic.
+#endif
+enum {
+  #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
+    FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
+  #undef FLATBUFFERS_TOKEN
+};
+
+static std::string TokenToString(int t) {
+  static const char * const tokens[] = {
+    #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
+      FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
+    #undef FLATBUFFERS_TOKEN
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+      CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+      IDLTYPE,
+      FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+    #undef FLATBUFFERS_TD
+  };
+  if (t < 256) {  // A single ascii char token.
+    std::string s;
+    s.append(1, static_cast<char>(t));
+    return s;
+  } else {       // Other tokens.
+    return tokens[t - 256];
+  }
+}
+// clang-format on
+
+std::string Parser::TokenToStringId(int t) const {
+  return t == kTokenIdentifier ? attribute_ : TokenToString(t);
+}
+
+// Parses exactly nibbles worth of hex digits into a number, or error.
+CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) {
+  FLATBUFFERS_ASSERT(nibbles > 0);
+  for (int i = 0; i < nibbles; i++)
+    if (!is_xdigit(cursor_[i]))
+      return Error("escape code must be followed by " + NumToString(nibbles) +
+                   " hex digits");
+  std::string target(cursor_, cursor_ + nibbles);
+  *val = StringToUInt(target.c_str(), 16);
+  cursor_ += nibbles;
+  return NoError();
+}
+
+CheckedError Parser::SkipByteOrderMark() {
+  if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError();
+  cursor_++;
+  if (static_cast<unsigned char>(*cursor_) != 0xbb)
+    return Error("invalid utf-8 byte order mark");
+  cursor_++;
+  if (static_cast<unsigned char>(*cursor_) != 0xbf)
+    return Error("invalid utf-8 byte order mark");
+  cursor_++;
+  return NoError();
+}
+
+static inline bool IsIdentifierStart(char c) {
+  return is_alpha(c) || (c == '_');
+}
+
+CheckedError Parser::Next() {
+  doc_comment_.clear();
+  bool seen_newline = cursor_ == source_;
+  attribute_.clear();
+  attr_is_trivial_ascii_string_ = true;
+  for (;;) {
+    char c = *cursor_++;
+    token_ = c;
+    switch (c) {
+      case '\0':
+        cursor_--;
+        token_ = kTokenEof;
+        return NoError();
+      case ' ':
+      case '\r':
+      case '\t': break;
+      case '\n':
+        MarkNewLine();
+        seen_newline = true;
+        break;
+      case '{':
+      case '}':
+      case '(':
+      case ')':
+      case '[':
+      case ']':
+      case ',':
+      case ':':
+      case ';':
+      case '=': return NoError();
+      case '\"':
+      case '\'': {
+        int unicode_high_surrogate = -1;
+
+        while (*cursor_ != c) {
+          if (*cursor_ < ' ' && static_cast<signed char>(*cursor_) >= 0)
+            return Error("illegal character in string constant");
+          if (*cursor_ == '\\') {
+            attr_is_trivial_ascii_string_ = false;  // has escape sequence
+            cursor_++;
+            if (unicode_high_surrogate != -1 && *cursor_ != 'u') {
+              return Error(
+                  "illegal Unicode sequence (unpaired high surrogate)");
+            }
+            switch (*cursor_) {
+              case 'n':
+                attribute_ += '\n';
+                cursor_++;
+                break;
+              case 't':
+                attribute_ += '\t';
+                cursor_++;
+                break;
+              case 'r':
+                attribute_ += '\r';
+                cursor_++;
+                break;
+              case 'b':
+                attribute_ += '\b';
+                cursor_++;
+                break;
+              case 'f':
+                attribute_ += '\f';
+                cursor_++;
+                break;
+              case '\"':
+                attribute_ += '\"';
+                cursor_++;
+                break;
+              case '\'':
+                attribute_ += '\'';
+                cursor_++;
+                break;
+              case '\\':
+                attribute_ += '\\';
+                cursor_++;
+                break;
+              case '/':
+                attribute_ += '/';
+                cursor_++;
+                break;
+              case 'x': {  // Not in the JSON standard
+                cursor_++;
+                uint64_t val;
+                ECHECK(ParseHexNum(2, &val));
+                attribute_ += static_cast<char>(val);
+                break;
+              }
+              case 'u': {
+                cursor_++;
+                uint64_t val;
+                ECHECK(ParseHexNum(4, &val));
+                if (val >= 0xD800 && val <= 0xDBFF) {
+                  if (unicode_high_surrogate != -1) {
+                    return Error(
+                        "illegal Unicode sequence (multiple high surrogates)");
+                  } else {
+                    unicode_high_surrogate = static_cast<int>(val);
+                  }
+                } else if (val >= 0xDC00 && val <= 0xDFFF) {
+                  if (unicode_high_surrogate == -1) {
+                    return Error(
+                        "illegal Unicode sequence (unpaired low surrogate)");
+                  } else {
+                    int code_point = 0x10000 +
+                                     ((unicode_high_surrogate & 0x03FF) << 10) +
+                                     (val & 0x03FF);
+                    ToUTF8(code_point, &attribute_);
+                    unicode_high_surrogate = -1;
+                  }
+                } else {
+                  if (unicode_high_surrogate != -1) {
+                    return Error(
+                        "illegal Unicode sequence (unpaired high surrogate)");
+                  }
+                  ToUTF8(static_cast<int>(val), &attribute_);
+                }
+                break;
+              }
+              default: return Error("unknown escape code in string constant");
+            }
+          } else {  // printable chars + UTF-8 bytes
+            if (unicode_high_surrogate != -1) {
+              return Error(
+                  "illegal Unicode sequence (unpaired high surrogate)");
+            }
+            // reset if non-printable
+            attr_is_trivial_ascii_string_ &= check_ascii_range(*cursor_, ' ', '~');
+
+            attribute_ += *cursor_++;
+          }
+        }
+        if (unicode_high_surrogate != -1) {
+          return Error("illegal Unicode sequence (unpaired high surrogate)");
+        }
+        cursor_++;
+        if (!attr_is_trivial_ascii_string_ && !opts.allow_non_utf8 &&
+            !ValidateUTF8(attribute_)) {
+          return Error("illegal UTF-8 sequence");
+        }
+        token_ = kTokenStringConstant;
+        return NoError();
+      }
+      case '/':
+        if (*cursor_ == '/') {
+          const char *start = ++cursor_;
+          while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++;
+          if (*start == '/') {  // documentation comment
+            if (!seen_newline)
+              return Error(
+                  "a documentation comment should be on a line on its own");
+            doc_comment_.push_back(std::string(start + 1, cursor_));
+          }
+          break;
+        } else if (*cursor_ == '*') {
+          cursor_++;
+          // TODO: make nested.
+          while (*cursor_ != '*' || cursor_[1] != '/') {
+            if (*cursor_ == '\n') MarkNewLine();
+            if (!*cursor_) return Error("end of file in comment");
+            cursor_++;
+          }
+          cursor_ += 2;
+          break;
+        }
+        FLATBUFFERS_FALLTHROUGH(); // else fall thru
+      default:
+        const auto has_sign = (c == '+') || (c == '-');
+        // '-'/'+' and following identifier - can be a predefined constant like:
+        // NAN, INF, PI, etc.
+        if (IsIdentifierStart(c) || (has_sign && IsIdentifierStart(*cursor_))) {
+          // Collect all chars of an identifier:
+          const char *start = cursor_ - 1;
+          while (IsIdentifierStart(*cursor_) || is_digit(*cursor_)) cursor_++;
+          attribute_.append(start, cursor_);
+          token_ = has_sign ? kTokenStringConstant : kTokenIdentifier;
+          return NoError();
+        }
+
+        auto dot_lvl = (c == '.') ? 0 : 1;  // dot_lvl==0 <=> exactly one '.' seen
+        if (!dot_lvl && !is_digit(*cursor_)) return NoError(); // enum?
+        // Parser accepts hexadecimal-floating-literal (see C++ 5.13.4).
+        if (is_digit(c) || has_sign || !dot_lvl) {
+          const auto start = cursor_ - 1;
+          auto start_digits = !is_digit(c) ? cursor_ : cursor_ - 1;
+          if (!is_digit(c) && is_digit(*cursor_)){
+            start_digits = cursor_; // see digit in cursor_ position
+            c = *cursor_++;
+          }
+          // hex-float can't begind with '.'
+          auto use_hex = dot_lvl && (c == '0') && is_alpha_char(*cursor_, 'X');
+          if (use_hex) start_digits = ++cursor_;  // '0x' is the prefix, skip it
+          // Read an integer number or mantisa of float-point number.
+          do {
+            if (use_hex) {
+              while (is_xdigit(*cursor_)) cursor_++;
+            } else {
+              while (is_digit(*cursor_)) cursor_++;
+            }
+          } while ((*cursor_ == '.') && (++cursor_) && (--dot_lvl >= 0));
+          // Exponent of float-point number.
+          if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
+            // The exponent suffix of hexadecimal float number is mandatory.
+            if (use_hex && !dot_lvl) start_digits = cursor_;
+            if ((use_hex && is_alpha_char(*cursor_, 'P')) ||
+                is_alpha_char(*cursor_, 'E')) {
+              dot_lvl = 0;  // Emulate dot to signal about float-point number.
+              cursor_++;
+              if (*cursor_ == '+' || *cursor_ == '-') cursor_++;
+              start_digits = cursor_;  // the exponent-part has to have digits
+              // Exponent is decimal integer number
+              while (is_digit(*cursor_)) cursor_++;
+              if (*cursor_ == '.') {
+                cursor_++;  // If see a dot treat it as part of invalid number.
+                dot_lvl = -1;  // Fall thru to Error().
+              }
+            }
+          }
+          // Finalize.
+          if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
+            attribute_.append(start, cursor_);
+            token_ = dot_lvl ? kTokenIntegerConstant : kTokenFloatConstant;
+            return NoError();
+          } else {
+            return Error("invalid number: " + std::string(start, cursor_));
+          }
+        }
+        std::string ch;
+        ch = c;
+        if (false == check_ascii_range(c, ' ', '~')) ch = "code: " + NumToString(c);
+        return Error("illegal character: " + ch);
+    }
+  }
+}
+
+// Check if a given token is next.
+bool Parser::Is(int t) const { return t == token_; }
+
+bool Parser::IsIdent(const char *id) const {
+  return token_ == kTokenIdentifier && attribute_ == id;
+}
+
+// Expect a given token to be next, consume it, or error if not present.
+CheckedError Parser::Expect(int t) {
+  if (t != token_) {
+    return Error("expecting: " + TokenToString(t) +
+                 " instead got: " + TokenToStringId(token_));
+  }
+  NEXT();
+  return NoError();
+}
+
+CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) {
+  while (Is('.')) {
+    NEXT();
+    *id += ".";
+    *id += attribute_;
+    if (last) *last = attribute_;
+    EXPECT(kTokenIdentifier);
+  }
+  return NoError();
+}
+
+EnumDef *Parser::LookupEnum(const std::string &id) {
+  // Search thru parent namespaces.
+  for (int components = static_cast<int>(current_namespace_->components.size());
+       components >= 0; components--) {
+    auto ed = enums_.Lookup(
+        current_namespace_->GetFullyQualifiedName(id, components));
+    if (ed) return ed;
+  }
+  return nullptr;
+}
+
+StructDef *Parser::LookupStruct(const std::string &id) const {
+  auto sd = structs_.Lookup(id);
+  if (sd) sd->refcount++;
+  return sd;
+}
+
+CheckedError Parser::ParseTypeIdent(Type &type) {
+  std::string id = attribute_;
+  EXPECT(kTokenIdentifier);
+  ECHECK(ParseNamespacing(&id, nullptr));
+  auto enum_def = LookupEnum(id);
+  if (enum_def) {
+    type = enum_def->underlying_type;
+    if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
+  } else {
+    type.base_type = BASE_TYPE_STRUCT;
+    type.struct_def = LookupCreateStruct(id);
+  }
+  return NoError();
+}
+
+// Parse any IDL type.
+CheckedError Parser::ParseType(Type &type) {
+  if (token_ == kTokenIdentifier) {
+    if (IsIdent("bool")) {
+      type.base_type = BASE_TYPE_BOOL;
+      NEXT();
+    } else if (IsIdent("byte") || IsIdent("int8")) {
+      type.base_type = BASE_TYPE_CHAR;
+      NEXT();
+    } else if (IsIdent("ubyte") || IsIdent("uint8")) {
+      type.base_type = BASE_TYPE_UCHAR;
+      NEXT();
+    } else if (IsIdent("short") || IsIdent("int16")) {
+      type.base_type = BASE_TYPE_SHORT;
+      NEXT();
+    } else if (IsIdent("ushort") || IsIdent("uint16")) {
+      type.base_type = BASE_TYPE_USHORT;
+      NEXT();
+    } else if (IsIdent("int") || IsIdent("int32")) {
+      type.base_type = BASE_TYPE_INT;
+      NEXT();
+    } else if (IsIdent("uint") || IsIdent("uint32")) {
+      type.base_type = BASE_TYPE_UINT;
+      NEXT();
+    } else if (IsIdent("long") || IsIdent("int64")) {
+      type.base_type = BASE_TYPE_LONG;
+      NEXT();
+    } else if (IsIdent("ulong") || IsIdent("uint64")) {
+      type.base_type = BASE_TYPE_ULONG;
+      NEXT();
+    } else if (IsIdent("float") || IsIdent("float32")) {
+      type.base_type = BASE_TYPE_FLOAT;
+      NEXT();
+    } else if (IsIdent("double") || IsIdent("float64")) {
+      type.base_type = BASE_TYPE_DOUBLE;
+      NEXT();
+    } else if (IsIdent("string")) {
+      type.base_type = BASE_TYPE_STRING;
+      NEXT();
+    } else {
+      ECHECK(ParseTypeIdent(type));
+    }
+  } else if (token_ == '[') {
+    NEXT();
+    Type subtype;
+    ECHECK(Recurse([&]() { return ParseType(subtype); }));
+    if (IsSeries(subtype)) {
+      // We could support this, but it will complicate things, and it's
+      // easier to work around with a struct around the inner vector.
+      return Error("nested vector types not supported (wrap in table first)");
+    }
+    if (token_ == ':') {
+      NEXT();
+      if (token_ != kTokenIntegerConstant) {
+        return Error("length of fixed-length array must be an integer value");
+      }
+      uint16_t fixed_length = 0;
+      bool check = StringToNumber(attribute_.c_str(), &fixed_length);
+      if (!check || fixed_length < 1) {
+        return Error(
+            "length of fixed-length array must be positive and fit to "
+            "uint16_t type");
+      }
+      // Check if enum arrays are used in C++ without specifying --scoped-enums
+      if ((opts.lang_to_generate & IDLOptions::kCpp) && !opts.scoped_enums &&
+          IsEnum(subtype)) {
+        return Error(
+            "--scoped-enums must be enabled to use enum arrays in C++\n");
+      }
+      type = Type(BASE_TYPE_ARRAY, subtype.struct_def, subtype.enum_def,
+                  fixed_length);
+      NEXT();
+    } else {
+      type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
+    }
+    type.element = subtype.base_type;
+    EXPECT(']');
+  } else {
+    return Error("illegal type syntax");
+  }
+  return NoError();
+}
+
+CheckedError Parser::AddField(StructDef &struct_def, const std::string &name,
+                              const Type &type, FieldDef **dest) {
+  auto &field = *new FieldDef();
+  field.value.offset =
+      FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size()));
+  field.name = name;
+  field.file = struct_def.file;
+  field.value.type = type;
+  if (struct_def.fixed) {  // statically compute the field offset
+    auto size = InlineSize(type);
+    auto alignment = InlineAlignment(type);
+    // structs_ need to have a predictable format, so we need to align to
+    // the largest scalar
+    struct_def.minalign = std::max(struct_def.minalign, alignment);
+    struct_def.PadLastField(alignment);
+    field.value.offset = static_cast<voffset_t>(struct_def.bytesize);
+    struct_def.bytesize += size;
+  }
+  if (struct_def.fields.Add(name, &field))
+    return Error("field already exists: " + name);
+  *dest = &field;
+  return NoError();
+}
+
+CheckedError Parser::ParseField(StructDef &struct_def) {
+  std::string name = attribute_;
+
+  if (LookupStruct(name))
+    return Error("field name can not be the same as table/struct name");
+
+  std::vector<std::string> dc = doc_comment_;
+  EXPECT(kTokenIdentifier);
+  EXPECT(':');
+  Type type;
+  ECHECK(ParseType(type));
+
+  if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type) &&
+      !IsArray(type))
+    return Error("structs_ may contain only scalar or struct fields");
+
+  if (!struct_def.fixed && IsArray(type))
+    return Error("fixed-length array in table must be wrapped in struct");
+
+  if (IsArray(type) && !SupportsAdvancedArrayFeatures()) {
+    return Error(
+        "Arrays are not yet supported in all "
+        "the specified programming languages.");
+  }
+
+  FieldDef *typefield = nullptr;
+  if (type.base_type == BASE_TYPE_UNION) {
+    // For union fields, add a second auto-generated field to hold the type,
+    // with a special suffix.
+    ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
+                    type.enum_def->underlying_type, &typefield));
+  } else if (type.base_type == BASE_TYPE_VECTOR &&
+             type.element == BASE_TYPE_UNION) {
+    // Only cpp, js and ts supports the union vector feature so far.
+    if (!SupportsAdvancedUnionFeatures()) {
+      return Error(
+          "Vectors of unions are not yet supported in all "
+          "the specified programming languages.");
+    }
+    // For vector of union fields, add a second auto-generated vector field to
+    // hold the types, with a special suffix.
+    Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def);
+    union_vector.element = BASE_TYPE_UTYPE;
+    ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), union_vector,
+                    &typefield));
+  }
+
+  FieldDef *field;
+  ECHECK(AddField(struct_def, name, type, &field));
+
+  if (token_ == '=') {
+    NEXT();
+    ECHECK(ParseSingleValue(&field->name, field->value, true));
+    if (!IsScalar(type.base_type) ||
+        (struct_def.fixed && field->value.constant != "0"))
+      return Error(
+            "default values currently only supported for scalars in tables");
+  }
+  // Append .0 if the value has not it (skip hex and scientific floats).
+  // This suffix needed for generated C++ code.
+  if (IsFloat(type.base_type)) {
+    auto &text = field->value.constant;
+    FLATBUFFERS_ASSERT(false == text.empty());
+    auto s = text.c_str();
+    while(*s == ' ') s++;
+    if (*s == '-' || *s == '+') s++;
+    // 1) A float constants (nan, inf, pi, etc) is a kind of identifier.
+    // 2) A float number needn't ".0" at the end if it has exponent.
+    if ((false == IsIdentifierStart(*s)) &&
+        (std::string::npos == field->value.constant.find_first_of(".eEpP"))) {
+      field->value.constant += ".0";
+    }
+  }
+  if (type.enum_def) {
+    // The type.base_type can only be scalar, union, array or vector.
+    // Table, struct or string can't have enum_def.
+    // Default value of union and vector in NONE, NULL translated to "0".
+    FLATBUFFERS_ASSERT(IsInteger(type.base_type) ||
+                       (type.base_type == BASE_TYPE_UNION) ||
+                       (type.base_type == BASE_TYPE_VECTOR) ||
+                       (type.base_type == BASE_TYPE_ARRAY));
+    if (type.base_type == BASE_TYPE_VECTOR) {
+      // Vector can't use initialization list.
+      FLATBUFFERS_ASSERT(field->value.constant == "0");
+    } else {
+      // All unions should have the NONE ("0") enum value.
+      auto in_enum = type.enum_def->attributes.Lookup("bit_flags") ||
+                     type.enum_def->FindByValue(field->value.constant);
+      if (false == in_enum)
+        return Error("default value of " + field->value.constant +
+                     " for field " + name + " is not part of enum " +
+                     type.enum_def->name);
+    }
+  }
+
+  field->doc_comment = dc;
+  ECHECK(ParseMetaData(&field->attributes));
+  field->deprecated = field->attributes.Lookup("deprecated") != nullptr;
+  auto hash_name = field->attributes.Lookup("hash");
+  if (hash_name) {
+    switch ((type.base_type == BASE_TYPE_VECTOR) ? type.element : type.base_type) {
+      case BASE_TYPE_SHORT:
+      case BASE_TYPE_USHORT: {
+        if (FindHashFunction16(hash_name->constant.c_str()) == nullptr)
+          return Error("Unknown hashing algorithm for 16 bit types: " +
+                       hash_name->constant);
+        break;
+      }
+      case BASE_TYPE_INT:
+      case BASE_TYPE_UINT: {
+        if (FindHashFunction32(hash_name->constant.c_str()) == nullptr)
+          return Error("Unknown hashing algorithm for 32 bit types: " +
+                       hash_name->constant);
+        break;
+      }
+      case BASE_TYPE_LONG:
+      case BASE_TYPE_ULONG: {
+        if (FindHashFunction64(hash_name->constant.c_str()) == nullptr)
+          return Error("Unknown hashing algorithm for 64 bit types: " +
+                       hash_name->constant);
+        break;
+      }
+      default:
+        return Error(
+            "only short, ushort, int, uint, long and ulong data types support hashing.");
+    }
+  }
+  auto cpp_type = field->attributes.Lookup("cpp_type");
+  if (cpp_type) {
+    if (!hash_name)
+      return Error("cpp_type can only be used with a hashed field");
+    /// forcing cpp_ptr_type to 'naked' if unset
+    auto cpp_ptr_type = field->attributes.Lookup("cpp_ptr_type");
+    if (!cpp_ptr_type) {
+      auto val = new Value();
+      val->type = cpp_type->type;
+      val->constant = "naked";
+      field->attributes.Add("cpp_ptr_type", val);
+    }
+  }
+  if (field->deprecated && struct_def.fixed)
+    return Error("can't deprecate fields in a struct");
+  field->required = field->attributes.Lookup("required") != nullptr;
+  if (field->required &&
+      (struct_def.fixed || IsScalar(type.base_type)))
+    return Error("only non-scalar fields in tables may be 'required'");
+  field->key = field->attributes.Lookup("key") != nullptr;
+  if (field->key) {
+    if (struct_def.has_key) return Error("only one field may be set as 'key'");
+    struct_def.has_key = true;
+    if (!IsScalar(type.base_type)) {
+      field->required = true;
+      if (type.base_type != BASE_TYPE_STRING)
+        return Error("'key' field must be string or scalar type");
+    }
+  }
+  field->shared = field->attributes.Lookup("shared") != nullptr;
+  if (field->shared && field->value.type.base_type != BASE_TYPE_STRING)
+    return Error("shared can only be defined on strings");
+
+  auto field_native_custom_alloc =
+      field->attributes.Lookup("native_custom_alloc");
+  if (field_native_custom_alloc)
+    return Error(
+        "native_custom_alloc can only be used with a table or struct "
+        "definition");
+
+  field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
+  if (field->native_inline && !IsStruct(field->value.type))
+    return Error("native_inline can only be defined on structs");
+
+  auto nested = field->attributes.Lookup("nested_flatbuffer");
+  if (nested) {
+    if (nested->type.base_type != BASE_TYPE_STRING)
+      return Error(
+          "nested_flatbuffer attribute must be a string (the root type)");
+    if (type.base_type != BASE_TYPE_VECTOR || type.element != BASE_TYPE_UCHAR)
+      return Error(
+          "nested_flatbuffer attribute may only apply to a vector of ubyte");
+    // This will cause an error if the root type of the nested flatbuffer
+    // wasn't defined elsewhere.
+    field->nested_flatbuffer = LookupCreateStruct(nested->constant);
+  }
+
+  if (field->attributes.Lookup("flexbuffer")) {
+    field->flexbuffer = true;
+    uses_flexbuffers_ = true;
+    if (type.base_type != BASE_TYPE_VECTOR ||
+        type.element != BASE_TYPE_UCHAR)
+      return Error("flexbuffer attribute may only apply to a vector of ubyte");
+  }
+
+  if (typefield) {
+    if (!IsScalar(typefield->value.type.base_type)) {
+      // this is a union vector field
+      typefield->required = field->required;
+    }
+    // If this field is a union, and it has a manually assigned id,
+    // the automatically added type field should have an id as well (of N - 1).
+    auto attr = field->attributes.Lookup("id");
+    if (attr) {
+      auto id = atoi(attr->constant.c_str());
+      auto val = new Value();
+      val->type = attr->type;
+      val->constant = NumToString(id - 1);
+      typefield->attributes.Add("id", val);
+    }
+  }
+
+  EXPECT(';');
+  return NoError();
+}
+
+CheckedError Parser::ParseString(Value &val) {
+  auto s = attribute_;
+  EXPECT(kTokenStringConstant);
+  val.constant = NumToString(builder_.CreateString(s).o);
+  return NoError();
+}
+
+CheckedError Parser::ParseComma() {
+  if (!opts.protobuf_ascii_alike) EXPECT(',');
+  return NoError();
+}
+
+CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
+                                   size_t parent_fieldn,
+                                   const StructDef *parent_struct_def,
+                                   uoffset_t count,
+                                   bool inside_vector) {
+  switch (val.type.base_type) {
+    case BASE_TYPE_UNION: {
+      FLATBUFFERS_ASSERT(field);
+      std::string constant;
+      Vector<uint8_t> *vector_of_union_types = nullptr;
+      // Find corresponding type field we may have already parsed.
+      for (auto elem = field_stack_.rbegin() + count;
+           elem != field_stack_.rbegin() + parent_fieldn + count; ++elem) {
+        auto &type = elem->second->value.type;
+        if (type.enum_def == val.type.enum_def) {
+          if (inside_vector) {
+            if (type.base_type == BASE_TYPE_VECTOR &&
+                type.element == BASE_TYPE_UTYPE) {
+              // Vector of union type field.
+              uoffset_t offset;
+              ECHECK(atot(elem->first.constant.c_str(), *this, &offset));
+              vector_of_union_types = reinterpret_cast<Vector<uint8_t> *>(
+                                        builder_.GetCurrentBufferPointer() +
+                                        builder_.GetSize() - offset);
+              break;
+            }
+          } else {
+            if (type.base_type == BASE_TYPE_UTYPE) {
+              // Union type field.
+              constant = elem->first.constant;
+              break;
+            }
+          }
+        }
+      }
+      if (constant.empty() && !inside_vector) {
+        // We haven't seen the type field yet. Sadly a lot of JSON writers
+        // output these in alphabetical order, meaning it comes after this
+        // value. So we scan past the value to find it, then come back here.
+        // We currently don't do this for vectors of unions because the
+        // scanning/serialization logic would get very complicated.
+        auto type_name = field->name + UnionTypeFieldSuffix();
+        FLATBUFFERS_ASSERT(parent_struct_def);
+        auto type_field = parent_struct_def->fields.Lookup(type_name);
+        FLATBUFFERS_ASSERT(type_field);  // Guaranteed by ParseField().
+        // Remember where we are in the source file, so we can come back here.
+        auto backup = *static_cast<ParserState *>(this);
+        ECHECK(SkipAnyJsonValue());  // The table.
+        ECHECK(ParseComma());
+        auto next_name = attribute_;
+        if (Is(kTokenStringConstant)) {
+          NEXT();
+        } else {
+          EXPECT(kTokenIdentifier);
+        }
+        if (next_name == type_name) {
+          EXPECT(':');
+          Value type_val = type_field->value;
+          ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr, 0));
+          constant = type_val.constant;
+          // Got the information we needed, now rewind:
+          *static_cast<ParserState *>(this) = backup;
+        }
+      }
+      if (constant.empty() && !vector_of_union_types) {
+        return Error("missing type field for this union value: " +
+                     field->name);
+      }
+      uint8_t enum_idx;
+      if (vector_of_union_types) {
+        enum_idx = vector_of_union_types->Get(count);
+      } else {
+        ECHECK(atot(constant.c_str(), *this, &enum_idx));
+      }
+      auto enum_val = val.type.enum_def->ReverseLookup(enum_idx, true);
+      if (!enum_val) return Error("illegal type id for: " + field->name);
+      if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
+        ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
+                          nullptr));
+        if (enum_val->union_type.struct_def->fixed) {
+          // All BASE_TYPE_UNION values are offsets, so turn this into one.
+          SerializeStruct(*enum_val->union_type.struct_def, val);
+          builder_.ClearOffsets();
+          val.constant = NumToString(builder_.GetSize());
+        }
+      } else if (enum_val->union_type.base_type == BASE_TYPE_STRING) {
+        ECHECK(ParseString(val));
+      } else {
+        FLATBUFFERS_ASSERT(false);
+      }
+      break;
+    }
+    case BASE_TYPE_STRUCT:
+      ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
+      break;
+    case BASE_TYPE_STRING: {
+      ECHECK(ParseString(val));
+      break;
+    }
+    case BASE_TYPE_VECTOR: {
+      uoffset_t off;
+      ECHECK(ParseVector(val.type.VectorType(), &off, field, parent_fieldn));
+      val.constant = NumToString(off);
+      break;
+    }
+    case BASE_TYPE_ARRAY: {
+      ECHECK(ParseArray(val));
+      break;
+    }
+    case BASE_TYPE_INT:
+    case BASE_TYPE_UINT:
+    case BASE_TYPE_LONG:
+    case BASE_TYPE_ULONG: {
+      if (field && field->attributes.Lookup("hash") &&
+          (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
+        ECHECK(ParseHash(val, field));
+      } else {
+        ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
+      }
+      break;
+    }
+    default:
+      ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
+      break;
+  }
+  return NoError();
+}
+
+void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
+  SerializeStruct(builder_, struct_def, val);
+}
+
+void Parser::SerializeStruct(FlatBufferBuilder &builder,
+                             const StructDef &struct_def, const Value &val) {
+  FLATBUFFERS_ASSERT(val.constant.length() == struct_def.bytesize);
+  builder.Align(struct_def.minalign);
+  builder.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()),
+                    struct_def.bytesize);
+  builder.AddStructOffset(val.offset, builder.GetSize());
+}
+
+template <typename F>
+CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
+                                          const StructDef *struct_def,
+                                          F body) {
+  // We allow tables both as JSON object{ .. } with field names
+  // or vector[..] with all fields in order
+  char terminator = '}';
+  bool is_nested_vector = struct_def && Is('[');
+  if (is_nested_vector) {
+    NEXT();
+    terminator = ']';
+  } else {
+    EXPECT('{');
+  }
+  for (;;) {
+    if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
+    std::string name;
+    if (is_nested_vector) {
+      if (fieldn >= struct_def->fields.vec.size()) {
+        return Error("too many unnamed fields in nested array");
+      }
+      name = struct_def->fields.vec[fieldn]->name;
+    } else {
+      name = attribute_;
+      if (Is(kTokenStringConstant)) {
+        NEXT();
+      } else {
+        EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
+      }
+      if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
+    }
+    ECHECK(body(name, fieldn, struct_def));
+    if (Is(terminator)) break;
+    ECHECK(ParseComma());
+  }
+  NEXT();
+  if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
+    return Error("wrong number of unnamed fields in table vector");
+  }
+  return NoError();
+}
+
+CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
+                                uoffset_t *ovalue) {
+  size_t fieldn_outer = 0;
+  auto err = ParseTableDelimiters(
+      fieldn_outer, &struct_def,
+      [&](const std::string &name, size_t &fieldn,
+          const StructDef *struct_def_inner) -> CheckedError {
+        if (name == "$schema") {
+          ECHECK(Expect(kTokenStringConstant));
+          return NoError();
+        }
+        auto field = struct_def_inner->fields.Lookup(name);
+        if (!field) {
+          if (!opts.skip_unexpected_fields_in_json) {
+            return Error("unknown field: " + name);
+          } else {
+            ECHECK(SkipAnyJsonValue());
+          }
+        } else {
+          if (IsIdent("null") && !IsScalar(field->value.type.base_type)) {
+            ECHECK(Next());  // Ignore this field.
+          } else {
+            Value val = field->value;
+            if (field->flexbuffer) {
+              flexbuffers::Builder builder(1024,
+                                           flexbuffers::BUILDER_FLAG_SHARE_ALL);
+              ECHECK(ParseFlexBufferValue(&builder));
+              builder.Finish();
+              // Force alignment for nested flexbuffer
+              builder_.ForceVectorAlignment(builder.GetSize(), sizeof(uint8_t),
+                                            sizeof(largest_scalar_t));
+              auto off = builder_.CreateVector(builder.GetBuffer());
+              val.constant = NumToString(off.o);
+            } else if (field->nested_flatbuffer) {
+              ECHECK(
+                  ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner));
+            } else {
+              ECHECK(Recurse([&]() {
+                return ParseAnyValue(val, field, fieldn, struct_def_inner, 0);
+              }));
+            }
+            // Hardcoded insertion-sort with error-check.
+            // If fields are specified in order, then this loop exits
+            // immediately.
+            auto elem = field_stack_.rbegin();
+            for (; elem != field_stack_.rbegin() + fieldn; ++elem) {
+              auto existing_field = elem->second;
+              if (existing_field == field)
+                return Error("field set more than once: " + field->name);
+              if (existing_field->value.offset < field->value.offset) break;
+            }
+            // Note: elem points to before the insertion point, thus .base()
+            // points to the correct spot.
+            field_stack_.insert(elem.base(), std::make_pair(val, field));
+            fieldn++;
+          }
+        }
+        return NoError();
+      });
+  ECHECK(err);
+
+  // Check if all required fields are parsed.
+  for (auto field_it = struct_def.fields.vec.begin();
+       field_it != struct_def.fields.vec.end(); ++field_it) {
+    auto required_field = *field_it;
+    if (!required_field->required) { continue; }
+    bool found = false;
+    for (auto pf_it = field_stack_.end() - fieldn_outer;
+         pf_it != field_stack_.end(); ++pf_it) {
+      auto parsed_field = pf_it->second;
+      if (parsed_field == required_field) {
+        found = true;
+        break;
+      }
+    }
+    if (!found) {
+      return Error("required field is missing: " + required_field->name +
+                   " in " + struct_def.name);
+    }
+  }
+
+  if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size())
+    return Error("struct: wrong number of initializers: " + struct_def.name);
+
+  auto start = struct_def.fixed ? builder_.StartStruct(struct_def.minalign)
+                                : builder_.StartTable();
+
+  for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; size;
+       size /= 2) {
+    // Go through elements in reverse, since we're building the data backwards.
+    for (auto it = field_stack_.rbegin();
+         it != field_stack_.rbegin() + fieldn_outer; ++it) {
+      auto &field_value = it->first;
+      auto field = it->second;
+      if (!struct_def.sortbysize ||
+          size == SizeOf(field_value.type.base_type)) {
+        switch (field_value.type.base_type) {
+          // clang-format off
+          #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+            CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+            case BASE_TYPE_ ## ENUM: \
+              builder_.Pad(field->padding); \
+              if (struct_def.fixed) { \
+                CTYPE val; \
+                ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
+                builder_.PushElement(val); \
+              } else { \
+                CTYPE val, valdef; \
+                ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
+                ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \
+                builder_.AddElement(field_value.offset, val, valdef); \
+              } \
+              break;
+            FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
+          #undef FLATBUFFERS_TD
+          #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+            CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+            case BASE_TYPE_ ## ENUM: \
+              builder_.Pad(field->padding); \
+              if (IsStruct(field->value.type)) { \
+                SerializeStruct(*field->value.type.struct_def, field_value); \
+              } else { \
+                CTYPE val; \
+                ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
+                builder_.AddOffset(field_value.offset, val); \
+              } \
+              break;
+            FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD);
+          #undef FLATBUFFERS_TD
+            case BASE_TYPE_ARRAY:
+              builder_.Pad(field->padding);
+              builder_.PushBytes(
+                reinterpret_cast<const uint8_t*>(field_value.constant.c_str()),
+                InlineSize(field_value.type));
+              break;
+              // clang-format on
+        }
+      }
+    }
+  }
+  for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back();
+
+  if (struct_def.fixed) {
+    builder_.ClearOffsets();
+    builder_.EndStruct();
+    FLATBUFFERS_ASSERT(value);
+    // Temporarily store this struct in the value string, since it is to
+    // be serialized in-place elsewhere.
+    value->assign(
+        reinterpret_cast<const char *>(builder_.GetCurrentBufferPointer()),
+        struct_def.bytesize);
+    builder_.PopBytes(struct_def.bytesize);
+    FLATBUFFERS_ASSERT(!ovalue);
+  } else {
+    auto val = builder_.EndTable(start);
+    if (ovalue) *ovalue = val;
+    if (value) *value = NumToString(val);
+  }
+  return NoError();
+}
+
+template <typename F>
+CheckedError Parser::ParseVectorDelimiters(uoffset_t &count, F body) {
+  EXPECT('[');
+  for (;;) {
+    if ((!opts.strict_json || !count) && Is(']')) break;
+    ECHECK(body(count));
+    count++;
+    if (Is(']')) break;
+    ECHECK(ParseComma());
+  }
+  NEXT();
+  return NoError();
+}
+
+CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue,
+                                 FieldDef *field, size_t fieldn) {
+  uoffset_t count = 0;
+  auto err = ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
+    Value val;
+    val.type = type;
+    ECHECK(Recurse([&]() {
+      return ParseAnyValue(val, field, fieldn, nullptr, count, true);
+    }));
+    field_stack_.push_back(std::make_pair(val, nullptr));
+    return NoError();
+  });
+  ECHECK(err);
+
+  builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
+                       InlineAlignment(type));
+  for (uoffset_t i = 0; i < count; i++) {
+    // start at the back, since we're building the data backwards.
+    auto &val = field_stack_.back().first;
+    switch (val.type.base_type) {
+      // clang-format off
+      #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+        CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+        case BASE_TYPE_ ## ENUM: \
+          if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
+          else { \
+             CTYPE elem; \
+             ECHECK(atot(val.constant.c_str(), *this, &elem)); \
+             builder_.PushElement(elem); \
+          } \
+          break;
+        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+      #undef FLATBUFFERS_TD
+      // clang-format on
+    }
+    field_stack_.pop_back();
+  }
+
+  builder_.ClearOffsets();
+  *ovalue = builder_.EndVector(count);
+  return NoError();
+}
+
+CheckedError Parser::ParseArray(Value &array) {
+  std::vector<Value> stack;
+  FlatBufferBuilder builder;
+  const auto &type = array.type.VectorType();
+  auto length = array.type.fixed_length;
+  uoffset_t count = 0;
+  auto err = ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
+    vector_emplace_back(&stack, Value());
+    auto &val = stack.back();
+    val.type = type;
+    if (IsStruct(type)) {
+      ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
+    } else {
+      ECHECK(ParseSingleValue(nullptr, val, false));
+    }
+    return NoError();
+  });
+  ECHECK(err);
+  if (length != count) return Error("Fixed-length array size is incorrect.");
+
+  for (auto it = stack.rbegin(); it != stack.rend(); ++it) {
+    auto &val = *it;
+    // clang-format off
+    switch (val.type.base_type) {
+      #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+        CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+        case BASE_TYPE_ ## ENUM: \
+          if (IsStruct(val.type)) { \
+            SerializeStruct(builder, *val.type.struct_def, val); \
+          } else { \
+            CTYPE elem; \
+            ECHECK(atot(val.constant.c_str(), *this, &elem)); \
+            builder.PushElement(elem); \
+          } \
+        break;
+        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+      #undef FLATBUFFERS_TD
+      default: FLATBUFFERS_ASSERT(0);
+    }
+    // clang-format on
+  }
+
+  array.constant.assign(
+      reinterpret_cast<const char *>(builder.GetCurrentBufferPointer()),
+      InlineSize(array.type));
+  return NoError();
+}
+
+CheckedError Parser::ParseNestedFlatbuffer(Value &val, FieldDef *field,
+                                           size_t fieldn,
+                                           const StructDef *parent_struct_def) {
+  if (token_ == '[') {  // backwards compat for 'legacy' ubyte buffers
+    ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def, 0));
+  } else {
+    auto cursor_at_value_begin = cursor_;
+    ECHECK(SkipAnyJsonValue());
+    std::string substring(cursor_at_value_begin - 1, cursor_ - 1);
+
+    // Create and initialize new parser
+    Parser nested_parser;
+    FLATBUFFERS_ASSERT(field->nested_flatbuffer);
+    nested_parser.root_struct_def_ = field->nested_flatbuffer;
+    nested_parser.enums_ = enums_;
+    nested_parser.opts = opts;
+    nested_parser.uses_flexbuffers_ = uses_flexbuffers_;
+
+    // Parse JSON substring into new flatbuffer builder using nested_parser
+    bool ok = nested_parser.Parse(substring.c_str(), nullptr, nullptr);
+
+    // Clean nested_parser to avoid deleting the elements in
+    // the SymbolTables on destruction
+    nested_parser.enums_.dict.clear();
+    nested_parser.enums_.vec.clear();
+
+    if (!ok) {
+      ECHECK(Error(nested_parser.error_));
+    }
+    // Force alignment for nested flatbuffer
+    builder_.ForceVectorAlignment(nested_parser.builder_.GetSize(), sizeof(uint8_t),
+                                  nested_parser.builder_.GetBufferMinAlignment());
+
+    auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(),
+                                     nested_parser.builder_.GetSize());
+    val.constant = NumToString(off.o);
+  }
+  return NoError();
+}
+
+CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) {
+  if (Is('(')) {
+    NEXT();
+    for (;;) {
+      auto name = attribute_;
+      if (false == (Is(kTokenIdentifier) || Is(kTokenStringConstant)))
+        return Error("attribute name must be either identifier or string: " +
+          name);
+      if (known_attributes_.find(name) == known_attributes_.end())
+        return Error("user define attributes must be declared before use: " +
+                     name);
+      NEXT();
+      auto e = new Value();
+      attributes->Add(name, e);
+      if (Is(':')) {
+        NEXT();
+        ECHECK(ParseSingleValue(&name, *e, true));
+      }
+      if (Is(')')) {
+        NEXT();
+        break;
+      }
+      EXPECT(',');
+    }
+  }
+  return NoError();
+}
+
+CheckedError Parser::TryTypedValue(const std::string *name, int dtoken,
+                                   bool check, Value &e, BaseType req,
+                                   bool *destmatch) {
+  bool match = dtoken == token_;
+  if (match) {
+    FLATBUFFERS_ASSERT(*destmatch == false);
+    *destmatch = true;
+    e.constant = attribute_;
+    // Check token match
+    if (!check) {
+      if (e.type.base_type == BASE_TYPE_NONE) {
+        e.type.base_type = req;
+      } else {
+        return Error(
+            std::string("type mismatch: expecting: ") +
+            kTypeNames[e.type.base_type] + ", found: " + kTypeNames[req] +
+            ", name: " + (name ? *name : "") + ", value: " + e.constant);
+      }
+    }
+    // The exponent suffix of hexadecimal float-point number is mandatory.
+    // A hex-integer constant is forbidden as an initializer of float number.
+    if ((kTokenFloatConstant != dtoken) && IsFloat(e.type.base_type)) {
+      const auto &s = e.constant;
+      const auto k = s.find_first_of("0123456789.");
+      if ((std::string::npos != k) && (s.length() > (k + 1)) &&
+          (s[k] == '0' && is_alpha_char(s[k + 1], 'X')) &&
+          (std::string::npos == s.find_first_of("pP", k + 2))) {
+        return Error(
+            "invalid number, the exponent suffix of hexadecimal "
+            "floating-point literals is mandatory: \"" +
+            s + "\"");
+      }
+    }
+
+    NEXT();
+  }
+  return NoError();
+}
+
+CheckedError Parser::ParseEnumFromString(const Type &type,
+                                         std::string *result) {
+  const auto base_type =
+      type.enum_def ? type.enum_def->underlying_type.base_type : type.base_type;
+  if (!IsInteger(base_type)) return Error("not a valid value for this field");
+  uint64_t u64 = 0;
+  for (size_t pos = 0; pos != std::string::npos;) {
+    const auto delim = attribute_.find_first_of(' ', pos);
+    const auto last = (std::string::npos == delim);
+    auto word = attribute_.substr(pos, !last ? delim - pos : std::string::npos);
+    pos = !last ? delim + 1 : std::string::npos;
+    const EnumVal *ev = nullptr;
+    if (type.enum_def) {
+      ev = type.enum_def->Lookup(word);
+    } else {
+      auto dot = word.find_first_of('.');
+      if (std::string::npos == dot)
+        return Error("enum values need to be qualified by an enum type");
+      auto enum_def_str = word.substr(0, dot);
+      const auto enum_def = LookupEnum(enum_def_str);
+      if (!enum_def) return Error("unknown enum: " + enum_def_str);
+      auto enum_val_str = word.substr(dot + 1);
+      ev = enum_def->Lookup(enum_val_str);
+    }
+    if (!ev) return Error("unknown enum value: " + word);
+    u64 |= ev->GetAsUInt64();
+  }
+  *result = IsUnsigned(base_type) ? NumToString(u64)
+                                  : NumToString(static_cast<int64_t>(u64));
+  return NoError();
+}
+
+CheckedError Parser::ParseHash(Value &e, FieldDef *field) {
+  FLATBUFFERS_ASSERT(field);
+  Value *hash_name = field->attributes.Lookup("hash");
+  switch (e.type.base_type) {
+    case BASE_TYPE_SHORT: {
+      auto hash = FindHashFunction16(hash_name->constant.c_str());
+      int16_t hashed_value = static_cast<int16_t>(hash(attribute_.c_str()));
+      e.constant = NumToString(hashed_value);
+      break;
+    }
+    case BASE_TYPE_USHORT: {
+      auto hash = FindHashFunction16(hash_name->constant.c_str());
+      uint16_t hashed_value = hash(attribute_.c_str());
+      e.constant = NumToString(hashed_value);
+      break;
+    }
+    case BASE_TYPE_INT: {
+      auto hash = FindHashFunction32(hash_name->constant.c_str());
+      int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
+      e.constant = NumToString(hashed_value);
+      break;
+    }
+    case BASE_TYPE_UINT: {
+      auto hash = FindHashFunction32(hash_name->constant.c_str());
+      uint32_t hashed_value = hash(attribute_.c_str());
+      e.constant = NumToString(hashed_value);
+      break;
+    }
+    case BASE_TYPE_LONG: {
+      auto hash = FindHashFunction64(hash_name->constant.c_str());
+      int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
+      e.constant = NumToString(hashed_value);
+      break;
+    }
+    case BASE_TYPE_ULONG: {
+      auto hash = FindHashFunction64(hash_name->constant.c_str());
+      uint64_t hashed_value = hash(attribute_.c_str());
+      e.constant = NumToString(hashed_value);
+      break;
+    }
+    default: FLATBUFFERS_ASSERT(0);
+  }
+  NEXT();
+  return NoError();
+}
+
+CheckedError Parser::TokenError() {
+  return Error("cannot parse value starting with: " + TokenToStringId(token_));
+}
+
+// Re-pack helper (ParseSingleValue) to normalize defaults of scalars.
+template<typename T> inline void SingleValueRepack(Value &e, T val) {
+  // Remove leading zeros.
+  if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); }
+}
+#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
+// Normilaze defaults NaN to unsigned quiet-NaN(0).
+static inline void SingleValueRepack(Value& e, float val) {
+  if (val != val) e.constant = "nan";
+}
+static inline void SingleValueRepack(Value& e, double val) {
+  if (val != val) e.constant = "nan";
+}
+#endif
+
+CheckedError Parser::ParseSingleValue(const std::string *name, Value &e,
+                                      bool check_now) {
+  // First see if this could be a conversion function:
+  if (token_ == kTokenIdentifier && *cursor_ == '(') {
+    // todo: Extract processing of conversion functions to ParseFunction.
+    const auto functionname = attribute_;
+    if (!IsFloat(e.type.base_type)) {
+      return Error(functionname + ": type of argument mismatch, expecting: " +
+                   kTypeNames[BASE_TYPE_DOUBLE] +
+                   ", found: " + kTypeNames[e.type.base_type] +
+                   ", name: " + (name ? *name : "") + ", value: " + e.constant);
+    }
+    NEXT();
+    EXPECT('(');
+    ECHECK(Recurse([&]() { return ParseSingleValue(name, e, false); }));
+    EXPECT(')');
+    // calculate with double precision
+    double x, y = 0.0;
+    ECHECK(atot(e.constant.c_str(), *this, &x));
+    auto func_match = false;
+    // clang-format off
+    #define FLATBUFFERS_FN_DOUBLE(name, op) \
+      if (!func_match && functionname == name) { y = op; func_match = true; }
+    FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180);
+    FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180);
+    FLATBUFFERS_FN_DOUBLE("sin", sin(x));
+    FLATBUFFERS_FN_DOUBLE("cos", cos(x));
+    FLATBUFFERS_FN_DOUBLE("tan", tan(x));
+    FLATBUFFERS_FN_DOUBLE("asin", asin(x));
+    FLATBUFFERS_FN_DOUBLE("acos", acos(x));
+    FLATBUFFERS_FN_DOUBLE("atan", atan(x));
+    // TODO(wvo): add more useful conversion functions here.
+    #undef FLATBUFFERS_FN_DOUBLE
+    // clang-format on
+    if (true != func_match) {
+      return Error(std::string("Unknown conversion function: ") + functionname +
+                   ", field name: " + (name ? *name : "") +
+                   ", value: " + e.constant);
+    }
+    e.constant = NumToString(y);
+    return NoError();
+  }
+
+  auto match = false;
+  const auto in_type = e.type.base_type;
+  // clang-format off
+  #define IF_ECHECK_(force, dtoken, check, req)    \
+    if (!match && ((check) || IsConstTrue(force))) \
+    ECHECK(TryTypedValue(name, dtoken, check, e, req, &match))
+  #define TRY_ECHECK(dtoken, check, req) IF_ECHECK_(false, dtoken, check, req)
+  #define FORCE_ECHECK(dtoken, check, req) IF_ECHECK_(true, dtoken, check, req)
+  // clang-format on
+
+  if (token_ == kTokenStringConstant || token_ == kTokenIdentifier) {
+    const auto kTokenStringOrIdent = token_;
+    // The string type is a most probable type, check it first.
+    TRY_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING,
+               BASE_TYPE_STRING);
+
+    // avoid escaped and non-ascii in the string
+    if (!match && (token_ == kTokenStringConstant) && IsScalar(in_type) &&
+        !attr_is_trivial_ascii_string_) {
+      return Error(
+          std::string("type mismatch or invalid value, an initializer of "
+                      "non-string field must be trivial ASCII string: type: ") +
+          kTypeNames[in_type] + ", name: " + (name ? *name : "") +
+          ", value: " + attribute_);
+    }
+
+    // A boolean as true/false. Boolean as Integer check below.
+    if (!match && IsBool(in_type)) {
+      auto is_true = attribute_ == "true";
+      if (is_true || attribute_ == "false") {
+        attribute_ = is_true ? "1" : "0";
+        // accepts both kTokenStringConstant and kTokenIdentifier
+        TRY_ECHECK(kTokenStringOrIdent, IsBool(in_type), BASE_TYPE_BOOL);
+      }
+    }
+    // Check if this could be a string/identifier enum value.
+    // Enum can have only true integer base type.
+    if (!match && IsInteger(in_type) && !IsBool(in_type) &&
+        IsIdentifierStart(*attribute_.c_str())) {
+      ECHECK(ParseEnumFromString(e.type, &e.constant));
+      NEXT();
+      match = true;
+    }
+    // Parse a float/integer number from the string.
+    if (!match) check_now = true;  // Re-pack if parsed from string literal.
+    if (!match && (token_ == kTokenStringConstant) && IsScalar(in_type)) {
+      // remove trailing whitespaces from attribute_
+      auto last = attribute_.find_last_not_of(' ');
+      if (std::string::npos != last)  // has non-whitespace
+        attribute_.resize(last + 1);
+    }
+    // Float numbers or nan, inf, pi, etc.
+    TRY_ECHECK(kTokenStringOrIdent, IsFloat(in_type), BASE_TYPE_FLOAT);
+    // An integer constant in string.
+    TRY_ECHECK(kTokenStringOrIdent, IsInteger(in_type), BASE_TYPE_INT);
+    // Unknown tokens will be interpreted as string type.
+    // An attribute value may be a scalar or string constant.
+    FORCE_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING,
+                 BASE_TYPE_STRING);
+  } else {
+    // Try a float number.
+    TRY_ECHECK(kTokenFloatConstant, IsFloat(in_type), BASE_TYPE_FLOAT);
+    // Integer token can init any scalar (integer of float).
+    FORCE_ECHECK(kTokenIntegerConstant, IsScalar(in_type), BASE_TYPE_INT);
+  }
+#undef FORCE_ECHECK
+#undef TRY_ECHECK
+#undef IF_ECHECK_
+
+  if (!match) {
+    std::string msg;
+    msg += "Cannot assign token starting with '" + TokenToStringId(token_) +
+           "' to value of <" + std::string(kTypeNames[in_type]) + "> type.";
+    return Error(msg);
+  }
+  const auto match_type = e.type.base_type; // may differ from in_type
+  // The check_now flag must be true when parse a fbs-schema.
+  // This flag forces to check default scalar values or metadata of field.
+  // For JSON parser the flag should be false.
+  // If it is set for JSON each value will be checked twice (see ParseTable).
+  if (check_now && IsScalar(match_type)) {
+    // clang-format off
+    switch (match_type) {
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+            CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+            case BASE_TYPE_ ## ENUM: {\
+                CTYPE val; \
+                ECHECK(atot(e.constant.c_str(), *this, &val)); \
+                SingleValueRepack(e, val); \
+              break; }
+    FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
+    #undef FLATBUFFERS_TD
+    default: break;
+    }
+    // clang-format on
+  }
+  return NoError();
+}
+
+StructDef *Parser::LookupCreateStruct(const std::string &name,
+                                      bool create_if_new, bool definition) {
+  std::string qualified_name = current_namespace_->GetFullyQualifiedName(name);
+  // See if it exists pre-declared by an unqualified use.
+  auto struct_def = LookupStruct(name);
+  if (struct_def && struct_def->predecl) {
+    if (definition) {
+      // Make sure it has the current namespace, and is registered under its
+      // qualified name.
+      struct_def->defined_namespace = current_namespace_;
+      structs_.Move(name, qualified_name);
+    }
+    return struct_def;
+  }
+  // See if it exists pre-declared by an qualified use.
+  struct_def = LookupStruct(qualified_name);
+  if (struct_def && struct_def->predecl) {
+    if (definition) {
+      // Make sure it has the current namespace.
+      struct_def->defined_namespace = current_namespace_;
+    }
+    return struct_def;
+  }
+  if (!definition) {
+    // Search thru parent namespaces.
+    for (size_t components = current_namespace_->components.size();
+         components && !struct_def; components--) {
+      struct_def = LookupStruct(
+          current_namespace_->GetFullyQualifiedName(name, components - 1));
+    }
+  }
+  if (!struct_def && create_if_new) {
+    struct_def = new StructDef();
+    if (definition) {
+      structs_.Add(qualified_name, struct_def);
+      struct_def->name = name;
+      struct_def->defined_namespace = current_namespace_;
+    } else {
+      // Not a definition.
+      // Rather than failing, we create a "pre declared" StructDef, due to
+      // circular references, and check for errors at the end of parsing.
+      // It is defined in the current namespace, as the best guess what the
+      // final namespace will be.
+      structs_.Add(name, struct_def);
+      struct_def->name = name;
+      struct_def->defined_namespace = current_namespace_;
+      struct_def->original_location.reset(
+          new std::string(file_being_parsed_ + ":" + NumToString(line_)));
+    }
+  }
+  return struct_def;
+}
+
+const EnumVal *EnumDef::MinValue() const {
+  return vals.vec.empty() ? nullptr : vals.vec.front();
+}
+const EnumVal *EnumDef::MaxValue() const {
+  return vals.vec.empty() ? nullptr : vals.vec.back();
+}
+
+template<typename T> static uint64_t EnumDistanceImpl(T e1, T e2) {
+  if (e1 < e2) { std::swap(e1, e2); }  // use std for scalars
+  // Signed overflow may occur, use unsigned calculation.
+  // The unsigned overflow is well-defined by C++ standard (modulo 2^n).
+  return static_cast<uint64_t>(e1) - static_cast<uint64_t>(e2);
+}
+
+uint64_t EnumDef::Distance(const EnumVal *v1, const EnumVal *v2) const {
+  return IsUInt64() ? EnumDistanceImpl(v1->GetAsUInt64(), v2->GetAsUInt64())
+                    : EnumDistanceImpl(v1->GetAsInt64(), v2->GetAsInt64());
+}
+
+std::string EnumDef::AllFlags() const {
+  FLATBUFFERS_ASSERT(attributes.Lookup("bit_flags"));
+  uint64_t u64 = 0;
+  for (auto it = Vals().begin(); it != Vals().end(); ++it) {
+    u64 |= (*it)->GetAsUInt64();
+  }
+  return IsUInt64() ? NumToString(u64) : NumToString(static_cast<int64_t>(u64));
+}
+
+EnumVal *EnumDef::ReverseLookup(int64_t enum_idx,
+                                bool skip_union_default) const {
+  auto skip_first = static_cast<int>(is_union && skip_union_default);
+  for (auto it = Vals().begin() + skip_first; it != Vals().end(); ++it) {
+    if ((*it)->GetAsInt64() == enum_idx) { return *it; }
+  }
+  return nullptr;
+}
+
+EnumVal *EnumDef::FindByValue(const std::string &constant) const {
+  int64_t i64;
+  auto done = false;
+  if (IsUInt64()) {
+    uint64_t u64;  // avoid reinterpret_cast of pointers
+    done = StringToNumber(constant.c_str(), &u64);
+    i64 = static_cast<int64_t>(u64);
+  } else {
+    done = StringToNumber(constant.c_str(), &i64);
+  }
+  FLATBUFFERS_ASSERT(done);
+  if (!done) return nullptr;
+  return ReverseLookup(i64, false);
+}
+
+void EnumDef::SortByValue() {
+  auto &v = vals.vec;
+  if (IsUInt64())
+    std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) {
+      return e1->GetAsUInt64() < e2->GetAsUInt64();
+    });
+  else
+    std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) {
+      return e1->GetAsInt64() < e2->GetAsInt64();
+    });
+}
+
+void EnumDef::RemoveDuplicates() {
+  // This method depends form SymbolTable implementation!
+  // 1) vals.vec - owner (raw pointer)
+  // 2) vals.dict - access map
+  auto first = vals.vec.begin();
+  auto last = vals.vec.end();
+  if (first == last) return;
+  auto result = first;
+  while (++first != last) {
+    if ((*result)->value != (*first)->value) {
+      *(++result) = *first;
+    } else {
+      auto ev = *first;
+      for (auto it = vals.dict.begin(); it != vals.dict.end(); ++it) {
+        if (it->second == ev) it->second = *result;  // reassign
+      }
+      delete ev;  // delete enum value
+      *first = nullptr;
+    }
+  }
+  vals.vec.erase(++result, last);
+}
+
+template<typename T> void EnumDef::ChangeEnumValue(EnumVal *ev, T new_value) {
+  ev->value = static_cast<int64_t>(new_value);
+}
+
+namespace EnumHelper {
+template<BaseType E> struct EnumValType { typedef int64_t type; };
+template<> struct EnumValType<BASE_TYPE_ULONG> { typedef uint64_t type; };
+}  // namespace EnumHelper
+
+struct EnumValBuilder {
+  EnumVal *CreateEnumerator(const std::string &ev_name) {
+    FLATBUFFERS_ASSERT(!temp);
+    auto first = enum_def.vals.vec.empty();
+    user_value = first;
+    temp = new EnumVal(ev_name, first ? 0 : enum_def.vals.vec.back()->value);
+    return temp;
+  }
+
+  EnumVal *CreateEnumerator(const std::string &ev_name, int64_t val) {
+    FLATBUFFERS_ASSERT(!temp);
+    user_value = true;
+    temp = new EnumVal(ev_name, val);
+    return temp;
+  }
+
+  FLATBUFFERS_CHECKED_ERROR AcceptEnumerator(const std::string &name) {
+    FLATBUFFERS_ASSERT(temp);
+    ECHECK(ValidateValue(&temp->value, false == user_value));
+    FLATBUFFERS_ASSERT((temp->union_type.enum_def == nullptr) ||
+                       (temp->union_type.enum_def == &enum_def));
+    auto not_unique = enum_def.vals.Add(name, temp);
+    temp = nullptr;
+    if (not_unique) return parser.Error("enum value already exists: " + name);
+    return NoError();
+  }
+
+  FLATBUFFERS_CHECKED_ERROR AcceptEnumerator() {
+    return AcceptEnumerator(temp->name);
+  }
+
+  FLATBUFFERS_CHECKED_ERROR AssignEnumeratorValue(const std::string &value) {
+    user_value = true;
+    auto fit = false;
+    auto ascending = false;
+    if (enum_def.IsUInt64()) {
+      uint64_t u64;
+      fit = StringToNumber(value.c_str(), &u64);
+      ascending = u64 > temp->GetAsUInt64();
+      temp->value = static_cast<int64_t>(u64);  // well-defined since C++20.
+    } else {
+      int64_t i64;
+      fit = StringToNumber(value.c_str(), &i64);
+      ascending = i64 > temp->GetAsInt64();
+      temp->value = i64;
+    }
+    if (!fit) return parser.Error("enum value does not fit, \"" + value + "\"");
+    if (!ascending && strict_ascending && !enum_def.vals.vec.empty())
+      return parser.Error("enum values must be specified in ascending order");
+    return NoError();
+  }
+
+  template<BaseType E, typename CTYPE>
+  inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) {
+    typedef typename EnumHelper::EnumValType<E>::type T;  // int64_t or uint64_t
+    static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
+    const auto v = static_cast<T>(*ev);
+    auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
+    auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
+    if (v < dn || v > (up - m)) {
+      return parser.Error("enum value does not fit, \"" + NumToString(v) +
+                          (m ? " + 1\"" : "\"") + " out of " +
+                          TypeToIntervalString<CTYPE>());
+    }
+    *ev = static_cast<int64_t>(v + m);  // well-defined since C++20.
+    return NoError();
+  }
+
+  FLATBUFFERS_CHECKED_ERROR ValidateValue(int64_t *ev, bool next) {
+    // clang-format off
+    switch (enum_def.underlying_type.base_type) {
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE,   \
+                           PTYPE, RTYPE, KTYPE)                         \
+      case BASE_TYPE_##ENUM: {                                          \
+        if (!IsInteger(BASE_TYPE_##ENUM)) break;                        \
+        return ValidateImpl<BASE_TYPE_##ENUM, CTYPE>(ev, next ? 1 : 0); \
+      }
+      FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
+    #undef FLATBUFFERS_TD
+    default: break;
+    }
+    // clang-format on
+    return parser.Error("fatal: invalid enum underlying type");
+  }
+
+  EnumValBuilder(Parser &_parser, EnumDef &_enum_def, bool strict_order = true)
+      : parser(_parser),
+        enum_def(_enum_def),
+        temp(nullptr),
+        strict_ascending(strict_order),
+        user_value(false) {}
+
+  ~EnumValBuilder() { delete temp; }
+
+  Parser &parser;
+  EnumDef &enum_def;
+  EnumVal *temp;
+  const bool strict_ascending;
+  bool user_value;
+};
+
+CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest) {
+  std::vector<std::string> enum_comment = doc_comment_;
+  NEXT();
+  std::string enum_name = attribute_;
+  EXPECT(kTokenIdentifier);
+  EnumDef *enum_def;
+  ECHECK(StartEnum(enum_name, is_union, &enum_def));
+  enum_def->doc_comment = enum_comment;
+  if (!is_union && !opts.proto_mode) {
+    // Give specialized error message, since this type spec used to
+    // be optional in the first FlatBuffers release.
+    if (!Is(':')) {
+      return Error(
+          "must specify the underlying integer type for this"
+          " enum (e.g. \': short\', which was the default).");
+    } else {
+      NEXT();
+    }
+    // Specify the integer type underlying this enum.
+    ECHECK(ParseType(enum_def->underlying_type));
+    if (!IsInteger(enum_def->underlying_type.base_type) ||
+        IsBool(enum_def->underlying_type.base_type))
+      return Error("underlying enum type must be integral");
+    // Make this type refer back to the enum it was derived from.
+    enum_def->underlying_type.enum_def = enum_def;
+  }
+  ECHECK(ParseMetaData(&enum_def->attributes));
+  const auto underlying_type = enum_def->underlying_type.base_type;
+  if (enum_def->attributes.Lookup("bit_flags") &&
+      !IsUnsigned(underlying_type)) {
+    // todo: Convert to the Error in the future?
+    Warning("underlying type of bit_flags enum must be unsigned");
+  }
+  // Protobuf allows them to be specified in any order, so sort afterwards.
+  const auto strict_ascending = (false == opts.proto_mode);
+  EnumValBuilder evb(*this, *enum_def, strict_ascending);
+  EXPECT('{');
+  // A lot of code generatos expect that an enum is not-empty.
+  if ((is_union || Is('}')) && !opts.proto_mode) {
+    evb.CreateEnumerator("NONE");
+    ECHECK(evb.AcceptEnumerator());
+  }
+  std::set<std::pair<BaseType, StructDef *>> union_types;
+  while (!Is('}')) {
+    if (opts.proto_mode && attribute_ == "option") {
+      ECHECK(ParseProtoOption());
+    } else {
+      auto &ev = *evb.CreateEnumerator(attribute_);
+      auto full_name = ev.name;
+      ev.doc_comment = doc_comment_;
+      EXPECT(kTokenIdentifier);
+      if (is_union) {
+        ECHECK(ParseNamespacing(&full_name, &ev.name));
+        if (opts.union_value_namespacing) {
+          // Since we can't namespace the actual enum identifiers, turn
+          // namespace parts into part of the identifier.
+          ev.name = full_name;
+          std::replace(ev.name.begin(), ev.name.end(), '.', '_');
+        }
+        if (Is(':')) {
+          NEXT();
+          ECHECK(ParseType(ev.union_type));
+          if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
+              ev.union_type.base_type != BASE_TYPE_STRING)
+            return Error("union value type may only be table/struct/string");
+        } else {
+          ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
+        }
+        if (!enum_def->uses_multiple_type_instances) {
+          auto ins = union_types.insert(std::make_pair(
+              ev.union_type.base_type, ev.union_type.struct_def));
+          enum_def->uses_multiple_type_instances = (false == ins.second);
+        }
+      }
+
+      if (Is('=')) {
+        NEXT();
+        ECHECK(evb.AssignEnumeratorValue(attribute_));
+        EXPECT(kTokenIntegerConstant);
+      } else if (false == strict_ascending) {
+        // The opts.proto_mode flag is active.
+        return Error("Protobuf mode doesn't allow implicit enum values.");
+      }
+
+      ECHECK(evb.AcceptEnumerator());
+
+      if (opts.proto_mode && Is('[')) {
+        NEXT();
+        // ignore attributes on enums.
+        while (token_ != ']') NEXT();
+        NEXT();
+      }
+    }
+    if (!Is(opts.proto_mode ? ';' : ',')) break;
+    NEXT();
+  }
+  EXPECT('}');
+
+  // At this point, the enum can be empty if input is invalid proto-file.
+  if (!enum_def->size())
+    return Error("incomplete enum declaration, values not found");
+
+  if (enum_def->attributes.Lookup("bit_flags")) {
+    const auto base_width = static_cast<uint64_t>(8 * SizeOf(underlying_type));
+    for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
+         ++it) {
+      auto ev = *it;
+      const auto u = ev->GetAsUInt64();
+      // Stop manipulations with the sign.
+      if (!IsUnsigned(underlying_type) && u == (base_width - 1))
+        return Error("underlying type of bit_flags enum must be unsigned");
+      if (u >= base_width)
+        return Error("bit flag out of range of underlying integral type");
+      enum_def->ChangeEnumValue(ev, 1ULL << u);
+    }
+  }
+
+  if (false == strict_ascending)
+    enum_def->SortByValue();  // Must be sorted to use MinValue/MaxValue.
+
+  if (dest) *dest = enum_def;
+  types_.Add(current_namespace_->GetFullyQualifiedName(enum_def->name),
+             new Type(BASE_TYPE_UNION, nullptr, enum_def));
+  return NoError();
+}
+
+CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
+  auto &struct_def = *LookupCreateStruct(name, true, true);
+  if (!struct_def.predecl) return Error("datatype already exists: " + name);
+  struct_def.predecl = false;
+  struct_def.name = name;
+  struct_def.file = file_being_parsed_;
+  // Move this struct to the back of the vector just in case it was predeclared,
+  // to preserve declaration order.
+  *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) =
+      &struct_def;
+  *dest = &struct_def;
+  return NoError();
+}
+
+CheckedError Parser::CheckClash(std::vector<FieldDef *> &fields,
+                                StructDef *struct_def, const char *suffix,
+                                BaseType basetype) {
+  auto len = strlen(suffix);
+  for (auto it = fields.begin(); it != fields.end(); ++it) {
+    auto &fname = (*it)->name;
+    if (fname.length() > len &&
+        fname.compare(fname.length() - len, len, suffix) == 0 &&
+        (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
+      auto field =
+          struct_def->fields.Lookup(fname.substr(0, fname.length() - len));
+      if (field && field->value.type.base_type == basetype)
+        return Error("Field " + fname +
+                     " would clash with generated functions for field " +
+                     field->name);
+    }
+  }
+  return NoError();
+}
+
+bool Parser::SupportsAdvancedUnionFeatures() const {
+  return opts.lang_to_generate != 0 &&
+         (opts.lang_to_generate & ~(IDLOptions::kCpp | IDLOptions::kJs |
+                                    IDLOptions::kTs | IDLOptions::kPhp |
+                                    IDLOptions::kJava | IDLOptions::kCSharp |
+                                    IDLOptions::kKotlin |
+                                    IDLOptions::kBinary)) == 0;
+}
+
+bool Parser::SupportsAdvancedArrayFeatures() const {
+  return (opts.lang_to_generate &
+          ~(IDLOptions::kCpp | IDLOptions::kPython | IDLOptions::kJava |
+            IDLOptions::kCSharp | IDLOptions::kJsonSchema | IDLOptions::kJson |
+            IDLOptions::kBinary)) == 0;
+}
+
+Namespace *Parser::UniqueNamespace(Namespace *ns) {
+  for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) {
+    if (ns->components == (*it)->components) {
+      delete ns;
+      return *it;
+    }
+  }
+  namespaces_.push_back(ns);
+  return ns;
+}
+
+std::string Parser::UnqualifiedName(const std::string &full_qualified_name) {
+  Namespace *ns = new Namespace();
+
+  std::size_t current, previous = 0;
+  current = full_qualified_name.find('.');
+  while (current != std::string::npos) {
+    ns->components.push_back(
+        full_qualified_name.substr(previous, current - previous));
+    previous = current + 1;
+    current = full_qualified_name.find('.', previous);
+  }
+  current_namespace_ = UniqueNamespace(ns);
+  return full_qualified_name.substr(previous, current - previous);
+}
+
+static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
+  auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
+  auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
+  return a_id < b_id;
+}
+
+CheckedError Parser::ParseDecl() {
+  std::vector<std::string> dc = doc_comment_;
+  bool fixed = IsIdent("struct");
+  if (!fixed && !IsIdent("table")) return Error("declaration expected");
+  NEXT();
+  std::string name = attribute_;
+  EXPECT(kTokenIdentifier);
+  StructDef *struct_def;
+  ECHECK(StartStruct(name, &struct_def));
+  struct_def->doc_comment = dc;
+  struct_def->fixed = fixed;
+  ECHECK(ParseMetaData(&struct_def->attributes));
+  struct_def->sortbysize =
+      struct_def->attributes.Lookup("original_order") == nullptr && !fixed;
+  EXPECT('{');
+  while (token_ != '}') ECHECK(ParseField(*struct_def));
+  auto force_align = struct_def->attributes.Lookup("force_align");
+  if (fixed) {
+    if (force_align) {
+      auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
+      if (force_align->type.base_type != BASE_TYPE_INT ||
+          align < struct_def->minalign || align > FLATBUFFERS_MAX_ALIGNMENT ||
+          align & (align - 1))
+        return Error(
+            "force_align must be a power of two integer ranging from the"
+            "struct\'s natural alignment to " +
+            NumToString(FLATBUFFERS_MAX_ALIGNMENT));
+      struct_def->minalign = align;
+    }
+    if (!struct_def->bytesize) return Error("size 0 structs not allowed");
+  }
+  struct_def->PadLastField(struct_def->minalign);
+  // Check if this is a table that has manual id assignments
+  auto &fields = struct_def->fields.vec;
+  if (!fixed && fields.size()) {
+    size_t num_id_fields = 0;
+    for (auto it = fields.begin(); it != fields.end(); ++it) {
+      if ((*it)->attributes.Lookup("id")) num_id_fields++;
+    }
+    // If any fields have ids..
+    if (num_id_fields) {
+      // Then all fields must have them.
+      if (num_id_fields != fields.size())
+        return Error(
+            "either all fields or no fields must have an 'id' attribute");
+      // Simply sort by id, then the fields are the same as if no ids had
+      // been specified.
+      std::sort(fields.begin(), fields.end(), compareFieldDefs);
+      // Verify we have a contiguous set, and reassign vtable offsets.
+      for (int i = 0; i < static_cast<int>(fields.size()); i++) {
+        if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str()))
+          return Error("field id\'s must be consecutive from 0, id " +
+                       NumToString(i) + " missing or set twice");
+        fields[i]->value.offset = FieldIndexToOffset(static_cast<voffset_t>(i));
+      }
+    }
+  }
+
+  ECHECK(
+      CheckClash(fields, struct_def, UnionTypeFieldSuffix(), BASE_TYPE_UNION));
+  ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION));
+  ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR));
+  ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR));
+  ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
+  ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
+  EXPECT('}');
+  types_.Add(current_namespace_->GetFullyQualifiedName(struct_def->name),
+             new Type(BASE_TYPE_STRUCT, struct_def, nullptr));
+  return NoError();
+}
+
+CheckedError Parser::ParseService() {
+  std::vector<std::string> service_comment = doc_comment_;
+  NEXT();
+  auto service_name = attribute_;
+  EXPECT(kTokenIdentifier);
+  auto &service_def = *new ServiceDef();
+  service_def.name = service_name;
+  service_def.file = file_being_parsed_;
+  service_def.doc_comment = service_comment;
+  service_def.defined_namespace = current_namespace_;
+  if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name),
+                    &service_def))
+    return Error("service already exists: " + service_name);
+  ECHECK(ParseMetaData(&service_def.attributes));
+  EXPECT('{');
+  do {
+    std::vector<std::string> doc_comment = doc_comment_;
+    auto rpc_name = attribute_;
+    EXPECT(kTokenIdentifier);
+    EXPECT('(');
+    Type reqtype, resptype;
+    ECHECK(ParseTypeIdent(reqtype));
+    EXPECT(')');
+    EXPECT(':');
+    ECHECK(ParseTypeIdent(resptype));
+    if (reqtype.base_type != BASE_TYPE_STRUCT || reqtype.struct_def->fixed ||
+        resptype.base_type != BASE_TYPE_STRUCT || resptype.struct_def->fixed)
+      return Error("rpc request and response types must be tables");
+    auto &rpc = *new RPCCall();
+    rpc.name = rpc_name;
+    rpc.request = reqtype.struct_def;
+    rpc.response = resptype.struct_def;
+    rpc.doc_comment = doc_comment;
+    if (service_def.calls.Add(rpc_name, &rpc))
+      return Error("rpc already exists: " + rpc_name);
+    ECHECK(ParseMetaData(&rpc.attributes));
+    EXPECT(';');
+  } while (token_ != '}');
+  NEXT();
+  return NoError();
+}
+
+bool Parser::SetRootType(const char *name) {
+  root_struct_def_ = LookupStruct(name);
+  if (!root_struct_def_)
+    root_struct_def_ =
+        LookupStruct(current_namespace_->GetFullyQualifiedName(name));
+  return root_struct_def_ != nullptr;
+}
+
+void Parser::MarkGenerated() {
+  // This function marks all existing definitions as having already
+  // been generated, which signals no code for included files should be
+  // generated.
+  for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
+    (*it)->generated = true;
+  }
+  for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
+    if (!(*it)->predecl) { (*it)->generated = true; }
+  }
+  for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
+    (*it)->generated = true;
+  }
+}
+
+CheckedError Parser::ParseNamespace() {
+  NEXT();
+  auto ns = new Namespace();
+  namespaces_.push_back(ns);  // Store it here to not leak upon error.
+  if (token_ != ';') {
+    for (;;) {
+      ns->components.push_back(attribute_);
+      EXPECT(kTokenIdentifier);
+      if (Is('.')) NEXT() else break;
+    }
+  }
+  namespaces_.pop_back();
+  current_namespace_ = UniqueNamespace(ns);
+  EXPECT(';');
+  return NoError();
+}
+
+// Best effort parsing of .proto declarations, with the aim to turn them
+// in the closest corresponding FlatBuffer equivalent.
+// We parse everything as identifiers instead of keywords, since we don't
+// want protobuf keywords to become invalid identifiers in FlatBuffers.
+CheckedError Parser::ParseProtoDecl() {
+  bool isextend = IsIdent("extend");
+  if (IsIdent("package")) {
+    // These are identical in syntax to FlatBuffer's namespace decl.
+    ECHECK(ParseNamespace());
+  } else if (IsIdent("message") || isextend) {
+    std::vector<std::string> struct_comment = doc_comment_;
+    NEXT();
+    StructDef *struct_def = nullptr;
+    Namespace *parent_namespace = nullptr;
+    if (isextend) {
+      if (Is('.')) NEXT();  // qualified names may start with a . ?
+      auto id = attribute_;
+      EXPECT(kTokenIdentifier);
+      ECHECK(ParseNamespacing(&id, nullptr));
+      struct_def = LookupCreateStruct(id, false);
+      if (!struct_def)
+        return Error("cannot extend unknown message type: " + id);
+    } else {
+      std::string name = attribute_;
+      EXPECT(kTokenIdentifier);
+      ECHECK(StartStruct(name, &struct_def));
+      // Since message definitions can be nested, we create a new namespace.
+      auto ns = new Namespace();
+      // Copy of current namespace.
+      *ns = *current_namespace_;
+      // But with current message name.
+      ns->components.push_back(name);
+      ns->from_table++;
+      parent_namespace = current_namespace_;
+      current_namespace_ = UniqueNamespace(ns);
+    }
+    struct_def->doc_comment = struct_comment;
+    ECHECK(ParseProtoFields(struct_def, isextend, false));
+    if (!isextend) { current_namespace_ = parent_namespace; }
+    if (Is(';')) NEXT();
+  } else if (IsIdent("enum")) {
+    // These are almost the same, just with different terminator:
+    EnumDef *enum_def;
+    ECHECK(ParseEnum(false, &enum_def));
+    if (Is(';')) NEXT();
+    // Temp: remove any duplicates, as .fbs files can't handle them.
+    enum_def->RemoveDuplicates();
+  } else if (IsIdent("syntax")) {  // Skip these.
+    NEXT();
+    EXPECT('=');
+    EXPECT(kTokenStringConstant);
+    EXPECT(';');
+  } else if (IsIdent("option")) {  // Skip these.
+    ECHECK(ParseProtoOption());
+    EXPECT(';');
+  } else if (IsIdent("service")) {  // Skip these.
+    NEXT();
+    EXPECT(kTokenIdentifier);
+    ECHECK(ParseProtoCurliesOrIdent());
+  } else {
+    return Error("don\'t know how to parse .proto declaration starting with " +
+                 TokenToStringId(token_));
+  }
+  return NoError();
+}
+
+CheckedError Parser::StartEnum(const std::string &enum_name, bool is_union,
+                               EnumDef **dest) {
+  auto &enum_def = *new EnumDef();
+  enum_def.name = enum_name;
+  enum_def.file = file_being_parsed_;
+  enum_def.doc_comment = doc_comment_;
+  enum_def.is_union = is_union;
+  enum_def.defined_namespace = current_namespace_;
+  if (enums_.Add(current_namespace_->GetFullyQualifiedName(enum_name),
+                 &enum_def))
+    return Error("enum already exists: " + enum_name);
+  enum_def.underlying_type.base_type = is_union ? BASE_TYPE_UTYPE
+                                                : BASE_TYPE_INT;
+  enum_def.underlying_type.enum_def = &enum_def;
+  if (dest) *dest = &enum_def;
+  return NoError();
+}
+
+CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend,
+                                      bool inside_oneof) {
+  EXPECT('{');
+  while (token_ != '}') {
+    if (IsIdent("message") || IsIdent("extend") || IsIdent("enum")) {
+      // Nested declarations.
+      ECHECK(ParseProtoDecl());
+    } else if (IsIdent("extensions")) {  // Skip these.
+      NEXT();
+      EXPECT(kTokenIntegerConstant);
+      if (Is(kTokenIdentifier)) {
+        NEXT();  // to
+        NEXT();  // num
+      }
+      EXPECT(';');
+    } else if (IsIdent("option")) {  // Skip these.
+      ECHECK(ParseProtoOption());
+      EXPECT(';');
+    } else if (IsIdent("reserved")) {  // Skip these.
+      NEXT();
+      while (!Is(';')) { NEXT(); }  // A variety of formats, just skip.
+      NEXT();
+    } else {
+      std::vector<std::string> field_comment = doc_comment_;
+      // Parse the qualifier.
+      bool required = false;
+      bool repeated = false;
+      bool oneof = false;
+      if (!inside_oneof) {
+        if (IsIdent("optional")) {
+          // This is the default.
+          NEXT();
+        } else if (IsIdent("required")) {
+          required = true;
+          NEXT();
+        } else if (IsIdent("repeated")) {
+          repeated = true;
+          NEXT();
+        } else if (IsIdent("oneof")) {
+          oneof = true;
+          NEXT();
+        } else {
+          // can't error, proto3 allows decls without any of the above.
+        }
+      }
+      StructDef *anonymous_struct = nullptr;
+      EnumDef *oneof_union = nullptr;
+      Type type;
+      if (IsIdent("group") || oneof) {
+        if (!oneof) NEXT();
+        if (oneof && opts.proto_oneof_union) {
+          auto name = MakeCamel(attribute_, true) + "Union";
+          ECHECK(StartEnum(name, true, &oneof_union));
+          type = Type(BASE_TYPE_UNION, nullptr, oneof_union);
+        } else {
+          auto name = "Anonymous" + NumToString(anonymous_counter++);
+          ECHECK(StartStruct(name, &anonymous_struct));
+          type = Type(BASE_TYPE_STRUCT, anonymous_struct);
+        }
+      } else {
+        ECHECK(ParseTypeFromProtoType(&type));
+      }
+      // Repeated elements get mapped to a vector.
+      if (repeated) {
+        type.element = type.base_type;
+        type.base_type = BASE_TYPE_VECTOR;
+        if (type.element == BASE_TYPE_VECTOR) {
+          // We have a vector or vectors, which FlatBuffers doesn't support.
+          // For now make it a vector of string (since the source is likely
+          // "repeated bytes").
+          // TODO(wvo): A better solution would be to wrap this in a table.
+          type.element = BASE_TYPE_STRING;
+        }
+      }
+      std::string name = attribute_;
+      EXPECT(kTokenIdentifier);
+      if (!oneof) {
+        // Parse the field id. Since we're just translating schemas, not
+        // any kind of binary compatibility, we can safely ignore these, and
+        // assign our own.
+        EXPECT('=');
+        EXPECT(kTokenIntegerConstant);
+      }
+      FieldDef *field = nullptr;
+      if (isextend) {
+        // We allow a field to be re-defined when extending.
+        // TODO: are there situations where that is problematic?
+        field = struct_def->fields.Lookup(name);
+      }
+      if (!field) ECHECK(AddField(*struct_def, name, type, &field));
+      field->doc_comment = field_comment;
+      if (!IsScalar(type.base_type)) field->required = required;
+      // See if there's a default specified.
+      if (Is('[')) {
+        NEXT();
+        for (;;) {
+          auto key = attribute_;
+          ECHECK(ParseProtoKey());
+          EXPECT('=');
+          auto val = attribute_;
+          ECHECK(ParseProtoCurliesOrIdent());
+          if (key == "default") {
+            // Temp: skip non-numeric defaults (enums).
+            auto numeric = strpbrk(val.c_str(), "0123456789-+.");
+            if (IsScalar(type.base_type) && numeric == val.c_str())
+              field->value.constant = val;
+          } else if (key == "deprecated") {
+            field->deprecated = val == "true";
+          }
+          if (!Is(',')) break;
+          NEXT();
+        }
+        EXPECT(']');
+      }
+      if (anonymous_struct) {
+        ECHECK(ParseProtoFields(anonymous_struct, false, oneof));
+        if (Is(';')) NEXT();
+      } else if (oneof_union) {
+        // Parse into a temporary StructDef, then transfer fields into an
+        // EnumDef describing the oneof as a union.
+        StructDef oneof_struct;
+        ECHECK(ParseProtoFields(&oneof_struct, false, oneof));
+        if (Is(';')) NEXT();
+        for (auto field_it = oneof_struct.fields.vec.begin();
+             field_it != oneof_struct.fields.vec.end(); ++field_it) {
+          const auto &oneof_field = **field_it;
+          const auto &oneof_type = oneof_field.value.type;
+          if (oneof_type.base_type != BASE_TYPE_STRUCT ||
+              !oneof_type.struct_def || oneof_type.struct_def->fixed)
+            return Error("oneof '" + name +
+                "' cannot be mapped to a union because member '" +
+                oneof_field.name + "' is not a table type.");
+          EnumValBuilder evb(*this, *oneof_union);
+          auto ev = evb.CreateEnumerator(oneof_type.struct_def->name);
+          ev->union_type = oneof_type;
+          ev->doc_comment = oneof_field.doc_comment;
+          ECHECK(evb.AcceptEnumerator(oneof_field.name));
+        }
+      } else {
+        EXPECT(';');
+      }
+    }
+  }
+  NEXT();
+  return NoError();
+}
+
+CheckedError Parser::ParseProtoKey() {
+  if (token_ == '(') {
+    NEXT();
+    // Skip "(a.b)" style custom attributes.
+    while (token_ == '.' || token_ == kTokenIdentifier) NEXT();
+    EXPECT(')');
+    while (Is('.')) {
+      NEXT();
+      EXPECT(kTokenIdentifier);
+    }
+  } else {
+    EXPECT(kTokenIdentifier);
+  }
+  return NoError();
+}
+
+CheckedError Parser::ParseProtoCurliesOrIdent() {
+  if (Is('{')) {
+    NEXT();
+    for (int nesting = 1; nesting;) {
+      if (token_ == '{')
+        nesting++;
+      else if (token_ == '}')
+        nesting--;
+      NEXT();
+    }
+  } else {
+    NEXT();  // Any single token.
+  }
+  return NoError();
+}
+
+CheckedError Parser::ParseProtoOption() {
+  NEXT();
+  ECHECK(ParseProtoKey());
+  EXPECT('=');
+  ECHECK(ParseProtoCurliesOrIdent());
+  return NoError();
+}
+
+// Parse a protobuf type, and map it to the corresponding FlatBuffer one.
+CheckedError Parser::ParseTypeFromProtoType(Type *type) {
+  struct type_lookup {
+    const char *proto_type;
+    BaseType fb_type, element;
+  };
+  static type_lookup lookup[] = {
+    { "float", BASE_TYPE_FLOAT, BASE_TYPE_NONE },
+    { "double", BASE_TYPE_DOUBLE, BASE_TYPE_NONE },
+    { "int32", BASE_TYPE_INT, BASE_TYPE_NONE },
+    { "int64", BASE_TYPE_LONG, BASE_TYPE_NONE },
+    { "uint32", BASE_TYPE_UINT, BASE_TYPE_NONE },
+    { "uint64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
+    { "sint32", BASE_TYPE_INT, BASE_TYPE_NONE },
+    { "sint64", BASE_TYPE_LONG, BASE_TYPE_NONE },
+    { "fixed32", BASE_TYPE_UINT, BASE_TYPE_NONE },
+    { "fixed64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
+    { "sfixed32", BASE_TYPE_INT, BASE_TYPE_NONE },
+    { "sfixed64", BASE_TYPE_LONG, BASE_TYPE_NONE },
+    { "bool", BASE_TYPE_BOOL, BASE_TYPE_NONE },
+    { "string", BASE_TYPE_STRING, BASE_TYPE_NONE },
+    { "bytes", BASE_TYPE_VECTOR, BASE_TYPE_UCHAR },
+    { nullptr, BASE_TYPE_NONE, BASE_TYPE_NONE }
+  };
+  for (auto tl = lookup; tl->proto_type; tl++) {
+    if (attribute_ == tl->proto_type) {
+      type->base_type = tl->fb_type;
+      type->element = tl->element;
+      NEXT();
+      return NoError();
+    }
+  }
+  if (Is('.')) NEXT();  // qualified names may start with a . ?
+  ECHECK(ParseTypeIdent(*type));
+  return NoError();
+}
+
+CheckedError Parser::SkipAnyJsonValue() {
+  switch (token_) {
+    case '{': {
+      size_t fieldn_outer = 0;
+      return ParseTableDelimiters(
+          fieldn_outer, nullptr,
+          [&](const std::string &, size_t &fieldn,
+              const StructDef *) -> CheckedError {
+            ECHECK(Recurse([&]() { return SkipAnyJsonValue(); }));
+            fieldn++;
+            return NoError();
+          });
+    }
+    case '[': {
+      uoffset_t count = 0;
+      return ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
+        return Recurse([&]() { return SkipAnyJsonValue(); });
+      });
+    }
+    case kTokenStringConstant:
+    case kTokenIntegerConstant:
+    case kTokenFloatConstant: NEXT(); break;
+    default:
+      if (IsIdent("true") || IsIdent("false") || IsIdent("null")) {
+        NEXT();
+      } else
+        return TokenError();
+  }
+  return NoError();
+}
+
+CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
+  switch (token_) {
+    case '{': {
+      auto start = builder->StartMap();
+      size_t fieldn_outer = 0;
+      auto err =
+          ParseTableDelimiters(fieldn_outer, nullptr,
+                               [&](const std::string &name, size_t &fieldn,
+                                   const StructDef *) -> CheckedError {
+                                 builder->Key(name);
+                                 ECHECK(ParseFlexBufferValue(builder));
+                                 fieldn++;
+                                 return NoError();
+                               });
+      ECHECK(err);
+      builder->EndMap(start);
+      break;
+    }
+    case '[': {
+      auto start = builder->StartVector();
+      uoffset_t count = 0;
+      ECHECK(ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
+        return ParseFlexBufferValue(builder);
+      }));
+      builder->EndVector(start, false, false);
+      break;
+    }
+    case kTokenStringConstant:
+      builder->String(attribute_);
+      EXPECT(kTokenStringConstant);
+      break;
+    case kTokenIntegerConstant:
+      builder->Int(StringToInt(attribute_.c_str()));
+      EXPECT(kTokenIntegerConstant);
+      break;
+    case kTokenFloatConstant:
+      builder->Double(strtod(attribute_.c_str(), nullptr));
+      EXPECT(kTokenFloatConstant);
+      break;
+    default:
+      if (IsIdent("true")) {
+        builder->Bool(true);
+        NEXT();
+      } else if (IsIdent("false")) {
+        builder->Bool(false);
+        NEXT();
+      } else if (IsIdent("null")) {
+        builder->Null();
+        NEXT();
+      } else
+        return TokenError();
+  }
+  return NoError();
+}
+
+bool Parser::ParseFlexBuffer(const char *source, const char *source_filename,
+                             flexbuffers::Builder *builder) {
+  auto ok = !StartParseFile(source, source_filename).Check() &&
+            !ParseFlexBufferValue(builder).Check();
+  if (ok) builder->Finish();
+  return ok;
+}
+
+bool Parser::Parse(const char *source, const char **include_paths,
+                   const char *source_filename) {
+  FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
+  auto r = !ParseRoot(source, include_paths, source_filename).Check();
+  FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
+  return r;
+}
+
+CheckedError Parser::StartParseFile(const char *source,
+                                    const char *source_filename) {
+  file_being_parsed_ = source_filename ? source_filename : "";
+  source_ = source;
+  ResetState(source_);
+  error_.clear();
+  ECHECK(SkipByteOrderMark());
+  NEXT();
+  if (Is(kTokenEof)) return Error("input file is empty");
+  return NoError();
+}
+
+CheckedError Parser::ParseRoot(const char *source, const char **include_paths,
+                               const char *source_filename) {
+  ECHECK(DoParse(source, include_paths, source_filename, nullptr));
+
+  // Check that all types were defined.
+  for (auto it = structs_.vec.begin(); it != structs_.vec.end();) {
+    auto &struct_def = **it;
+    if (struct_def.predecl) {
+      if (opts.proto_mode) {
+        // Protos allow enums to be used before declaration, so check if that
+        // is the case here.
+        EnumDef *enum_def = nullptr;
+        for (size_t components =
+                 struct_def.defined_namespace->components.size() + 1;
+             components && !enum_def; components--) {
+          auto qualified_name =
+              struct_def.defined_namespace->GetFullyQualifiedName(
+                  struct_def.name, components - 1);
+          enum_def = LookupEnum(qualified_name);
+        }
+        if (enum_def) {
+          // This is pretty slow, but a simple solution for now.
+          auto initial_count = struct_def.refcount;
+          for (auto struct_it = structs_.vec.begin();
+               struct_it != structs_.vec.end(); ++struct_it) {
+            auto &sd = **struct_it;
+            for (auto field_it = sd.fields.vec.begin();
+                 field_it != sd.fields.vec.end(); ++field_it) {
+              auto &field = **field_it;
+              if (field.value.type.struct_def == &struct_def) {
+                field.value.type.struct_def = nullptr;
+                field.value.type.enum_def = enum_def;
+                auto &bt = field.value.type.base_type == BASE_TYPE_VECTOR
+                               ? field.value.type.element
+                               : field.value.type.base_type;
+                FLATBUFFERS_ASSERT(bt == BASE_TYPE_STRUCT);
+                bt = enum_def->underlying_type.base_type;
+                struct_def.refcount--;
+                enum_def->refcount++;
+              }
+            }
+          }
+          if (struct_def.refcount)
+            return Error("internal: " + NumToString(struct_def.refcount) + "/" +
+                         NumToString(initial_count) +
+                         " use(s) of pre-declaration enum not accounted for: " +
+                         enum_def->name);
+          structs_.dict.erase(structs_.dict.find(struct_def.name));
+          it = structs_.vec.erase(it);
+          delete &struct_def;
+          continue;  // Skip error.
+        }
+      }
+      auto err = "type referenced but not defined (check namespace): " +
+                 struct_def.name;
+      if (struct_def.original_location)
+        err += ", originally at: " + *struct_def.original_location;
+      return Error(err);
+    }
+    ++it;
+  }
+
+  // This check has to happen here and not earlier, because only now do we
+  // know for sure what the type of these are.
+  for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
+    auto &enum_def = **it;
+    if (enum_def.is_union) {
+      for (auto val_it = enum_def.Vals().begin();
+           val_it != enum_def.Vals().end(); ++val_it) {
+        auto &val = **val_it;
+        if (!SupportsAdvancedUnionFeatures() && val.union_type.struct_def &&
+            val.union_type.struct_def->fixed)
+          return Error(
+              "only tables can be union elements in the generated language: " +
+              val.name);
+      }
+    }
+  }
+  return NoError();
+}
+
+CheckedError Parser::DoParse(const char *source, const char **include_paths,
+                             const char *source_filename,
+                             const char *include_filename) {
+  if (source_filename) {
+    if (included_files_.find(source_filename) == included_files_.end()) {
+      included_files_[source_filename] =
+          include_filename ? include_filename : "";
+      files_included_per_file_[source_filename] = std::set<std::string>();
+    } else {
+      return NoError();
+    }
+  }
+  if (!include_paths) {
+    static const char *current_directory[] = { "", nullptr };
+    include_paths = current_directory;
+  }
+  field_stack_.clear();
+  builder_.Clear();
+  // Start with a blank namespace just in case this file doesn't have one.
+  current_namespace_ = empty_namespace_;
+
+  ECHECK(StartParseFile(source, source_filename));
+
+  // Includes must come before type declarations:
+  for (;;) {
+    // Parse pre-include proto statements if any:
+    if (opts.proto_mode && (attribute_ == "option" || attribute_ == "syntax" ||
+                            attribute_ == "package")) {
+      ECHECK(ParseProtoDecl());
+    } else if (IsIdent("native_include")) {
+      NEXT();
+      vector_emplace_back(&native_included_files_, attribute_);
+      EXPECT(kTokenStringConstant);
+      EXPECT(';');
+    } else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) {
+      NEXT();
+      if (opts.proto_mode && attribute_ == "public") NEXT();
+      auto name = flatbuffers::PosixPath(attribute_.c_str());
+      EXPECT(kTokenStringConstant);
+      // Look for the file in include_paths.
+      std::string filepath;
+      for (auto paths = include_paths; paths && *paths; paths++) {
+        filepath = flatbuffers::ConCatPathFileName(*paths, name);
+        if (FileExists(filepath.c_str())) break;
+      }
+      if (filepath.empty())
+        return Error("unable to locate include file: " + name);
+      if (source_filename)
+        files_included_per_file_[source_filename].insert(filepath);
+      if (included_files_.find(filepath) == included_files_.end()) {
+        // We found an include file that we have not parsed yet.
+        // Load it and parse it.
+        std::string contents;
+        if (!LoadFile(filepath.c_str(), true, &contents))
+          return Error("unable to load include file: " + name);
+        ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
+                       name.c_str()));
+        // We generally do not want to output code for any included files:
+        if (!opts.generate_all) MarkGenerated();
+        // Reset these just in case the included file had them, and the
+        // parent doesn't.
+        root_struct_def_ = nullptr;
+        file_identifier_.clear();
+        file_extension_.clear();
+        // This is the easiest way to continue this file after an include:
+        // instead of saving and restoring all the state, we simply start the
+        // file anew. This will cause it to encounter the same include
+        // statement again, but this time it will skip it, because it was
+        // entered into included_files_.
+        // This is recursive, but only go as deep as the number of include
+        // statements.
+        if (source_filename) {
+          included_files_.erase(source_filename);
+        }
+        return DoParse(source, include_paths, source_filename,
+                       include_filename);
+      }
+      EXPECT(';');
+    } else {
+      break;
+    }
+  }
+  // Now parse all other kinds of declarations:
+  while (token_ != kTokenEof) {
+    if (opts.proto_mode) {
+      ECHECK(ParseProtoDecl());
+    } else if (IsIdent("namespace")) {
+      ECHECK(ParseNamespace());
+    } else if (token_ == '{') {
+      if (!root_struct_def_)
+        return Error("no root type set to parse json with");
+      if (builder_.GetSize()) {
+        return Error("cannot have more than one json object in a file");
+      }
+      uoffset_t toff;
+      ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
+      if (opts.size_prefixed) {
+        builder_.FinishSizePrefixed(Offset<Table>(toff), file_identifier_.length()
+                                                             ? file_identifier_.c_str()
+                                                             : nullptr);
+      } else {
+        builder_.Finish(Offset<Table>(toff), file_identifier_.length()
+                                                 ? file_identifier_.c_str()
+                                                 : nullptr);
+      }
+      // Check that JSON file doesn't contain more objects or IDL directives.
+      // Comments after JSON are allowed.
+      EXPECT(kTokenEof);
+    } else if (IsIdent("enum")) {
+      ECHECK(ParseEnum(false, nullptr));
+    } else if (IsIdent("union")) {
+      ECHECK(ParseEnum(true, nullptr));
+    } else if (IsIdent("root_type")) {
+      NEXT();
+      auto root_type = attribute_;
+      EXPECT(kTokenIdentifier);
+      ECHECK(ParseNamespacing(&root_type, nullptr));
+      if (opts.root_type.empty()) {
+        if (!SetRootType(root_type.c_str()))
+          return Error("unknown root type: " + root_type);
+        if (root_struct_def_->fixed)
+          return Error("root type must be a table");
+      }
+      EXPECT(';');
+    } else if (IsIdent("file_identifier")) {
+      NEXT();
+      file_identifier_ = attribute_;
+      EXPECT(kTokenStringConstant);
+      if (file_identifier_.length() != FlatBufferBuilder::kFileIdentifierLength)
+        return Error("file_identifier must be exactly " +
+                     NumToString(FlatBufferBuilder::kFileIdentifierLength) +
+                     " characters");
+      EXPECT(';');
+    } else if (IsIdent("file_extension")) {
+      NEXT();
+      file_extension_ = attribute_;
+      EXPECT(kTokenStringConstant);
+      EXPECT(';');
+    } else if (IsIdent("include")) {
+      return Error("includes must come before declarations");
+    } else if (IsIdent("attribute")) {
+      NEXT();
+      auto name = attribute_;
+      if (Is(kTokenIdentifier)) {
+        NEXT();
+      } else {
+        EXPECT(kTokenStringConstant);
+      }
+      EXPECT(';');
+      known_attributes_[name] = false;
+    } else if (IsIdent("rpc_service")) {
+      ECHECK(ParseService());
+    } else {
+      ECHECK(ParseDecl());
+    }
+  }
+  return NoError();
+}
+
+std::set<std::string> Parser::GetIncludedFilesRecursive(
+    const std::string &file_name) const {
+  std::set<std::string> included_files;
+  std::list<std::string> to_process;
+
+  if (file_name.empty()) return included_files;
+  to_process.push_back(file_name);
+
+  while (!to_process.empty()) {
+    std::string current = to_process.front();
+    to_process.pop_front();
+    included_files.insert(current);
+
+    // Workaround the lack of const accessor in C++98 maps.
+    auto &new_files =
+        (*const_cast<std::map<std::string, std::set<std::string>> *>(
+            &files_included_per_file_))[current];
+    for (auto it = new_files.begin(); it != new_files.end(); ++it) {
+      if (included_files.find(*it) == included_files.end())
+        to_process.push_back(*it);
+    }
+  }
+
+  return included_files;
+}
+
+// Schema serialization functionality:
+
+template<typename T> bool compareName(const T *a, const T *b) {
+  return a->defined_namespace->GetFullyQualifiedName(a->name) <
+         b->defined_namespace->GetFullyQualifiedName(b->name);
+}
+
+template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
+  // Pre-sort these vectors, such that we can set the correct indices for them.
+  auto vec = defvec;
+  std::sort(vec.begin(), vec.end(), compareName<T>);
+  for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
+}
+
+void Parser::Serialize() {
+  builder_.Clear();
+  AssignIndices(structs_.vec);
+  AssignIndices(enums_.vec);
+  std::vector<Offset<reflection::Object>> object_offsets;
+  for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
+    auto offset = (*it)->Serialize(&builder_, *this);
+    object_offsets.push_back(offset);
+    (*it)->serialized_location = offset.o;
+  }
+  std::vector<Offset<reflection::Enum>> enum_offsets;
+  for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
+    auto offset = (*it)->Serialize(&builder_, *this);
+    enum_offsets.push_back(offset);
+    (*it)->serialized_location = offset.o;
+  }
+  std::vector<Offset<reflection::Service>> service_offsets;
+  for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
+    auto offset = (*it)->Serialize(&builder_, *this);
+    service_offsets.push_back(offset);
+    (*it)->serialized_location = offset.o;
+  }
+  auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets);
+  auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets);
+  auto fiid__ = builder_.CreateString(file_identifier_);
+  auto fext__ = builder_.CreateString(file_extension_);
+  auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
+  auto schema_offset =
+      reflection::CreateSchema(builder_, objs__, enum__, fiid__, fext__,
+        (root_struct_def_ ? root_struct_def_->serialized_location : 0),
+        serv__);
+  if (opts.size_prefixed) {
+    builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier());
+  } else {
+    builder_.Finish(schema_offset, reflection::SchemaIdentifier());
+  }
+}
+
+static Namespace *GetNamespace(
+    const std::string &qualified_name, std::vector<Namespace *> &namespaces,
+    std::map<std::string, Namespace *> &namespaces_index) {
+  size_t dot = qualified_name.find_last_of('.');
+  std::string namespace_name = (dot != std::string::npos)
+                                   ? std::string(qualified_name.c_str(), dot)
+                                   : "";
+  Namespace *&ns = namespaces_index[namespace_name];
+
+  if (!ns) {
+    ns = new Namespace();
+    namespaces.push_back(ns);
+
+    size_t pos = 0;
+
+    for (;;) {
+      dot = qualified_name.find('.', pos);
+      if (dot == std::string::npos) { break; }
+      ns->components.push_back(qualified_name.substr(pos, dot - pos));
+      pos = dot + 1;
+    }
+  }
+
+  return ns;
+}
+
+Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
+                                                const Parser &parser) const {
+  std::vector<Offset<reflection::Field>> field_offsets;
+  for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
+    field_offsets.push_back((*it)->Serialize(
+        builder, static_cast<uint16_t>(it - fields.vec.begin()), parser));
+  }
+  auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
+  auto name__ = builder->CreateString(qualified_name);
+  auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets);
+  auto attr__ = SerializeAttributes(builder, parser);
+  auto docs__ = parser.opts.binary_schema_comments
+                ? builder->CreateVectorOfStrings(doc_comment)
+                : 0;
+  return reflection::CreateObject(*builder, name__, flds__, fixed,
+                                  static_cast<int>(minalign),
+                                  static_cast<int>(bytesize),
+                                  attr__, docs__);
+}
+
+bool StructDef::Deserialize(Parser &parser, const reflection::Object *object) {
+  if (!DeserializeAttributes(parser, object->attributes()))
+    return false;
+  DeserializeDoc(doc_comment, object->documentation());
+  name = parser.UnqualifiedName(object->name()->str());
+  predecl = false;
+  sortbysize = attributes.Lookup("original_order") == nullptr && !fixed;
+  const auto& of = *(object->fields());
+  auto indexes = std::vector<uoffset_t>(of.size());
+  for (uoffset_t i = 0; i < of.size(); i++) indexes[of.Get(i)->id()] = i;
+  size_t tmp_struct_size = 0;
+  for (size_t i = 0; i < indexes.size(); i++) {
+    auto field = of.Get(indexes[i]);
+    auto field_def = new FieldDef();
+    if (!field_def->Deserialize(parser, field) ||
+        fields.Add(field_def->name, field_def)) {
+      delete field_def;
+      return false;
+    }
+    if (fixed) {
+      // Recompute padding since that's currently not serialized.
+      auto size = InlineSize(field_def->value.type);
+      auto next_field =
+          i + 1 < indexes.size()
+          ? of.Get(indexes[i+1])
+          : nullptr;
+      tmp_struct_size += size;
+      field_def->padding =
+          next_field ? (next_field->offset() - field_def->value.offset) - size
+                     : PaddingBytes(tmp_struct_size, minalign);
+      tmp_struct_size += field_def->padding;
+    }
+  }
+  FLATBUFFERS_ASSERT(static_cast<int>(tmp_struct_size) == object->bytesize());
+  return true;
+}
+
+Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
+                                              uint16_t id,
+                                              const Parser &parser) const {
+  auto name__ = builder->CreateString(name);
+  auto type__ = value.type.Serialize(builder);
+  auto attr__ = SerializeAttributes(builder, parser);
+  auto docs__ = parser.opts.binary_schema_comments
+                ? builder->CreateVectorOfStrings(doc_comment)
+                : 0;
+  return reflection::CreateField(*builder, name__, type__, id, value.offset,
+      // Is uint64>max(int64) tested?
+      IsInteger(value.type.base_type) ? StringToInt(value.constant.c_str()) : 0,
+      // result may be platform-dependent if underlying is float (not double)
+      IsFloat(value.type.base_type) ? strtod(value.constant.c_str(), nullptr)
+                                    : 0.0,
+      deprecated, required, key, attr__, docs__);
+  // TODO: value.constant is almost always "0", we could save quite a bit of
+  // space by sharing it. Same for common values of value.type.
+}
+
+bool FieldDef::Deserialize(Parser &parser, const reflection::Field *field) {
+  name = field->name()->str();
+  defined_namespace = parser.current_namespace_;
+  if (!value.type.Deserialize(parser, field->type()))
+    return false;
+  value.offset = field->offset();
+  if (IsInteger(value.type.base_type)) {
+    value.constant = NumToString(field->default_integer());
+  } else if (IsFloat(value.type.base_type)) {
+    value.constant = FloatToString(field->default_real(), 16);
+    size_t last_zero = value.constant.find_last_not_of('0');
+    if (last_zero != std::string::npos && last_zero != 0) {
+      value.constant.erase(last_zero, std::string::npos);
+    }
+  }
+  deprecated = field->deprecated();
+  required = field->required();
+  key = field->key();
+  if (!DeserializeAttributes(parser, field->attributes()))
+    return false;
+  // TODO: this should probably be handled by a separate attribute
+  if (attributes.Lookup("flexbuffer")) {
+    flexbuffer = true;
+    parser.uses_flexbuffers_ = true;
+    if (value.type.base_type != BASE_TYPE_VECTOR ||
+        value.type.element != BASE_TYPE_UCHAR)
+      return false;
+  }
+  if (auto nested = attributes.Lookup("nested_flatbuffer")) {
+    auto nested_qualified_name =
+        parser.current_namespace_->GetFullyQualifiedName(nested->constant);
+    nested_flatbuffer = parser.LookupStruct(nested_qualified_name);
+    if (!nested_flatbuffer) return false;
+  }
+  DeserializeDoc(doc_comment, field->documentation());
+  return true;
+}
+
+Offset<reflection::RPCCall> RPCCall::Serialize(FlatBufferBuilder *builder,
+                                               const Parser &parser) const {
+  auto name__ = builder->CreateString(name);
+  auto attr__ = SerializeAttributes(builder, parser);
+  auto docs__ = parser.opts.binary_schema_comments
+                ? builder->CreateVectorOfStrings(doc_comment)
+                : 0;
+  return reflection::CreateRPCCall(*builder, name__,
+                                   request->serialized_location,
+                                   response->serialized_location,
+                                   attr__, docs__);
+}
+
+bool RPCCall::Deserialize(Parser &parser, const reflection::RPCCall *call) {
+  name = call->name()->str();
+  if (!DeserializeAttributes(parser, call->attributes()))
+    return false;
+  DeserializeDoc(doc_comment, call->documentation());
+  request = parser.structs_.Lookup(call->request()->name()->str());
+  response = parser.structs_.Lookup(call->response()->name()->str());
+  if (!request || !response) { return false; }
+  return true;
+}
+
+Offset<reflection::Service> ServiceDef::Serialize(FlatBufferBuilder *builder,
+                                                  const Parser &parser) const {
+  std::vector<Offset<reflection::RPCCall>> servicecall_offsets;
+  for (auto it = calls.vec.begin(); it != calls.vec.end(); ++it) {
+    servicecall_offsets.push_back((*it)->Serialize(builder, parser));
+  }
+  auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
+  auto name__ = builder->CreateString(qualified_name);
+  auto call__ = builder->CreateVector(servicecall_offsets);
+  auto attr__ = SerializeAttributes(builder, parser);
+  auto docs__ = parser.opts.binary_schema_comments
+                ? builder->CreateVectorOfStrings(doc_comment)
+                : 0;
+  return reflection::CreateService(*builder, name__, call__, attr__, docs__);
+}
+
+bool ServiceDef::Deserialize(Parser &parser,
+                             const reflection::Service *service) {
+  name = parser.UnqualifiedName(service->name()->str());
+  if (service->calls()) {
+    for (uoffset_t i = 0; i < service->calls()->size(); ++i) {
+      auto call = new RPCCall();
+      if (!call->Deserialize(parser, service->calls()->Get(i)) ||
+          calls.Add(call->name, call)) {
+        delete call;
+        return false;
+      }
+    }
+  }
+  if (!DeserializeAttributes(parser, service->attributes()))
+    return false;
+  DeserializeDoc(doc_comment, service->documentation());
+  return true;
+}
+
+Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
+                                            const Parser &parser) const {
+  std::vector<Offset<reflection::EnumVal>> enumval_offsets;
+  for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
+    enumval_offsets.push_back((*it)->Serialize(builder, parser));
+  }
+  auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
+  auto name__ = builder->CreateString(qualified_name);
+  auto vals__ = builder->CreateVector(enumval_offsets);
+  auto type__ = underlying_type.Serialize(builder);
+  auto attr__ = SerializeAttributes(builder, parser);
+  auto docs__ = parser.opts.binary_schema_comments
+                ? builder->CreateVectorOfStrings(doc_comment)
+                : 0;
+  return reflection::CreateEnum(*builder, name__, vals__, is_union, type__,
+                                attr__, docs__);
+}
+
+bool EnumDef::Deserialize(Parser &parser, const reflection::Enum *_enum) {
+  name = parser.UnqualifiedName(_enum->name()->str());
+  for (uoffset_t i = 0; i < _enum->values()->size(); ++i) {
+    auto val = new EnumVal();
+    if (!val->Deserialize(parser, _enum->values()->Get(i)) ||
+        vals.Add(val->name, val)) {
+      delete val;
+      return false;
+    }
+  }
+  is_union = _enum->is_union();
+  if (!underlying_type.Deserialize(parser, _enum->underlying_type())) {
+    return false;
+  }
+  if (!DeserializeAttributes(parser, _enum->attributes()))
+    return false;
+  DeserializeDoc(doc_comment, _enum->documentation());
+  return true;
+}
+
+Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder,
+                                               const Parser &parser) const {
+  auto name__ = builder->CreateString(name);
+  auto type__ = union_type.Serialize(builder);
+  auto docs__ = parser.opts.binary_schema_comments
+                ? builder->CreateVectorOfStrings(doc_comment)
+                : 0;
+  return reflection::CreateEnumVal(*builder, name__, value,
+      union_type.struct_def ? union_type.struct_def->serialized_location : 0,
+      type__, docs__);
+}
+
+bool EnumVal::Deserialize(const Parser &parser,
+                          const reflection::EnumVal *val) {
+  name = val->name()->str();
+  value = val->value();
+  if (!union_type.Deserialize(parser, val->union_type()))
+    return false;
+  DeserializeDoc(doc_comment, val->documentation());
+  return true;
+}
+
+Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
+  return reflection::CreateType(
+      *builder, static_cast<reflection::BaseType>(base_type),
+      static_cast<reflection::BaseType>(element),
+      struct_def ? struct_def->index : (enum_def ? enum_def->index : -1),
+      fixed_length);
+}
+
+bool Type::Deserialize(const Parser &parser, const reflection::Type *type) {
+  if (type == nullptr) return true;
+  base_type = static_cast<BaseType>(type->base_type());
+  element = static_cast<BaseType>(type->element());
+  fixed_length = type->fixed_length();
+  if (type->index() >= 0) {
+    bool is_series = type->base_type() == reflection::Vector ||
+                     type->base_type() == reflection::Array;
+    if (type->base_type() == reflection::Obj ||
+        (is_series &&
+         type->element() == reflection::Obj)) {
+      if (static_cast<size_t>(type->index()) < parser.structs_.vec.size()) {
+        struct_def = parser.structs_.vec[type->index()];
+        struct_def->refcount++;
+      } else {
+        return false;
+      }
+    } else {
+      if (static_cast<size_t>(type->index()) < parser.enums_.vec.size()) {
+        enum_def = parser.enums_.vec[type->index()];
+      } else {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+flatbuffers::Offset<
+    flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
+Definition::SerializeAttributes(FlatBufferBuilder *builder,
+                                const Parser &parser) const {
+  std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
+  for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) {
+    auto it = parser.known_attributes_.find(kv->first);
+    FLATBUFFERS_ASSERT(it != parser.known_attributes_.end());
+    if (parser.opts.binary_schema_builtins || !it->second) {
+      auto key = builder->CreateString(kv->first);
+      auto val = builder->CreateString(kv->second->constant);
+      attrs.push_back(reflection::CreateKeyValue(*builder, key, val));
+    }
+  }
+  if (attrs.size()) {
+    return builder->CreateVectorOfSortedTables(&attrs);
+  } else {
+    return 0;
+  }
+}
+
+bool Definition::DeserializeAttributes(
+    Parser &parser, const Vector<Offset<reflection::KeyValue>> *attrs) {
+  if (attrs == nullptr)
+    return true;
+  for (uoffset_t i = 0; i < attrs->size(); ++i) {
+    auto kv = attrs->Get(i);
+    auto value = new Value();
+    if (kv->value()) { value->constant = kv->value()->str(); }
+    if (attributes.Add(kv->key()->str(), value)) {
+      delete value;
+      return false;
+    }
+    parser.known_attributes_[kv->key()->str()];
+  }
+  return true;
+}
+
+/************************************************************************/
+/* DESERIALIZATION                                                      */
+/************************************************************************/
+bool Parser::Deserialize(const uint8_t *buf, const size_t size) {
+  flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t *>(buf), size);
+  bool size_prefixed = false;
+  if(!reflection::SchemaBufferHasIdentifier(buf)) {
+    if (!flatbuffers::BufferHasIdentifier(buf, reflection::SchemaIdentifier(),
+                                          true))
+      return false;
+    else
+      size_prefixed = true;
+  }
+  auto verify_fn = size_prefixed ? &reflection::VerifySizePrefixedSchemaBuffer
+                                 : &reflection::VerifySchemaBuffer;
+  if (!verify_fn(verifier)) {
+    return false;
+  }
+  auto schema = size_prefixed ? reflection::GetSizePrefixedSchema(buf)
+                              : reflection::GetSchema(buf);
+  return Deserialize(schema);
+}
+
+bool Parser::Deserialize(const reflection::Schema *schema) {
+  file_identifier_ = schema->file_ident() ? schema->file_ident()->str() : "";
+  file_extension_ = schema->file_ext() ? schema->file_ext()->str() : "";
+  std::map<std::string, Namespace *> namespaces_index;
+
+  // Create defs without deserializing so references from fields to structs and
+  // enums can be resolved.
+  for (auto it = schema->objects()->begin(); it != schema->objects()->end();
+       ++it) {
+    auto struct_def = new StructDef();
+    struct_def->bytesize = it->bytesize();
+    struct_def->fixed = it->is_struct();
+    struct_def->minalign = it->minalign();
+    if (structs_.Add(it->name()->str(), struct_def)) {
+      delete struct_def;
+      return false;
+    }
+    auto type = new Type(BASE_TYPE_STRUCT, struct_def, nullptr);
+    if (types_.Add(it->name()->str(), type)) {
+      delete type;
+      return false;
+    }
+  }
+  for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) {
+    auto enum_def = new EnumDef();
+    if (enums_.Add(it->name()->str(), enum_def)) {
+      delete enum_def;
+      return false;
+    }
+    auto type = new Type(BASE_TYPE_UNION, nullptr, enum_def);
+    if (types_.Add(it->name()->str(), type)) {
+      delete type;
+      return false;
+    }
+  }
+
+  // Now fields can refer to structs and enums by index.
+  for (auto it = schema->objects()->begin(); it != schema->objects()->end();
+       ++it) {
+    std::string qualified_name = it->name()->str();
+    auto struct_def = structs_.Lookup(qualified_name);
+    struct_def->defined_namespace =
+        GetNamespace(qualified_name, namespaces_, namespaces_index);
+    if (!struct_def->Deserialize(*this, * it)) { return false; }
+    if (schema->root_table() == *it) { root_struct_def_ = struct_def; }
+  }
+  for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) {
+    std::string qualified_name = it->name()->str();
+    auto enum_def = enums_.Lookup(qualified_name);
+    enum_def->defined_namespace =
+        GetNamespace(qualified_name, namespaces_, namespaces_index);
+    if (!enum_def->Deserialize(*this, *it)) { return false; }
+  }
+
+  if (schema->services()) {
+    for (auto it = schema->services()->begin(); it != schema->services()->end();
+         ++it) {
+      std::string qualified_name = it->name()->str();
+      auto service_def = new ServiceDef();
+      service_def->defined_namespace =
+          GetNamespace(qualified_name, namespaces_, namespaces_index);
+      if (!service_def->Deserialize(*this, *it) ||
+          services_.Add(qualified_name, service_def)) {
+        delete service_def;
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+std::string Parser::ConformTo(const Parser &base) {
+  for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) {
+    auto &struct_def = **sit;
+    auto qualified_name =
+        struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name);
+    auto struct_def_base = base.LookupStruct(qualified_name);
+    if (!struct_def_base) continue;
+    for (auto fit = struct_def.fields.vec.begin();
+         fit != struct_def.fields.vec.end(); ++fit) {
+      auto &field = **fit;
+      auto field_base = struct_def_base->fields.Lookup(field.name);
+      if (field_base) {
+        if (field.value.offset != field_base->value.offset)
+          return "offsets differ for field: " + field.name;
+        if (field.value.constant != field_base->value.constant)
+          return "defaults differ for field: " + field.name;
+        if (!EqualByName(field.value.type, field_base->value.type))
+          return "types differ for field: " + field.name;
+      } else {
+        // Doesn't have to exist, deleting fields is fine.
+        // But we should check if there is a field that has the same offset
+        // but is incompatible (in the case of field renaming).
+        for (auto fbit = struct_def_base->fields.vec.begin();
+             fbit != struct_def_base->fields.vec.end(); ++fbit) {
+          field_base = *fbit;
+          if (field.value.offset == field_base->value.offset) {
+            if (!EqualByName(field.value.type, field_base->value.type))
+              return "field renamed to different type: " + field.name;
+            break;
+          }
+        }
+      }
+    }
+  }
+  for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) {
+    auto &enum_def = **eit;
+    auto qualified_name =
+        enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name);
+    auto enum_def_base = base.enums_.Lookup(qualified_name);
+    if (!enum_def_base) continue;
+    for (auto evit = enum_def.Vals().begin(); evit != enum_def.Vals().end();
+         ++evit) {
+      auto &enum_val = **evit;
+      auto enum_val_base = enum_def_base->Lookup(enum_val.name);
+      if (enum_val_base) {
+        if (enum_val != *enum_val_base)
+          return "values differ for enum: " + enum_val.name;
+      }
+    }
+  }
+  return "";
+}
+
+}  // namespace flatbuffers
diff --git a/src/reflection.cpp b/src/reflection.cpp
new file mode 100644
index 0000000..89ce783
--- /dev/null
+++ b/src/reflection.cpp
@@ -0,0 +1,683 @@
+/*
+ * Copyright 2015 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 "flatbuffers/reflection.h"
+#include "flatbuffers/util.h"
+
+// Helper functionality for reflection.
+
+namespace flatbuffers {
+
+int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
+  // clang-format off
+  #define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data))
+  switch (type) {
+    case reflection::UType:
+    case reflection::Bool:
+    case reflection::UByte:  return FLATBUFFERS_GET(uint8_t);
+    case reflection::Byte:   return FLATBUFFERS_GET(int8_t);
+    case reflection::Short:  return FLATBUFFERS_GET(int16_t);
+    case reflection::UShort: return FLATBUFFERS_GET(uint16_t);
+    case reflection::Int:    return FLATBUFFERS_GET(int32_t);
+    case reflection::UInt:   return FLATBUFFERS_GET(uint32_t);
+    case reflection::Long:   return FLATBUFFERS_GET(int64_t);
+    case reflection::ULong:  return FLATBUFFERS_GET(uint64_t);
+    case reflection::Float:  return FLATBUFFERS_GET(float);
+    case reflection::Double: return FLATBUFFERS_GET(double);
+    case reflection::String: {
+      auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
+                                                data);
+      return s ? StringToInt(s->c_str()) : 0;
+    }
+    default: return 0;  // Tables & vectors do not make sense.
+  }
+  #undef FLATBUFFERS_GET
+  // clang-format on
+}
+
+double GetAnyValueF(reflection::BaseType type, const uint8_t *data) {
+  switch (type) {
+    case reflection::Float: return static_cast<double>(ReadScalar<float>(data));
+    case reflection::Double: return ReadScalar<double>(data);
+    case reflection::String: {
+      auto s =
+          reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data);
+      return s ? strtod(s->c_str(), nullptr) : 0.0;
+    }
+    default: return static_cast<double>(GetAnyValueI(type, data));
+  }
+}
+
+std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
+                         const reflection::Schema *schema, int type_index) {
+  switch (type) {
+    case reflection::Float:
+    case reflection::Double: return NumToString(GetAnyValueF(type, data));
+    case reflection::String: {
+      auto s =
+          reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data);
+      return s ? s->c_str() : "";
+    }
+    case reflection::Obj:
+      if (schema) {
+        // Convert the table to a string. This is mostly for debugging purposes,
+        // and does NOT promise to be JSON compliant.
+        // Also prefixes the type.
+        auto &objectdef = *schema->objects()->Get(type_index);
+        auto s = objectdef.name()->str();
+        if (objectdef.is_struct()) {
+          s += "(struct)";  // TODO: implement this as well.
+        } else {
+          auto table_field = reinterpret_cast<const Table *>(
+              ReadScalar<uoffset_t>(data) + data);
+          s += " { ";
+          auto fielddefs = objectdef.fields();
+          for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+            auto &fielddef = **it;
+            if (!table_field->CheckField(fielddef.offset())) continue;
+            auto val = GetAnyFieldS(*table_field, fielddef, schema);
+            if (fielddef.type()->base_type() == reflection::String) {
+              std::string esc;
+              flatbuffers::EscapeString(val.c_str(), val.length(), &esc, true,
+                                        false);
+              val = esc;
+            }
+            s += fielddef.name()->str();
+            s += ": ";
+            s += val;
+            s += ", ";
+          }
+          s += "}";
+        }
+        return s;
+      } else {
+        return "(table)";
+      }
+    case reflection::Vector:
+      return "[(elements)]";                   // TODO: implement this as well.
+    case reflection::Union: return "(union)";  // TODO: implement this as well.
+    default: return NumToString(GetAnyValueI(type, data));
+  }
+}
+
+void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) {
+  // clang-format off
+  #define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val))
+  switch (type) {
+    case reflection::UType:
+    case reflection::Bool:
+    case reflection::UByte:  FLATBUFFERS_SET(uint8_t ); break;
+    case reflection::Byte:   FLATBUFFERS_SET(int8_t  ); break;
+    case reflection::Short:  FLATBUFFERS_SET(int16_t ); break;
+    case reflection::UShort: FLATBUFFERS_SET(uint16_t); break;
+    case reflection::Int:    FLATBUFFERS_SET(int32_t ); break;
+    case reflection::UInt:   FLATBUFFERS_SET(uint32_t); break;
+    case reflection::Long:   FLATBUFFERS_SET(int64_t ); break;
+    case reflection::ULong:  FLATBUFFERS_SET(uint64_t); break;
+    case reflection::Float:  FLATBUFFERS_SET(float   ); break;
+    case reflection::Double: FLATBUFFERS_SET(double  ); break;
+    // TODO: support strings
+    default: break;
+  }
+  #undef FLATBUFFERS_SET
+  // clang-format on
+}
+
+void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val) {
+  switch (type) {
+    case reflection::Float: WriteScalar(data, static_cast<float>(val)); break;
+    case reflection::Double: WriteScalar(data, val); break;
+    // TODO: support strings.
+    default: SetAnyValueI(type, data, static_cast<int64_t>(val)); break;
+  }
+}
+
+void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) {
+  switch (type) {
+    case reflection::Float:
+    case reflection::Double:
+      SetAnyValueF(type, data, strtod(val, nullptr));
+      break;
+    // TODO: support strings.
+    default: SetAnyValueI(type, data, StringToInt(val)); break;
+  }
+}
+
+// Resize a FlatBuffer in-place by iterating through all offsets in the buffer
+// and adjusting them by "delta" if they straddle the start offset.
+// Once that is done, bytes can now be inserted/deleted safely.
+// "delta" may be negative (shrinking).
+// Unless "delta" is a multiple of the largest alignment, you'll create a small
+// amount of garbage space in the buffer (usually 0..7 bytes).
+// If your FlatBuffer's root table is not the schema's root table, you should
+// pass in your root_table type as well.
+class ResizeContext {
+ public:
+  ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta,
+                std::vector<uint8_t> *flatbuf,
+                const reflection::Object *root_table = nullptr)
+      : schema_(schema),
+        startptr_(vector_data(*flatbuf) + start),
+        delta_(delta),
+        buf_(*flatbuf),
+        dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
+    auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1);
+    delta_ = (delta_ + mask) & ~mask;
+    if (!delta_) return;  // We can't shrink by less than largest_scalar_t.
+    // Now change all the offsets by delta_.
+    auto root = GetAnyRoot(vector_data(buf_));
+    Straddle<uoffset_t, 1>(vector_data(buf_), root, vector_data(buf_));
+    ResizeTable(root_table ? *root_table : *schema.root_table(), root);
+    // We can now add or remove bytes at start.
+    if (delta_ > 0)
+      buf_.insert(buf_.begin() + start, delta_, 0);
+    else
+      buf_.erase(buf_.begin() + start, buf_.begin() + start - delta_);
+  }
+
+  // Check if the range between first (lower address) and second straddles
+  // the insertion point. If it does, change the offset at offsetloc (of
+  // type T, with direction D).
+  template<typename T, int D>
+  void Straddle(const void *first, const void *second, void *offsetloc) {
+    if (first <= startptr_ && second >= startptr_) {
+      WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
+      DagCheck(offsetloc) = true;
+    }
+  }
+
+  // This returns a boolean that records if the corresponding offset location
+  // has been modified already. If so, we can't even read the corresponding
+  // offset, since it is pointing to a location that is illegal until the
+  // resize actually happens.
+  // This must be checked for every offset, since we can't know which offsets
+  // will straddle and which won't.
+  uint8_t &DagCheck(const void *offsetloc) {
+    auto dag_idx = reinterpret_cast<const uoffset_t *>(offsetloc) -
+                   reinterpret_cast<const uoffset_t *>(vector_data(buf_));
+    return dag_check_[dag_idx];
+  }
+
+  void ResizeTable(const reflection::Object &objectdef, Table *table) {
+    if (DagCheck(table)) return;  // Table already visited.
+    auto vtable = table->GetVTable();
+    // Early out: since all fields inside the table must point forwards in
+    // memory, if the insertion point is before the table we can stop here.
+    auto tableloc = reinterpret_cast<uint8_t *>(table);
+    if (startptr_ <= tableloc) {
+      // Check if insertion point is between the table and a vtable that
+      // precedes it. This can't happen in current construction code, but check
+      // just in case we ever change the way flatbuffers are built.
+      Straddle<soffset_t, -1>(vtable, table, table);
+    } else {
+      // Check each field.
+      auto fielddefs = objectdef.fields();
+      for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+        auto &fielddef = **it;
+        auto base_type = fielddef.type()->base_type();
+        // Ignore scalars.
+        if (base_type <= reflection::Double) continue;
+        // Ignore fields that are not stored.
+        auto offset = table->GetOptionalFieldOffset(fielddef.offset());
+        if (!offset) continue;
+        // Ignore structs.
+        auto subobjectdef =
+            base_type == reflection::Obj
+                ? schema_.objects()->Get(fielddef.type()->index())
+                : nullptr;
+        if (subobjectdef && subobjectdef->is_struct()) continue;
+        // Get this fields' offset, and read it if safe.
+        auto offsetloc = tableloc + offset;
+        if (DagCheck(offsetloc)) continue;  // This offset already visited.
+        auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
+        Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
+        // Recurse.
+        switch (base_type) {
+          case reflection::Obj: {
+            ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
+            break;
+          }
+          case reflection::Vector: {
+            auto elem_type = fielddef.type()->element();
+            if (elem_type != reflection::Obj && elem_type != reflection::String)
+              break;
+            auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
+            auto elemobjectdef =
+                elem_type == reflection::Obj
+                    ? schema_.objects()->Get(fielddef.type()->index())
+                    : nullptr;
+            if (elemobjectdef && elemobjectdef->is_struct()) break;
+            for (uoffset_t i = 0; i < vec->size(); i++) {
+              auto loc = vec->Data() + i * sizeof(uoffset_t);
+              if (DagCheck(loc)) continue;  // This offset already visited.
+              auto dest = loc + vec->Get(i);
+              Straddle<uoffset_t, 1>(loc, dest, loc);
+              if (elemobjectdef)
+                ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
+            }
+            break;
+          }
+          case reflection::Union: {
+            ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
+                        reinterpret_cast<Table *>(ref));
+            break;
+          }
+          case reflection::String: break;
+          default: FLATBUFFERS_ASSERT(false);
+        }
+      }
+      // Check if the vtable offset points beyond the insertion point.
+      // Must do this last, since GetOptionalFieldOffset above still reads
+      // this value.
+      Straddle<soffset_t, -1>(table, vtable, table);
+    }
+  }
+
+  void operator=(const ResizeContext &rc);
+
+ private:
+  const reflection::Schema &schema_;
+  uint8_t *startptr_;
+  int delta_;
+  std::vector<uint8_t> &buf_;
+  std::vector<uint8_t> dag_check_;
+};
+
+void SetString(const reflection::Schema &schema, const std::string &val,
+               const String *str, std::vector<uint8_t> *flatbuf,
+               const reflection::Object *root_table) {
+  auto delta = static_cast<int>(val.size()) - static_cast<int>(str->size());
+  auto str_start = static_cast<uoffset_t>(
+      reinterpret_cast<const uint8_t *>(str) - vector_data(*flatbuf));
+  auto start = str_start + static_cast<uoffset_t>(sizeof(uoffset_t));
+  if (delta) {
+    // Clear the old string, since we don't want parts of it remaining.
+    memset(vector_data(*flatbuf) + start, 0, str->size());
+    // Different size, we must expand (or contract).
+    ResizeContext(schema, start, delta, flatbuf, root_table);
+    // Set the new length.
+    WriteScalar(vector_data(*flatbuf) + str_start,
+                static_cast<uoffset_t>(val.size()));
+  }
+  // Copy new data. Safe because we created the right amount of space.
+  memcpy(vector_data(*flatbuf) + start, val.c_str(), val.size() + 1);
+}
+
+uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
+                         const VectorOfAny *vec, uoffset_t num_elems,
+                         uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
+                         const reflection::Object *root_table) {
+  auto delta_elem = static_cast<int>(newsize) - static_cast<int>(num_elems);
+  auto delta_bytes = delta_elem * static_cast<int>(elem_size);
+  auto vec_start =
+      reinterpret_cast<const uint8_t *>(vec) - vector_data(*flatbuf);
+  auto start = static_cast<uoffset_t>(vec_start + sizeof(uoffset_t) +
+                                      elem_size * num_elems);
+  if (delta_bytes) {
+    if (delta_elem < 0) {
+      // Clear elements we're throwing away, since some might remain in the
+      // buffer.
+      auto size_clear = -delta_elem * elem_size;
+      memset(vector_data(*flatbuf) + start - size_clear, 0, size_clear);
+    }
+    ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
+    WriteScalar(vector_data(*flatbuf) + vec_start, newsize);  // Length field.
+    // Set new elements to 0.. this can be overwritten by the caller.
+    if (delta_elem > 0) {
+      memset(vector_data(*flatbuf) + start, 0, delta_elem * elem_size);
+    }
+  }
+  return vector_data(*flatbuf) + start;
+}
+
+const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
+                             const uint8_t *newbuf, size_t newlen) {
+  // Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're
+  // going to chop off the root offset.
+  while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) ||
+         !(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) {
+    flatbuf.push_back(0);
+  }
+  auto insertion_point = static_cast<uoffset_t>(flatbuf.size());
+  // Insert the entire FlatBuffer minus the root pointer.
+  flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t), newbuf + newlen);
+  auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t);
+  return vector_data(flatbuf) + insertion_point + root_offset;
+}
+
+void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef,
+                const Table &table, size_t align, size_t size) {
+  fbb.Align(align);
+  fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size);
+  fbb.TrackField(fielddef.offset(), fbb.GetSize());
+}
+
+Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
+                                const reflection::Schema &schema,
+                                const reflection::Object &objectdef,
+                                const Table &table, bool use_string_pooling) {
+  // Before we can construct the table, we have to first generate any
+  // subobjects, and collect their offsets.
+  std::vector<uoffset_t> offsets;
+  auto fielddefs = objectdef.fields();
+  for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+    auto &fielddef = **it;
+    // Skip if field is not present in the source.
+    if (!table.CheckField(fielddef.offset())) continue;
+    uoffset_t offset = 0;
+    switch (fielddef.type()->base_type()) {
+      case reflection::String: {
+        offset = use_string_pooling
+                     ? fbb.CreateSharedString(GetFieldS(table, fielddef)).o
+                     : fbb.CreateString(GetFieldS(table, fielddef)).o;
+        break;
+      }
+      case reflection::Obj: {
+        auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
+        if (!subobjectdef.is_struct()) {
+          offset =
+              CopyTable(fbb, schema, subobjectdef, *GetFieldT(table, fielddef))
+                  .o;
+        }
+        break;
+      }
+      case reflection::Union: {
+        auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
+        offset =
+            CopyTable(fbb, schema, subobjectdef, *GetFieldT(table, fielddef)).o;
+        break;
+      }
+      case reflection::Vector: {
+        auto vec =
+            table.GetPointer<const Vector<Offset<Table>> *>(fielddef.offset());
+        auto element_base_type = fielddef.type()->element();
+        auto elemobjectdef =
+            element_base_type == reflection::Obj
+                ? schema.objects()->Get(fielddef.type()->index())
+                : nullptr;
+        switch (element_base_type) {
+          case reflection::String: {
+            std::vector<Offset<const String *>> elements(vec->size());
+            auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec);
+            for (uoffset_t i = 0; i < vec_s->size(); i++) {
+              elements[i] = use_string_pooling
+                                ? fbb.CreateSharedString(vec_s->Get(i)).o
+                                : fbb.CreateString(vec_s->Get(i)).o;
+            }
+            offset = fbb.CreateVector(elements).o;
+            break;
+          }
+          case reflection::Obj: {
+            if (!elemobjectdef->is_struct()) {
+              std::vector<Offset<const Table *>> elements(vec->size());
+              for (uoffset_t i = 0; i < vec->size(); i++) {
+                elements[i] =
+                    CopyTable(fbb, schema, *elemobjectdef, *vec->Get(i));
+              }
+              offset = fbb.CreateVector(elements).o;
+              break;
+            }
+          }
+          FLATBUFFERS_FALLTHROUGH(); // fall thru
+          default: {  // Scalars and structs.
+            auto element_size = GetTypeSize(element_base_type);
+            if (elemobjectdef && elemobjectdef->is_struct())
+              element_size = elemobjectdef->bytesize();
+            fbb.StartVector(vec->size(), element_size);
+            fbb.PushBytes(vec->Data(), element_size * vec->size());
+            offset = fbb.EndVector(vec->size());
+            break;
+          }
+        }
+        break;
+      }
+      default:  // Scalars.
+        break;
+    }
+    if (offset) { offsets.push_back(offset); }
+  }
+  // Now we can build the actual table from either offsets or scalar data.
+  auto start = objectdef.is_struct() ? fbb.StartStruct(objectdef.minalign())
+                                     : fbb.StartTable();
+  size_t offset_idx = 0;
+  for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+    auto &fielddef = **it;
+    if (!table.CheckField(fielddef.offset())) continue;
+    auto base_type = fielddef.type()->base_type();
+    switch (base_type) {
+      case reflection::Obj: {
+        auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
+        if (subobjectdef.is_struct()) {
+          CopyInline(fbb, fielddef, table, subobjectdef.minalign(),
+                     subobjectdef.bytesize());
+          break;
+        }
+      }
+      FLATBUFFERS_FALLTHROUGH(); // fall thru
+      case reflection::Union:
+      case reflection::String:
+      case reflection::Vector:
+        fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
+        break;
+      default: {  // Scalars.
+        auto size = GetTypeSize(base_type);
+        CopyInline(fbb, fielddef, table, size, size);
+        break;
+      }
+    }
+  }
+  FLATBUFFERS_ASSERT(offset_idx == offsets.size());
+  if (objectdef.is_struct()) {
+    fbb.ClearOffsets();
+    return fbb.EndStruct();
+  } else {
+    return fbb.EndTable(start);
+  }
+}
+
+bool VerifyStruct(flatbuffers::Verifier &v,
+                  const flatbuffers::Table &parent_table,
+                  voffset_t field_offset, const reflection::Object &obj,
+                  bool required) {
+  auto offset = parent_table.GetOptionalFieldOffset(field_offset);
+  if (required && !offset) { return false; }
+
+  return !offset ||
+         v.Verify(reinterpret_cast<const uint8_t *>(&parent_table), offset,
+                  obj.bytesize());
+}
+
+bool VerifyVectorOfStructs(flatbuffers::Verifier &v,
+                           const flatbuffers::Table &parent_table,
+                           voffset_t field_offset,
+                           const reflection::Object &obj, bool required) {
+  auto p = parent_table.GetPointer<const uint8_t *>(field_offset);
+  if (required && !p) { return false; }
+
+  return !p || v.VerifyVectorOrString(p, obj.bytesize());
+}
+
+// forward declare to resolve cyclic deps between VerifyObject and VerifyVector
+bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
+                  const reflection::Object &obj,
+                  const flatbuffers::Table *table, bool required);
+
+bool VerifyVector(flatbuffers::Verifier &v, const reflection::Schema &schema,
+                  const flatbuffers::Table &table,
+                  const reflection::Field &vec_field) {
+  FLATBUFFERS_ASSERT(vec_field.type()->base_type() == reflection::Vector);
+  if (!table.VerifyField<uoffset_t>(v, vec_field.offset())) return false;
+
+  switch (vec_field.type()->element()) {
+    case reflection::None: FLATBUFFERS_ASSERT(false); break;
+    case reflection::UType:
+      return v.VerifyVector(flatbuffers::GetFieldV<uint8_t>(table, vec_field));
+    case reflection::Bool:
+    case reflection::Byte:
+    case reflection::UByte:
+      return v.VerifyVector(flatbuffers::GetFieldV<int8_t>(table, vec_field));
+    case reflection::Short:
+    case reflection::UShort:
+      return v.VerifyVector(flatbuffers::GetFieldV<int16_t>(table, vec_field));
+    case reflection::Int:
+    case reflection::UInt:
+      return v.VerifyVector(flatbuffers::GetFieldV<int32_t>(table, vec_field));
+    case reflection::Long:
+    case reflection::ULong:
+      return v.VerifyVector(flatbuffers::GetFieldV<int64_t>(table, vec_field));
+    case reflection::Float:
+      return v.VerifyVector(flatbuffers::GetFieldV<float>(table, vec_field));
+    case reflection::Double:
+      return v.VerifyVector(flatbuffers::GetFieldV<double>(table, vec_field));
+    case reflection::String: {
+      auto vec_string =
+          flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
+              table, vec_field);
+      if (v.VerifyVector(vec_string) && v.VerifyVectorOfStrings(vec_string)) {
+        return true;
+      } else {
+        return false;
+      }
+    }
+    case reflection::Vector: FLATBUFFERS_ASSERT(false); break;
+    case reflection::Obj: {
+      auto obj = schema.objects()->Get(vec_field.type()->index());
+      if (obj->is_struct()) {
+        if (!VerifyVectorOfStructs(v, table, vec_field.offset(), *obj,
+                                   vec_field.required())) {
+          return false;
+        }
+      } else {
+        auto vec =
+            flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::Table>>(
+                table, vec_field);
+        if (!v.VerifyVector(vec)) return false;
+        if (vec) {
+          for (uoffset_t j = 0; j < vec->size(); j++) {
+            if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) {
+              return false;
+            }
+          }
+        }
+      }
+      return true;
+    }
+    case reflection::Union: FLATBUFFERS_ASSERT(false); break;
+    default: FLATBUFFERS_ASSERT(false); break;
+  }
+
+  return false;
+}
+
+bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
+                  const reflection::Object &obj,
+                  const flatbuffers::Table *table, bool required) {
+  if (!table) {
+    if (!required)
+      return true;
+    else
+      return false;
+  }
+
+  if (!table->VerifyTableStart(v)) return false;
+
+  for (uoffset_t i = 0; i < obj.fields()->size(); i++) {
+    auto field_def = obj.fields()->Get(i);
+    switch (field_def->type()->base_type()) {
+      case reflection::None: FLATBUFFERS_ASSERT(false); break;
+      case reflection::UType:
+        if (!table->VerifyField<uint8_t>(v, field_def->offset())) return false;
+        break;
+      case reflection::Bool:
+      case reflection::Byte:
+      case reflection::UByte:
+        if (!table->VerifyField<int8_t>(v, field_def->offset())) return false;
+        break;
+      case reflection::Short:
+      case reflection::UShort:
+        if (!table->VerifyField<int16_t>(v, field_def->offset())) return false;
+        break;
+      case reflection::Int:
+      case reflection::UInt:
+        if (!table->VerifyField<int32_t>(v, field_def->offset())) return false;
+        break;
+      case reflection::Long:
+      case reflection::ULong:
+        if (!table->VerifyField<int64_t>(v, field_def->offset())) return false;
+        break;
+      case reflection::Float:
+        if (!table->VerifyField<float>(v, field_def->offset())) return false;
+        break;
+      case reflection::Double:
+        if (!table->VerifyField<double>(v, field_def->offset())) return false;
+        break;
+      case reflection::String:
+        if (!table->VerifyField<uoffset_t>(v, field_def->offset()) ||
+            !v.VerifyString(flatbuffers::GetFieldS(*table, *field_def))) {
+          return false;
+        }
+        break;
+      case reflection::Vector:
+        if (!VerifyVector(v, schema, *table, *field_def)) return false;
+        break;
+      case reflection::Obj: {
+        auto child_obj = schema.objects()->Get(field_def->type()->index());
+        if (child_obj->is_struct()) {
+          if (!VerifyStruct(v, *table, field_def->offset(), *child_obj,
+                            field_def->required())) {
+            return false;
+          }
+        } else {
+          if (!VerifyObject(v, schema, *child_obj,
+                            flatbuffers::GetFieldT(*table, *field_def),
+                            field_def->required())) {
+            return false;
+          }
+        }
+        break;
+      }
+      case reflection::Union: {
+        //  get union type from the prev field
+        voffset_t utype_offset = field_def->offset() - sizeof(voffset_t);
+        auto utype = table->GetField<uint8_t>(utype_offset, 0);
+        if (utype != 0) {
+          // Means we have this union field present
+          auto fb_enum = schema.enums()->Get(field_def->type()->index());
+          auto child_obj = fb_enum->values()->Get(utype)->object();
+          if (!VerifyObject(v, schema, *child_obj,
+                            flatbuffers::GetFieldT(*table, *field_def),
+                            field_def->required())) {
+            return false;
+          }
+        }
+        break;
+      }
+      default: FLATBUFFERS_ASSERT(false); break;
+    }
+  }
+
+  if (!v.EndTable()) return false;
+
+  return true;
+}
+
+bool Verify(const reflection::Schema &schema, const reflection::Object &root,
+            const uint8_t *buf, size_t length) {
+  Verifier v(buf, length);
+  return VerifyObject(v, schema, root, flatbuffers::GetAnyRoot(buf), true);
+}
+
+}  // namespace flatbuffers
diff --git a/src/util.cpp b/src/util.cpp
new file mode 100644
index 0000000..5483cee
--- /dev/null
+++ b/src/util.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2016 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.
+ */
+
+// clang-format off
+// Dont't remove `format off`, it prevent reordering of win-includes.
+#ifdef _WIN32
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN
+#  endif
+#  ifndef NOMINMAX
+#    define NOMINMAX
+#  endif
+#  ifdef _MSC_VER
+#    include <crtdbg.h>
+#  endif
+#  include <windows.h>  // Must be included before <direct.h>
+#  include <direct.h>
+#  include <winbase.h>
+#  undef interface  // This is also important because of reasons
+#else
+#  include <limits.h>
+#endif
+// clang-format on
+
+#include "flatbuffers/base.h"
+#include "flatbuffers/util.h"
+
+#include <sys/stat.h>
+#include <clocale>
+#include <fstream>
+
+namespace flatbuffers {
+
+bool FileExistsRaw(const char *name) {
+  std::ifstream ifs(name);
+  return ifs.good();
+}
+
+bool LoadFileRaw(const char *name, bool binary, std::string *buf) {
+  if (DirExists(name)) return false;
+  std::ifstream ifs(name, binary ? std::ifstream::binary : std::ifstream::in);
+  if (!ifs.is_open()) return false;
+  if (binary) {
+    // The fastest way to read a file into a string.
+    ifs.seekg(0, std::ios::end);
+    auto size = ifs.tellg();
+    (*buf).resize(static_cast<size_t>(size));
+    ifs.seekg(0, std::ios::beg);
+    ifs.read(&(*buf)[0], (*buf).size());
+  } else {
+    // This is slower, but works correctly on all platforms for text files.
+    std::ostringstream oss;
+    oss << ifs.rdbuf();
+    *buf = oss.str();
+  }
+  return !ifs.bad();
+}
+
+static LoadFileFunction g_load_file_function = LoadFileRaw;
+static FileExistsFunction g_file_exists_function = FileExistsRaw;
+
+bool LoadFile(const char *name, bool binary, std::string *buf) {
+  FLATBUFFERS_ASSERT(g_load_file_function);
+  return g_load_file_function(name, binary, buf);
+}
+
+bool FileExists(const char *name) {
+  FLATBUFFERS_ASSERT(g_file_exists_function);
+  return g_file_exists_function(name);
+}
+
+bool DirExists(const char *name) {
+  // clang-format off
+
+  #ifdef _WIN32
+    #define flatbuffers_stat _stat
+    #define FLATBUFFERS_S_IFDIR _S_IFDIR
+  #else
+    #define flatbuffers_stat stat
+    #define FLATBUFFERS_S_IFDIR S_IFDIR
+  #endif
+  // clang-format on
+  struct flatbuffers_stat file_info;
+  if (flatbuffers_stat(name, &file_info) != 0) return false;
+  return (file_info.st_mode & FLATBUFFERS_S_IFDIR) != 0;
+}
+
+LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function) {
+  LoadFileFunction previous_function = g_load_file_function;
+  g_load_file_function = load_file_function ? load_file_function : LoadFileRaw;
+  return previous_function;
+}
+
+FileExistsFunction SetFileExistsFunction(
+    FileExistsFunction file_exists_function) {
+  FileExistsFunction previous_function = g_file_exists_function;
+  g_file_exists_function =
+      file_exists_function ? file_exists_function : FileExistsRaw;
+  return previous_function;
+}
+
+bool SaveFile(const char *name, const char *buf, size_t len, bool binary) {
+  std::ofstream ofs(name, binary ? std::ofstream::binary : std::ofstream::out);
+  if (!ofs.is_open()) return false;
+  ofs.write(buf, len);
+  return !ofs.bad();
+}
+
+// We internally store paths in posix format ('/'). Paths supplied
+// by the user should go through PosixPath to ensure correct behavior
+// on Windows when paths are string-compared.
+
+static const char kPathSeparatorWindows = '\\';
+static const char *PathSeparatorSet = "\\/";  // Intentionally no ':'
+
+std::string StripExtension(const std::string &filepath) {
+  size_t i = filepath.find_last_of('.');
+  return i != std::string::npos ? filepath.substr(0, i) : filepath;
+}
+
+std::string GetExtension(const std::string &filepath) {
+  size_t i = filepath.find_last_of('.');
+  return i != std::string::npos ? filepath.substr(i + 1) : "";
+}
+
+std::string StripPath(const std::string &filepath) {
+  size_t i = filepath.find_last_of(PathSeparatorSet);
+  return i != std::string::npos ? filepath.substr(i + 1) : filepath;
+}
+
+std::string StripFileName(const std::string &filepath) {
+  size_t i = filepath.find_last_of(PathSeparatorSet);
+  return i != std::string::npos ? filepath.substr(0, i) : "";
+}
+
+std::string ConCatPathFileName(const std::string &path,
+                               const std::string &filename) {
+  std::string filepath = path;
+  if (filepath.length()) {
+    char &filepath_last_character = string_back(filepath);
+    if (filepath_last_character == kPathSeparatorWindows) {
+      filepath_last_character = kPathSeparator;
+    } else if (filepath_last_character != kPathSeparator) {
+      filepath += kPathSeparator;
+    }
+  }
+  filepath += filename;
+  // Ignore './' at the start of filepath.
+  if (filepath[0] == '.' && filepath[1] == kPathSeparator) {
+    filepath.erase(0, 2);
+  }
+  return filepath;
+}
+
+std::string PosixPath(const char *path) {
+  std::string p = path;
+  std::replace(p.begin(), p.end(), '\\', '/');
+  return p;
+}
+
+void EnsureDirExists(const std::string &filepath) {
+  auto parent = StripFileName(filepath);
+  if (parent.length()) EnsureDirExists(parent);
+    // clang-format off
+
+  #ifdef _WIN32
+    (void)_mkdir(filepath.c_str());
+  #else
+    mkdir(filepath.c_str(), S_IRWXU|S_IRGRP|S_IXGRP);
+  #endif
+  // clang-format on
+}
+
+std::string AbsolutePath(const std::string &filepath) {
+  // clang-format off
+
+  #ifdef FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
+    return filepath;
+  #else
+    #ifdef _WIN32
+      char abs_path[MAX_PATH];
+      return GetFullPathNameA(filepath.c_str(), MAX_PATH, abs_path, nullptr)
+    #else
+      char abs_path[PATH_MAX];
+      return realpath(filepath.c_str(), abs_path)
+    #endif
+      ? abs_path
+      : filepath;
+  #endif // FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
+  // clang-format on
+}
+
+// Locale-independent code.
+#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && \
+    (FLATBUFFERS_LOCALE_INDEPENDENT > 0)
+
+// clang-format off
+// Allocate locale instance at startup of application.
+ClassicLocale ClassicLocale::instance_;
+
+#ifdef _MSC_VER
+  ClassicLocale::ClassicLocale()
+    : locale_(_create_locale(LC_ALL, "C")) {}
+  ClassicLocale::~ClassicLocale() { _free_locale(locale_); }
+#else
+  ClassicLocale::ClassicLocale()
+    : locale_(newlocale(LC_ALL, "C", nullptr)) {}
+  ClassicLocale::~ClassicLocale() { freelocale(locale_); }
+#endif
+// clang-format on
+
+#endif  // !FLATBUFFERS_LOCALE_INDEPENDENT
+
+std::string RemoveStringQuotes(const std::string &s) {
+  auto ch = *s.c_str();
+  return ((s.size() >= 2) && (ch == '\"' || ch == '\'') &&
+          (ch == string_back(s)))
+             ? s.substr(1, s.length() - 2)
+             : s;
+}
+
+bool SetGlobalTestLocale(const char *locale_name, std::string *_value) {
+  const auto the_locale = setlocale(LC_ALL, locale_name);
+  if (!the_locale) return false;
+  if (_value) *_value = std::string(the_locale);
+  return true;
+}
+
+bool ReadEnvironmentVariable(const char *var_name, std::string *_value) {
+  #ifdef _MSC_VER
+  __pragma(warning(disable : 4996)); // _CRT_SECURE_NO_WARNINGS
+  #endif
+  auto env_str = std::getenv(var_name);
+  if (!env_str) return false;
+  if (_value) *_value = std::string(env_str);
+  return true;
+}
+
+void SetupDefaultCRTReportMode() {
+  // clang-format off
+
+  #ifdef _MSC_VER
+    // By default, send all reports to STDOUT to prevent CI hangs.
+    // Enable assert report box [Abort|Retry|Ignore] if a debugger is present.
+    const int dbg_mode = (_CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG) |
+                         (IsDebuggerPresent() ? _CRTDBG_MODE_WNDW : 0);
+    (void)dbg_mode; // release mode fix
+    // CrtDebug reports to _CRT_WARN channel.
+    _CrtSetReportMode(_CRT_WARN, dbg_mode);
+    _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
+    // The assert from <assert.h> reports to _CRT_ERROR channel
+    _CrtSetReportMode(_CRT_ERROR, dbg_mode);
+    _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
+    // Internal CRT assert channel?
+    _CrtSetReportMode(_CRT_ASSERT, dbg_mode);
+    _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);
+  #endif
+
+  // clang-format on
+}
+
+}  // namespace flatbuffers