idl_parser.cpp revision 557c88c0396220e79e9a43c07f8393a5c68b739d
126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen/*
226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen * Copyright 2014 Google Inc. All rights reserved.
326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen *
426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen * Licensed under the Apache License, Version 2.0 (the "License");
526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen * you may not use this file except in compliance with the License.
626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen * You may obtain a copy of the License at
726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen *
826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen *     http://www.apache.org/licenses/LICENSE-2.0
926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen *
1026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen * Unless required by applicable law or agreed to in writing, software
1126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen * distributed under the License is distributed on an "AS IS" BASIS,
1226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen * See the License for the specific language governing permissions and
1426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen * limitations under the License.
1526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen */
1626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
1726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen#include <algorithm>
1826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
1926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen#include "flatbuffers/flatbuffers.h"
2026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen#include "flatbuffers/idl.h"
2126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen#include "flatbuffers/util.h"
2226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
2326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssennamespace flatbuffers {
2426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
2526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenconst char *const kTypeNames[] = {
26557c88c0396220e79e9a43c07f8393a5c68b739dWouter van Oortmerssen  #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) IDLTYPE,
2726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
2826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  #undef FLATBUFFERS_TD
2926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  nullptr
3026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen};
3126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
3226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenconst char kTypeSizes[] = {
33557c88c0396220e79e9a43c07f8393a5c68b739dWouter van Oortmerssen  #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
34557c88c0396220e79e9a43c07f8393a5c68b739dWouter van Oortmerssen      sizeof(CTYPE),
3526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
3626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  #undef FLATBUFFERS_TD
3726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen};
3826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
3926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenstatic void Error(const std::string &msg) {
4026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  throw msg;
4126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
4226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
4326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen// Ensure that integer values we parse fit inside the declared integer type.
4426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenstatic void CheckBitsFit(int64_t val, size_t bits) {
4526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  auto mask = (1ll << bits) - 1;  // Bits we allow to be used.
4626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (bits < 64 &&
4726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      (val & ~mask) != 0 &&  // Positive or unsigned.
4826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      (val |  mask) != -1)   // Negative.
4926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Error("constant does not fit in a " + NumToString(bits) + "-bit field");
5026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
5126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
5226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen// atot: templated version of atoi/atof: convert a string to an instance of T.
5326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssentemplate<typename T> inline T atot(const char *s) {
5426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  auto val = StringToInt(s);
5526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  CheckBitsFit(val, sizeof(T) * 8);
5626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  return (T)val;
5726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
5826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssentemplate<> inline bool atot<bool>(const char *s) {
5926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  return 0 != atoi(s);
6026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
6126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssentemplate<> inline float atot<float>(const char *s) {
6226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  return static_cast<float>(strtod(s, nullptr));
6326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
6426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssentemplate<> inline double atot<double>(const char *s) {
6526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  return strtod(s, nullptr);
6626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
6726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
6826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssentemplate<> inline Offset<void> atot<Offset<void>>(const char *s) {
6926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  return Offset<void>(atoi(s));
7026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
7126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
7226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen// Declare tokens we'll use. Single character tokens are represented by their
7326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen// ascii character code (e.g. '{'), others above 256.
7426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen#define FLATBUFFERS_GEN_TOKENS(TD) \
7526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  TD(Eof, 256, "end of file") \
7626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  TD(StringConstant, 257, "string constant") \
7726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  TD(IntegerConstant, 258, "integer constant") \
7826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  TD(FloatConstant, 259, "float constant") \
7926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  TD(Identifier, 260, "identifier") \
8026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  TD(Table, 261, "table") \
8126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  TD(Struct, 262, "struct") \
8226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  TD(Enum, 263, "enum") \
8326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  TD(Union, 264, "union") \
8426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  TD(NameSpace, 265, "namespace") \
855da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen  TD(RootType, 266, "root_type") \
865da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen  TD(FileIdentifier, 267, "file_identifier") \
87be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen  TD(FileExtension, 268, "file_extension") \
88be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen  TD(Include, 269, "include")
898f80fecc445cb733615ad0186358d4e3789ab377Wouter van Oortmerssen#ifdef __GNUC__
908f80fecc445cb733615ad0186358d4e3789ab377Wouter van Oortmerssen__extension__  // Stop GCC complaining about trailing comma with -Wpendantic.
918f80fecc445cb733615ad0186358d4e3789ab377Wouter van Oortmerssen#endif
9226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenenum {
9375349ae8c39d01e7e2b5779a18ace750c08e2fd9Wouter van Oortmerssen  #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
9426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
9526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  #undef FLATBUFFERS_TOKEN
96557c88c0396220e79e9a43c07f8393a5c68b739dWouter van Oortmerssen  #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
97557c88c0396220e79e9a43c07f8393a5c68b739dWouter van Oortmerssen      kToken ## ENUM,
9826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
9926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  #undef FLATBUFFERS_TD
10026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen};
10126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
10226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenstatic std::string TokenToString(int t) {
10326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  static const char *tokens[] = {
10426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
10526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
10626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    #undef FLATBUFFERS_TOKEN
107557c88c0396220e79e9a43c07f8393a5c68b739dWouter van Oortmerssen    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) IDLTYPE,
10826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
10926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    #undef FLATBUFFERS_TD
11026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  };
11126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (t < 256) {  // A single ascii char token.
11226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    std::string s;
1138e40902d5284ac479baea5a8ba5eeb31c8edb1a9Wouter van Oortmerssen    s.append(1, static_cast<char>(t));
11426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    return s;
11526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  } else {       // Other tokens.
11626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    return tokens[t - 256];
11726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
11826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
11926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
120ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen// Parses exactly nibbles worth of hex digits into a number, or error.
121ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssenint64_t Parser::ParseHexNum(int nibbles) {
122ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen  for (int i = 0; i < nibbles; i++)
123ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen    if (!isxdigit(cursor_[i]))
124ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen      Error("escape code must be followed by " + NumToString(nibbles) +
125ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen            " hex digits");
126ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen  auto val = StringToInt(cursor_, 16);
127ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen  cursor_ += nibbles;
128ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen  return val;
129ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen}
130ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen
13126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenvoid Parser::Next() {
13226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  doc_comment_.clear();
13326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  bool seen_newline = false;
13426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  for (;;) {
13526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    char c = *cursor_++;
13626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    token_ = c;
13726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    switch (c) {
13826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      case '\0': cursor_--; token_ = kTokenEof; return;
13926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      case ' ': case '\r': case '\t': break;
14026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      case '\n': line_++; seen_newline = true; break;
14126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      case '{': case '}': case '(': case ')': case '[': case ']': return;
14226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      case ',': case ':': case ';': case '=': return;
14326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      case '.':
14426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        if(!isdigit(*cursor_)) return;
14526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        Error("floating point constant can\'t start with \".\"");
14626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        break;
14726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      case '\"':
14826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        attribute_ = "";
14926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        while (*cursor_ != '\"') {
15026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (*cursor_ < ' ' && *cursor_ >= 0)
15126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            Error("illegal character in string constant");
15226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (*cursor_ == '\\') {
15326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            cursor_++;
15426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            switch (*cursor_) {
15526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              case 'n':  attribute_ += '\n'; cursor_++; break;
15626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              case 't':  attribute_ += '\t'; cursor_++; break;
15726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              case 'r':  attribute_ += '\r'; cursor_++; break;
158ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen              case 'b':  attribute_ += '\b'; cursor_++; break;
159ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen              case 'f':  attribute_ += '\f'; cursor_++; break;
16026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              case '\"': attribute_ += '\"'; cursor_++; break;
16126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              case '\\': attribute_ += '\\'; cursor_++; break;
162ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen              case '/':  attribute_ += '/';  cursor_++; break;
163ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen              case 'x': {  // Not in the JSON standard
164ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen                cursor_++;
165ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen                attribute_ += static_cast<char>(ParseHexNum(2));
166ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen                break;
167ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen              }
168ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen              case 'u': {
169ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen                cursor_++;
170ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen                ToUTF8(static_cast<int>(ParseHexNum(4)), &attribute_);
171ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen                break;
172ebac1e1940b16e096e500ae95381706397d86feeWouter van Oortmerssen              }
17326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              default: Error("unknown escape code in string constant"); break;
17426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            }
17526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          } else { // printable chars + UTF-8 bytes
17626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            attribute_ += *cursor_++;
17726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          }
17826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        }
17926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        cursor_++;
18026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        token_ = kTokenStringConstant;
18126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        return;
18226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      case '/':
18326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        if (*cursor_ == '/') {
18426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          const char *start = ++cursor_;
18526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          while (*cursor_ && *cursor_ != '\n') cursor_++;
18626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (*start == '/') {  // documentation comment
18726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            if (!seen_newline)
18826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              Error("a documentation comment should be on a line on its own");
18926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            // todo: do we want to support multiline comments instead?
19026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            doc_comment_ += std::string(start + 1, cursor_);
19126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          }
19226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          break;
19326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        }
19426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        // fall thru
19526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      default:
19626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        if (isalpha(static_cast<unsigned char>(c))) {
19726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          // Collect all chars of an identifier:
19826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          const char *start = cursor_ - 1;
19926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          while (isalnum(static_cast<unsigned char>(*cursor_)) ||
20026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                 *cursor_ == '_')
20126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            cursor_++;
20226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          attribute_.clear();
20326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          attribute_.append(start, cursor_);
20426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          // First, see if it is a type keyword from the table of types:
205557c88c0396220e79e9a43c07f8393a5c68b739dWouter van Oortmerssen          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
20626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            if (attribute_ == IDLTYPE) { \
20726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              token_ = kToken ## ENUM; \
20826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              return; \
20926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            }
21026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
21126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          #undef FLATBUFFERS_TD
21226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          // If it's a boolean constant keyword, turn those into integers,
21326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          // which simplifies our logic downstream.
21426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (attribute_ == "true" || attribute_ == "false") {
21526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            attribute_ = NumToString(attribute_ == "true");
21626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            token_ = kTokenIntegerConstant;
21726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            return;
21826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          }
21926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          // Check for declaration keywords:
22026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (attribute_ == "table")     { token_ = kTokenTable;     return; }
22126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (attribute_ == "struct")    { token_ = kTokenStruct;    return; }
22226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (attribute_ == "enum")      { token_ = kTokenEnum;      return; }
22326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (attribute_ == "union")     { token_ = kTokenUnion;     return; }
22426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (attribute_ == "namespace") { token_ = kTokenNameSpace; return; }
22526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (attribute_ == "root_type") { token_ = kTokenRootType;  return; }
226be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen          if (attribute_ == "include")   { token_ = kTokenInclude;  return; }
2275da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen          if (attribute_ == "file_identifier") {
2285da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen            token_ = kTokenFileIdentifier;
2295da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen            return;
2305da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen          }
2315da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen          if (attribute_ == "file_extension") {
2325da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen            token_ = kTokenFileExtension;
2335da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen            return;
2345da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen          }
23526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          // If not, it is a user-defined identifier:
23626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          token_ = kTokenIdentifier;
23726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          return;
23826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        } else if (isdigit(static_cast<unsigned char>(c)) || c == '-') {
23926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          const char *start = cursor_ - 1;
24026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
24126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (*cursor_ == '.') {
24226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            cursor_++;
24326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
24493df5697a04e406929d7a3fa1f17904d2859e36dWouter van Oortmerssen            // See if this float has a scientific notation suffix. Both JSON
24593df5697a04e406929d7a3fa1f17904d2859e36dWouter van Oortmerssen            // and C++ (through strtod() we use) have the same format:
24693df5697a04e406929d7a3fa1f17904d2859e36dWouter van Oortmerssen            if (*cursor_ == 'e' || *cursor_ == 'E') {
24793df5697a04e406929d7a3fa1f17904d2859e36dWouter van Oortmerssen              cursor_++;
24893df5697a04e406929d7a3fa1f17904d2859e36dWouter van Oortmerssen              if (*cursor_ == '+' || *cursor_ == '-') cursor_++;
24993df5697a04e406929d7a3fa1f17904d2859e36dWouter van Oortmerssen              while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
25093df5697a04e406929d7a3fa1f17904d2859e36dWouter van Oortmerssen            }
25126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            token_ = kTokenFloatConstant;
25226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          } else {
25326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            token_ = kTokenIntegerConstant;
25426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          }
25526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          attribute_.clear();
25626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          attribute_.append(start, cursor_);
25726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          return;
25826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        }
25926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        std::string ch;
26026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        ch = c;
26126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        if (c < ' ' || c > '~') ch = "code: " + NumToString(c);
26226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        Error("illegal character: " + ch);
26326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        break;
26426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
26526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
26626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
26726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
26826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen// Check if a given token is next, if so, consume it as well.
26926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenbool Parser::IsNext(int t) {
27026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  bool isnext = t == token_;
27126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (isnext) Next();
27226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  return isnext;
27326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
27426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
27526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen// Expect a given token to be next, consume it, or error if not present.
27626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenvoid Parser::Expect(int t) {
27726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (t != token_) {
27826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Error("expecting: " + TokenToString(t) + " instead got: " +
27926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          TokenToString(token_));
28026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
28126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Next();
28226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
28326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
28426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen// Parse any IDL type.
28526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenvoid Parser::ParseType(Type &type) {
28626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (token_ >= kTokenBOOL && token_ <= kTokenSTRING) {
28726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    type.base_type = static_cast<BaseType>(token_ - kTokenNONE);
28826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  } else {
28926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    if (token_ == kTokenIdentifier) {
29026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      auto enum_def = enums_.Lookup(attribute_);
29126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      if (enum_def) {
29226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        type = enum_def->underlying_type;
29326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
29426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      } else {
29526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        type.base_type = BASE_TYPE_STRUCT;
29626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        type.struct_def = LookupCreateStruct(attribute_);
29726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      }
29826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    } else if (token_ == '[') {
29926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      Next();
30026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      Type subtype;
30126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      ParseType(subtype);
30226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      if (subtype.base_type == BASE_TYPE_VECTOR) {
30326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        // We could support this, but it will complicate things, and it's
30426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        // easier to work around with a struct around the inner vector.
30526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        Error("nested vector types not supported (wrap in table first).");
30626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      }
30726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      if (subtype.base_type == BASE_TYPE_UNION) {
30826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        // We could support this if we stored a struct of 2 elements per
30926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        // union element.
31026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        Error("vector of union types not supported (wrap in table first).");
31126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      }
3123fb6a86d020f7423553a4e2dbba637b56d7760f6Wouter van Oortmerssen      type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
31326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      type.element = subtype.base_type;
31426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      Expect(']');
31526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      return;
31626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    } else {
31726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      Error("illegal type syntax");
31826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
31926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
32026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Next();
32126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
32226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
32326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van OortmerssenFieldDef &Parser::AddField(StructDef &struct_def,
32426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                           const std::string &name,
32526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                           const Type &type) {
32626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  auto &field = *new FieldDef();
32726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  field.value.offset =
32826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size()));
32926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  field.name = name;
33026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  field.value.type = type;
33126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (struct_def.fixed) {  // statically compute the field offset
33226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    auto size = InlineSize(type);
33326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    auto alignment = InlineAlignment(type);
33426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    // structs_ need to have a predictable format, so we need to align to
33526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    // the largest scalar
33626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    struct_def.minalign = std::max(struct_def.minalign, alignment);
33726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    struct_def.PadLastField(alignment);
3381256307a388f05917b112253ef79e9b79ff76e1dWouter van Oortmerssen    field.value.offset = static_cast<voffset_t>(struct_def.bytesize);
33926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    struct_def.bytesize += size;
34026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
34126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (struct_def.fields.Add(name, &field))
34226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Error("field already exists: " + name);
34326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  return field;
34426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
34526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
34626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenvoid Parser::ParseField(StructDef &struct_def) {
34726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  std::string name = attribute_;
34826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  std::string dc = doc_comment_;
34926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Expect(kTokenIdentifier);
35026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Expect(':');
35126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Type type;
35226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  ParseType(type);
35326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
35426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type))
35526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Error("structs_ may contain only scalar or struct fields");
35626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
3579140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen  FieldDef *typefield = nullptr;
35826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (type.base_type == BASE_TYPE_UNION) {
35926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    // For union fields, add a second auto-generated field to hold the type,
36026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    // with _type appended as the name.
3619140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen    typefield = &AddField(struct_def, name + "_type",
3629140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen                          type.enum_def->underlying_type);
36326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
36426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
36526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  auto &field = AddField(struct_def, name, type);
36626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
36726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (token_ == '=') {
36826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Next();
36915dc1a86cd9e1fd22a46fde1a3632418eb8d9466Wouter van Oortmerssen    if (!IsScalar(type.base_type))
37015dc1a86cd9e1fd22a46fde1a3632418eb8d9466Wouter van Oortmerssen      Error("default values currently only supported for scalars");
37126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    ParseSingleValue(field.value);
37226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
37326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
37426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  field.doc_comment = dc;
37526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  ParseMetaData(field);
37626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  field.deprecated = field.attributes.Lookup("deprecated") != nullptr;
37726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (field.deprecated && struct_def.fixed)
37826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Error("can't deprecate fields in a struct");
3793e201a99b2f23c8c8475e43803d122b105db9a68Wouter van Oortmerssen  auto nested = field.attributes.Lookup("nested_flatbuffer");
3803e201a99b2f23c8c8475e43803d122b105db9a68Wouter van Oortmerssen  if (nested) {
3813e201a99b2f23c8c8475e43803d122b105db9a68Wouter van Oortmerssen    if (nested->type.base_type != BASE_TYPE_STRING)
3823e201a99b2f23c8c8475e43803d122b105db9a68Wouter van Oortmerssen      Error("nested_flatbuffer attribute must be a string (the root type)");
3833e201a99b2f23c8c8475e43803d122b105db9a68Wouter van Oortmerssen    if (field.value.type.base_type != BASE_TYPE_VECTOR ||
3843e201a99b2f23c8c8475e43803d122b105db9a68Wouter van Oortmerssen        field.value.type.element != BASE_TYPE_UCHAR)
3853e201a99b2f23c8c8475e43803d122b105db9a68Wouter van Oortmerssen      Error("nested_flatbuffer attribute may only apply to a vector of ubyte");
3863e201a99b2f23c8c8475e43803d122b105db9a68Wouter van Oortmerssen    // This will cause an error if the root type of the nested flatbuffer
3873e201a99b2f23c8c8475e43803d122b105db9a68Wouter van Oortmerssen    // wasn't defined elsewhere.
3883e201a99b2f23c8c8475e43803d122b105db9a68Wouter van Oortmerssen    LookupCreateStruct(nested->constant);
3893e201a99b2f23c8c8475e43803d122b105db9a68Wouter van Oortmerssen  }
39026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
3919140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen  if (typefield) {
3929140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen    // If this field is a union, and it has a manually assigned id,
3939140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen    // the automatically added type field should have an id as well (of N - 1).
3949140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen    auto attr = field.attributes.Lookup("id");
3959140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen    if (attr) {
3969140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      auto id = atoi(attr->constant.c_str());
3979140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      auto val = new Value();
3989140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      val->type = attr->type;
3999140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      val->constant = NumToString(id - 1);
4009140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      typefield->attributes.Add("id", val);
4019140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen    }
4029140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen  }
4039140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen
40426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Expect(';');
40526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
40626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
40726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenvoid Parser::ParseAnyValue(Value &val, FieldDef *field) {
40826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  switch (val.type.base_type) {
40926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    case BASE_TYPE_UNION: {
41026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      assert(field);
41126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      if (!field_stack_.size() ||
41226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          field_stack_.back().second->value.type.base_type != BASE_TYPE_UTYPE)
41326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        Error("missing type field before this union value: " + field->name);
41426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      auto enum_idx = atot<unsigned char>(
41526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                                    field_stack_.back().first.constant.c_str());
4163fb6a86d020f7423553a4e2dbba637b56d7760f6Wouter van Oortmerssen      auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
4173fb6a86d020f7423553a4e2dbba637b56d7760f6Wouter van Oortmerssen      if (!enum_val) Error("illegal type id for: " + field->name);
4183fb6a86d020f7423553a4e2dbba637b56d7760f6Wouter van Oortmerssen      val.constant = NumToString(ParseTable(*enum_val->struct_def));
41926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      break;
42026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
42126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    case BASE_TYPE_STRUCT:
42226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      val.constant = NumToString(ParseTable(*val.type.struct_def));
42326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      break;
42426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    case BASE_TYPE_STRING: {
42526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      auto s = attribute_;
42626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      Expect(kTokenStringConstant);
42726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      val.constant = NumToString(builder_.CreateString(s).o);
42826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      break;
42926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
43026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    case BASE_TYPE_VECTOR: {
43126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      Expect('[');
43226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      val.constant = NumToString(ParseVector(val.type.VectorType()));
43326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      break;
43426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
43526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    default:
43626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      ParseSingleValue(val);
43726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      break;
43826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
43926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
44026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
44126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenvoid Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
44226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  auto off = atot<uoffset_t>(val.constant.c_str());
44326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  assert(struct_stack_.size() - off == struct_def.bytesize);
44426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  builder_.Align(struct_def.minalign);
44526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  builder_.PushBytes(&struct_stack_[off], struct_def.bytesize);
44626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  struct_stack_.resize(struct_stack_.size() - struct_def.bytesize);
44726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  builder_.AddStructOffset(val.offset, builder_.GetSize());
44826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
44926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
45026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenuoffset_t Parser::ParseTable(const StructDef &struct_def) {
45126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Expect('{');
45226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  size_t fieldn = 0;
4530b47e69d4d6cb6905388f28760a6a90e96380a82Wouter van Oortmerssen  if (!IsNext('}')) for (;;) {
45426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    std::string name = attribute_;
45526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    if (!IsNext(kTokenStringConstant)) Expect(kTokenIdentifier);
45626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    auto field = struct_def.fields.Lookup(name);
45726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    if (!field) Error("unknown field: " + name);
45826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    if (struct_def.fixed && (fieldn >= struct_def.fields.vec.size()
45926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                            || struct_def.fields.vec[fieldn] != field)) {
46026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen       Error("struct field appearing out of order: " + name);
46126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
46226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Expect(':');
46326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Value val = field->value;
46426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    ParseAnyValue(val, field);
46526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    field_stack_.push_back(std::make_pair(val, field));
46626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    fieldn++;
46726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    if (IsNext('}')) break;
46826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Expect(',');
46926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
47011f25386100ce50e114ec52d5487027af2912ebfWouter van Oortmerssen  for (auto it = field_stack_.rbegin();
47111f25386100ce50e114ec52d5487027af2912ebfWouter van Oortmerssen           it != field_stack_.rbegin() + fieldn; ++it) {
47211f25386100ce50e114ec52d5487027af2912ebfWouter van Oortmerssen    if (it->second->used)
47311f25386100ce50e114ec52d5487027af2912ebfWouter van Oortmerssen      Error("field set more than once: " + it->second->name);
47411f25386100ce50e114ec52d5487027af2912ebfWouter van Oortmerssen    it->second->used = true;
47511f25386100ce50e114ec52d5487027af2912ebfWouter van Oortmerssen  }
47611f25386100ce50e114ec52d5487027af2912ebfWouter van Oortmerssen  for (auto it = field_stack_.rbegin();
47711f25386100ce50e114ec52d5487027af2912ebfWouter van Oortmerssen           it != field_stack_.rbegin() + fieldn; ++it) {
47811f25386100ce50e114ec52d5487027af2912ebfWouter van Oortmerssen    it->second->used = false;
47911f25386100ce50e114ec52d5487027af2912ebfWouter van Oortmerssen  }
48026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (struct_def.fixed && fieldn != struct_def.fields.vec.size())
48126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Error("incomplete struct initialization: " + struct_def.name);
48226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  auto start = struct_def.fixed
48326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                 ? builder_.StartStruct(struct_def.minalign)
48426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                 : builder_.StartTable();
48526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
48626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
48726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen       size;
48826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen       size /= 2) {
48926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    // Go through elements in reverse, since we're building the data backwards.
49026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    for (auto it = field_stack_.rbegin();
49126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen             it != field_stack_.rbegin() + fieldn; ++it) {
49226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      auto &value = it->first;
49326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      auto field = it->second;
49426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      if (!struct_def.sortbysize || size == SizeOf(value.type.base_type)) {
49526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        switch (value.type.base_type) {
496557c88c0396220e79e9a43c07f8393a5c68b739dWouter van Oortmerssen          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
49726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            case BASE_TYPE_ ## ENUM: \
49826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              builder_.Pad(field->padding); \
499be3c8742585326447a6f9e776ad90a6b0fceb953Wouter van Oortmerssen              if (struct_def.fixed) { \
500be3c8742585326447a6f9e776ad90a6b0fceb953Wouter van Oortmerssen                builder_.PushElement(atot<CTYPE>(value.constant.c_str())); \
501be3c8742585326447a6f9e776ad90a6b0fceb953Wouter van Oortmerssen              } else { \
502be3c8742585326447a6f9e776ad90a6b0fceb953Wouter van Oortmerssen                builder_.AddElement(value.offset, \
50326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                             atot<CTYPE>(       value.constant.c_str()), \
50426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                             atot<CTYPE>(field->value.constant.c_str())); \
505be3c8742585326447a6f9e776ad90a6b0fceb953Wouter van Oortmerssen              } \
50626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              break;
50726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
50826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          #undef FLATBUFFERS_TD
509557c88c0396220e79e9a43c07f8393a5c68b739dWouter van Oortmerssen          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
51026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            case BASE_TYPE_ ## ENUM: \
51126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              builder_.Pad(field->padding); \
51226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              if (IsStruct(field->value.type)) { \
51326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                SerializeStruct(*field->value.type.struct_def, value); \
51426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              } else { \
51526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                builder_.AddOffset(value.offset, \
51626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                  atot<CTYPE>(value.constant.c_str())); \
51726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              } \
51826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              break;
51926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD);
52026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          #undef FLATBUFFERS_TD
52126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        }
52226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      }
52326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
52426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
52526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  for (size_t i = 0; i < fieldn; i++) field_stack_.pop_back();
52626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
52726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (struct_def.fixed) {
52826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    builder_.ClearOffsets();
52926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    builder_.EndStruct();
53026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    // Temporarily store this struct in a side buffer, since this data has to
53126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    // be stored in-line later in the parent object.
53226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    auto off = struct_stack_.size();
53326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    struct_stack_.insert(struct_stack_.end(),
53426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                         builder_.GetBufferPointer(),
53526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                         builder_.GetBufferPointer() + struct_def.bytesize);
53626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    builder_.PopBytes(struct_def.bytesize);
53726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    return static_cast<uoffset_t>(off);
53826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  } else {
53926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    return builder_.EndTable(
54026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      start,
54126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      static_cast<voffset_t>(struct_def.fields.vec.size()));
54226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
54326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
54426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
54526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenuoffset_t Parser::ParseVector(const Type &type) {
54626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  int count = 0;
54726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (token_ != ']') for (;;) {
54826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Value val;
54926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    val.type = type;
55026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    ParseAnyValue(val, NULL);
55126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    field_stack_.push_back(std::make_pair(val, nullptr));
55226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    count++;
55326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    if (token_ == ']') break;
55426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Expect(',');
55526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
55626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Next();
55726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
558be3c8742585326447a6f9e776ad90a6b0fceb953Wouter van Oortmerssen  builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
559be3c8742585326447a6f9e776ad90a6b0fceb953Wouter van Oortmerssen                       InlineAlignment(type));
56026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  for (int i = 0; i < count; i++) {
56126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    // start at the back, since we're building the data backwards.
56226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    auto &val = field_stack_.back().first;
56326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    switch (val.type.base_type) {
564557c88c0396220e79e9a43c07f8393a5c68b739dWouter van Oortmerssen      #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
56526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        case BASE_TYPE_ ## ENUM: \
56626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
56726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          else builder_.PushElement(atot<CTYPE>(val.constant.c_str())); \
56826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          break;
56926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
57026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      #undef FLATBUFFERS_TD
57126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
57226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    field_stack_.pop_back();
57326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
57426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
57526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  builder_.ClearOffsets();
57626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  return builder_.EndVector(count);
57726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
57826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
57926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenvoid Parser::ParseMetaData(Definition &def) {
58026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (IsNext('(')) {
58126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    for (;;) {
58226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      auto name = attribute_;
58326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      Expect(kTokenIdentifier);
58426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      auto e = new Value();
58526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      def.attributes.Add(name, e);
58626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      if (IsNext(':')) {
58726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        ParseSingleValue(*e);
58826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      }
58926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      if (IsNext(')')) break;
59026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      Expect(',');
59126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
59226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
59326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
59426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
59526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenbool Parser::TryTypedValue(int dtoken,
59626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                           bool check,
59726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                           Value &e,
59826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                           BaseType req) {
59926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  bool match = dtoken == token_;
60026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (match) {
60126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    e.constant = attribute_;
60226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    if (!check) {
60326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      if (e.type.base_type == BASE_TYPE_NONE) {
60426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        e.type.base_type = req;
60526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      } else {
60626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        Error(std::string("type mismatch: expecting: ") +
60726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              kTypeNames[e.type.base_type] +
60826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              ", found: " +
60926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen              kTypeNames[req]);
61026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      }
61126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
61226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Next();
61326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
61426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  return match;
61526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
61626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
6179c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssenint64_t Parser::ParseIntegerFromString(Type &type) {
6189c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen  int64_t result = 0;
6199c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen  // Parse one or more enum identifiers, separated by spaces.
6209c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen  const char *next = attribute_.c_str();
6219c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen  do {
6229c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen    const char *divider = strchr(next, ' ');
6239c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen    std::string word;
6249c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen    if (divider) {
6259c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      word = std::string(next, divider);
6269c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      next = divider + strspn(divider, " ");
6279c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen    } else {
6289c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      word = next;
6299c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      next += word.length();
6309c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen    }
6319c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen    if (type.enum_def) {  // The field has an enum type
6329c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      auto enum_val = type.enum_def->vals.Lookup(word);
6339c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      if (!enum_val)
6349c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen        Error("unknown enum value: " + word +
6359c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen              ", for enum: " + type.enum_def->name);
6369c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      result |= enum_val->value;
6379c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen    } else {  // No enum type, probably integral field.
6389c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      if (!IsInteger(type.base_type))
6399c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen        Error("not a valid value for this field: " + word);
6409c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      // TODO: could check if its a valid number constant here.
6419c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      const char *dot = strchr(word.c_str(), '.');
6429c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      if (!dot) Error("enum values need to be qualified by an enum type");
6439c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      std::string enum_def_str(word.c_str(), dot);
6449c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      std::string enum_val_str(dot + 1, word.c_str() + word.length());
6459c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      auto enum_def = enums_.Lookup(enum_def_str);
6469c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      if (!enum_def) Error("unknown enum: " + enum_def_str);
6479c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      auto enum_val = enum_def->vals.Lookup(enum_val_str);
6489c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      if (!enum_val) Error("unknown enum value: " + enum_val_str);
6499c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      result |= enum_val->value;
6509c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen    }
6519c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen  } while(*next);
6529c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen  return result;
6539c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen}
6549c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen
65526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenvoid Parser::ParseSingleValue(Value &e) {
6569c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen  // First check if this could be a string/identifier enum value:
6579c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen  if (e.type.base_type != BASE_TYPE_STRING &&
6589c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      e.type.base_type != BASE_TYPE_NONE &&
6599c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
6609c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      e.constant = NumToString(ParseIntegerFromString(e.type));
6619c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      Next();
6623fb6a86d020f7423553a4e2dbba637b56d7760f6Wouter van Oortmerssen  } else if (TryTypedValue(kTokenIntegerConstant,
66326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                    IsScalar(e.type.base_type),
66426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                    e,
66526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                    BASE_TYPE_INT) ||
66626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      TryTypedValue(kTokenFloatConstant,
66726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                    IsFloat(e.type.base_type),
66826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                    e,
66926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                    BASE_TYPE_FLOAT) ||
67026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      TryTypedValue(kTokenStringConstant,
67126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                    e.type.base_type == BASE_TYPE_STRING,
67226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                    e,
67326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen                    BASE_TYPE_STRING)) {
67426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  } else {
67526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Error("cannot parse value starting with: " + TokenToString(token_));
67626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
67726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
67826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
67926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van OortmerssenStructDef *Parser::LookupCreateStruct(const std::string &name) {
68026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  auto struct_def = structs_.Lookup(name);
68126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (!struct_def) {
68226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    // Rather than failing, we create a "pre declared" StructDef, due to
68326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    // circular references, and check for errors at the end of parsing.
68426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    struct_def = new StructDef();
68526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    structs_.Add(name, struct_def);
68626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    struct_def->name = name;
68726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    struct_def->predecl = true;
688c2ba7fd251b9da9fd2f0210818cc0221682f29c4Wouter van Oortmerssen    struct_def->defined_namespace = namespaces_.back();
68926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
69026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  return struct_def;
69126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
69226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
69326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenvoid Parser::ParseEnum(bool is_union) {
69426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  std::string dc = doc_comment_;
69526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Next();
69626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  std::string name = attribute_;
69726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Expect(kTokenIdentifier);
69826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  auto &enum_def = *new EnumDef();
69926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  enum_def.name = name;
70026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  enum_def.doc_comment = dc;
70126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  enum_def.is_union = is_union;
70226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (enums_.Add(name, &enum_def)) Error("enum already exists: " + name);
70326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (is_union) {
70426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    enum_def.underlying_type.base_type = BASE_TYPE_UTYPE;
70526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    enum_def.underlying_type.enum_def = &enum_def;
706a5f50019bc979c352bb7e0c08b8bbfd8ab06af4dWouter van Oortmerssen  } else {
707a5f50019bc979c352bb7e0c08b8bbfd8ab06af4dWouter van Oortmerssen    // Give specialized error message, since this type spec used to
708a5f50019bc979c352bb7e0c08b8bbfd8ab06af4dWouter van Oortmerssen    // be optional in the first FlatBuffers release.
709a5f50019bc979c352bb7e0c08b8bbfd8ab06af4dWouter van Oortmerssen    if (!IsNext(':')) Error("must specify the underlying integer type for this"
710a5f50019bc979c352bb7e0c08b8bbfd8ab06af4dWouter van Oortmerssen                            " enum (e.g. \': short\', which was the default).");
711a5f50019bc979c352bb7e0c08b8bbfd8ab06af4dWouter van Oortmerssen    // Specify the integer type underlying this enum.
71226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    ParseType(enum_def.underlying_type);
71326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    if (!IsInteger(enum_def.underlying_type.base_type))
71426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      Error("underlying enum type must be integral");
7153fb6a86d020f7423553a4e2dbba637b56d7760f6Wouter van Oortmerssen    // Make this type refer back to the enum it was derived from.
7163fb6a86d020f7423553a4e2dbba637b56d7760f6Wouter van Oortmerssen    enum_def.underlying_type.enum_def = &enum_def;
71726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
71826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  ParseMetaData(enum_def);
71926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Expect('{');
72026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (is_union) enum_def.vals.Add("NONE", new EnumVal("NONE", 0));
72126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  do {
72226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    std::string name = attribute_;
72326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    std::string dc = doc_comment_;
72426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Expect(kTokenIdentifier);
72526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    auto prevsize = enum_def.vals.vec.size();
726127d35085a22cb33034f608ee21d65a655d1582cWouter van Oortmerssen    auto value = enum_def.vals.vec.size()
727127d35085a22cb33034f608ee21d65a655d1582cWouter van Oortmerssen      ? enum_def.vals.vec.back()->value + 1
728127d35085a22cb33034f608ee21d65a655d1582cWouter van Oortmerssen      : 0;
729127d35085a22cb33034f608ee21d65a655d1582cWouter van Oortmerssen    auto &ev = *new EnumVal(name, value);
73026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    if (enum_def.vals.Add(name, &ev))
73126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      Error("enum value already exists: " + name);
73226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    ev.doc_comment = dc;
73326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    if (is_union) {
73426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      ev.struct_def = LookupCreateStruct(name);
73526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
73626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    if (IsNext('=')) {
73726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      ev.value = atoi(attribute_.c_str());
73826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      Expect(kTokenIntegerConstant);
73926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      if (prevsize && enum_def.vals.vec[prevsize - 1]->value >= ev.value)
74026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        Error("enum values must be specified in ascending order");
74126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
742c553b6b950870b299b40e0153818430c649b76cfWouter van Oortmerssen  } while (IsNext(',') && token_ != '}');
74326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Expect('}');
744127d35085a22cb33034f608ee21d65a655d1582cWouter van Oortmerssen  if (enum_def.attributes.Lookup("bit_flags")) {
745127d35085a22cb33034f608ee21d65a655d1582cWouter van Oortmerssen    for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
746127d35085a22cb33034f608ee21d65a655d1582cWouter van Oortmerssen         ++it) {
747127d35085a22cb33034f608ee21d65a655d1582cWouter van Oortmerssen      if (static_cast<size_t>((*it)->value) >=
748127d35085a22cb33034f608ee21d65a655d1582cWouter van Oortmerssen           SizeOf(enum_def.underlying_type.base_type) * 8)
749127d35085a22cb33034f608ee21d65a655d1582cWouter van Oortmerssen        Error("bit flag out of range of underlying integral type");
7509c3de1e2a0591c2526453cf85260c09e3c624189Wouter van Oortmerssen      (*it)->value = 1LL << (*it)->value;
751127d35085a22cb33034f608ee21d65a655d1582cWouter van Oortmerssen    }
752127d35085a22cb33034f608ee21d65a655d1582cWouter van Oortmerssen  }
75326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
75426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
75526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenvoid Parser::ParseDecl() {
75626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  std::string dc = doc_comment_;
75726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  bool fixed = IsNext(kTokenStruct);
75826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (!fixed) Expect(kTokenTable);
75926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  std::string name = attribute_;
76026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Expect(kTokenIdentifier);
76126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  auto &struct_def = *LookupCreateStruct(name);
76226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (!struct_def.predecl) Error("datatype already exists: " + name);
76326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  struct_def.predecl = false;
76426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  struct_def.name = name;
76526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  struct_def.doc_comment = dc;
76626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  struct_def.fixed = fixed;
76726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  // Move this struct to the back of the vector just in case it was predeclared,
76826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  // to preserve declartion order.
76926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  remove(structs_.vec.begin(), structs_.vec.end(), &struct_def);
77026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  structs_.vec.back() = &struct_def;
77126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  ParseMetaData(struct_def);
77226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  struct_def.sortbysize =
77326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    struct_def.attributes.Lookup("original_order") == nullptr && !fixed;
77426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  Expect('{');
77526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  while (token_ != '}') ParseField(struct_def);
77626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  auto force_align = struct_def.attributes.Lookup("force_align");
77726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  if (fixed && force_align) {
77826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
77926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    if (force_align->type.base_type != BASE_TYPE_INT ||
78026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        align < struct_def.minalign ||
78126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        align > 256 ||
78226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        align & (align - 1))
78326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      Error("force_align must be a power of two integer ranging from the"
78426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            "struct\'s natural alignment to 256");
78526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    struct_def.minalign = align;
78626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
78765cfa18855abc712faa1bf0cb5c3b88ab8df4b28Wouter van Oortmerssen  struct_def.PadLastField(struct_def.minalign);
7889140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen  // Check if this is a table that has manual id assignments
7899140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen  auto &fields = struct_def.fields.vec;
7909140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen  if (!struct_def.fixed && fields.size()) {
7917fcbe723fc821785abfec0348023d9ebf5b4db96Wouter van Oortmerssen    size_t num_id_fields = 0;
7929140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen    for (auto it = fields.begin(); it != fields.end(); ++it) {
7939140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      if ((*it)->attributes.Lookup("id")) num_id_fields++;
7949140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen    }
7959140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen    // If any fields have ids..
7969140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen    if (num_id_fields) {
7979140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      // Then all fields must have them.
7989140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      if (num_id_fields != fields.size())
7999140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen        Error("either all fields or no fields must have an 'id' attribute");
8009140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      // Simply sort by id, then the fields are the same as if no ids had
8019140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      // been specified.
8029140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      std::sort(fields.begin(), fields.end(),
8039140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen        [](const FieldDef *a, const FieldDef *b) -> bool {
8049140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen          auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
8059140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen          auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
8069140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen          return a_id < b_id;
8079140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      });
8089140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      // Verify we have a contiguous set, and reassign vtable offsets.
8099140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      for (int i = 0; i < static_cast<int>(fields.size()); i++) {
8109140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen        if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str()))
8119140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen          Error("field id\'s must be consecutive from 0, id " +
8129140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen                NumToString(i) + " missing or set twice");
8139140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen        fields[i]->value.offset = FieldIndexToOffset(static_cast<voffset_t>(i));
8149140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen      }
8159140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen    }
8169140144d5161124623a27cf8b8038f6e7c9bb74dWouter van Oortmerssen  }
817541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen  // Check that no identifiers clash with auto generated fields.
818541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen  // This is not an ideal situation, but should occur very infrequently,
819541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen  // and allows us to keep using very readable names for type & length fields
820541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen  // without inducing compile errors.
821541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen  auto CheckClash = [&fields, &struct_def](const char *suffix,
822541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen                                           BaseType basetype) {
823541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen    auto len = strlen(suffix);
824541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen    for (auto it = fields.begin(); it != fields.end(); ++it) {
825541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen      auto &name = (*it)->name;
826541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen      if (name.length() > len &&
827541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen          name.compare(name.length() - len, len, suffix) == 0 &&
828541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen          (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
829541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen        auto field = struct_def.fields.Lookup(
830541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen                       name.substr(0, name.length() - len));
831541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen        if (field && field->value.type.base_type == basetype)
832541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen          Error("Field " + name +
833541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen                " would clash with generated functions for field " +
834541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen                field->name);
835541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen      }
836541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen    }
837541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen  };
838541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen  CheckClash("_type", BASE_TYPE_UNION);
839541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen  CheckClash("Type", BASE_TYPE_UNION);
840541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen  CheckClash("_length", BASE_TYPE_VECTOR);
841541b06759f72dcff9008478da797957e6fbabb45Wouter van Oortmerssen  CheckClash("Length", BASE_TYPE_VECTOR);
84265cfa18855abc712faa1bf0cb5c3b88ab8df4b28Wouter van Oortmerssen  Expect('}');
84326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
84426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
84526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssenbool Parser::SetRootType(const char *name) {
84626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  root_struct_def = structs_.Lookup(name);
84726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  return root_struct_def != nullptr;
84826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
84926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
850be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssenvoid Parser::MarkGenerated() {
851be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen  // Since the Parser object retains definitions across files, we must
852be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen  // ensure we only output code for definitions once, in the file they are first
853be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen  // declared. This function marks all existing definitions as having already
854be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen  // been generated.
855be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen  for (auto it = enums_.vec.begin();
856be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen           it != enums_.vec.end(); ++it) {
857be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen    (*it)->generated = true;
858be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen  }
859be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen  for (auto it = structs_.vec.begin();
860be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen           it != structs_.vec.end(); ++it) {
861be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen    (*it)->generated = true;
862be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen  }
863be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen}
864be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen
865e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssenbool Parser::Parse(const char *source, const char **include_paths) {
86626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  source_ = cursor_ = source;
86726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  line_ = 1;
86826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  error_.clear();
86926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  builder_.Clear();
87026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  try {
87126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    Next();
872be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen    // Includes must come first:
873be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen    while (IsNext(kTokenInclude)) {
874be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen      auto name = attribute_;
875be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen      Expect(kTokenStringConstant);
876be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen      if (included_files_.find(name) == included_files_.end()) {
877be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen        // We found an include file that we have not parsed yet.
878be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen        // Load it and parse it.
879be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen        std::string contents;
880e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen        if (!include_paths) {
881e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen          const char *current_directory[] = { "", nullptr };
882e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen          include_paths = current_directory;
883e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen        }
884e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen        for (auto paths = include_paths; paths && *paths; paths++) {
885e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen          auto filepath = flatbuffers::ConCatPathFileName(*paths, name);
886e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen          if(LoadFile(filepath.c_str(), true, &contents)) break;
887e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen        }
888e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen        if (contents.empty())
889be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen          Error("unable to load include file: " + name);
890e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen        included_files_[name] = true;
891e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen        if (!Parse(contents.c_str(), include_paths)) {
892e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen          // Any errors, we're done.
893e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen          return false;
894e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen        }
895be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen        // We do not want to output code for any included files:
896be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen        MarkGenerated();
897be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen        // This is the easiest way to continue this file after an include:
898be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen        // instead of saving and restoring all the state, we simply start the
899be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen        // file anew. This will cause it to encounter the same include statement
900be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen        // again, but this time it will skip it, because it was entered into
901be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen        // included_files_.
902e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen        // This is recursive, but only go as deep as the number of include
903e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen        // statements.
904e57b86bb9f17cabc5bf5b4afe78153dde55f46eaWouter van Oortmerssen        return Parse(source, include_paths);
905be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen      }
906be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen      Expect(';');
907be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen    }
908be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen    // Now parse all other kinds of declarations:
90926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    while (token_ != kTokenEof) {
91026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      if (token_ == kTokenNameSpace) {
91126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        Next();
912c2ba7fd251b9da9fd2f0210818cc0221682f29c4Wouter van Oortmerssen        auto ns = new Namespace();
913c2ba7fd251b9da9fd2f0210818cc0221682f29c4Wouter van Oortmerssen        namespaces_.push_back(ns);
91426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        for (;;) {
915c2ba7fd251b9da9fd2f0210818cc0221682f29c4Wouter van Oortmerssen          ns->components.push_back(attribute_);
91626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          Expect(kTokenIdentifier);
91726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (!IsNext('.')) break;
91826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        }
91926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        Expect(';');
92026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      } else if (token_ == '{') {
92126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        if (!root_struct_def) Error("no root type set to parse json with");
92226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        if (builder_.GetSize()) {
92326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          Error("cannot have more than one json object in a file");
92426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        }
92509a2999c66abc92e5c33fdef75c63dec81f90a3aWouter van Oortmerssen        builder_.Finish(Offset<Table>(ParseTable(*root_struct_def)),
92609a2999c66abc92e5c33fdef75c63dec81f90a3aWouter van Oortmerssen          file_identifier_.length() ? file_identifier_.c_str() : nullptr);
92726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      } else if (token_ == kTokenEnum) {
92826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        ParseEnum(false);
92926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      } else if (token_ == kTokenUnion) {
93026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        ParseEnum(true);
93126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      } else if (token_ == kTokenRootType) {
93226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        Next();
93326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        auto root_type = attribute_;
93426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        Expect(kTokenIdentifier);
93526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        if (!SetRootType(root_type.c_str()))
93626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          Error("unknown root type: " + root_type);
93726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        if (root_struct_def->fixed)
93826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          Error("root type must be a table");
9395da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen        Expect(';');
9405da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen      } else if (token_ == kTokenFileIdentifier) {
9415da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen        Next();
9425da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen        file_identifier_ = attribute_;
9435da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen        Expect(kTokenStringConstant);
9445da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen        if (file_identifier_.length() !=
9455da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen            FlatBufferBuilder::kFileIdentifierLength)
9465da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen          Error("file_identifier must be exactly " +
9475da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen                NumToString(FlatBufferBuilder::kFileIdentifierLength) +
9485da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen                " characters");
9495da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen        Expect(';');
9505da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen      } else if (token_ == kTokenFileExtension) {
9515da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen        Next();
9525da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen        file_extension_ = attribute_;
9535da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen        Expect(kTokenStringConstant);
9545da7bda826a98fa92eb1356907afa631bfa9c1b1Wouter van Oortmerssen        Expect(';');
955be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen      } else if(token_ == kTokenInclude) {
956be894f09df2383844d6c19b1d173fec105451e0fWouter van Oortmerssen        Error("includes must come before declarations");
95726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      } else {
95826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        ParseDecl();
95926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      }
96026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
96126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
96226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      if ((*it)->predecl)
96326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        Error("type referenced but not defined: " + (*it)->name);
96426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
96526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
96626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      auto &enum_def = **it;
96726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      if (enum_def.is_union) {
96826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        for (auto it = enum_def.vals.vec.begin();
96926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen             it != enum_def.vals.vec.end();
97026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen             ++it) {
97126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          auto &val = **it;
97226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen          if (val.struct_def && val.struct_def->fixed)
97326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen            Error("only tables can be union elements: " + val.name);
97426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen        }
97526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen      }
97626a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    }
97726a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  } catch (const std::string &msg) {
97826a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    error_ = "line " + NumToString(line_) + ": " + msg;
97926a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen    return false;
98026a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  }
98126a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  assert(!struct_stack_.size());
98226a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen  return true;
98326a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}
98426a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen
98526a30738a4fa4e92300821fd761764ec8df2dcf2Wouter van Oortmerssen}  // namespace flatbuffers
986