idl_parser.cpp revision 127d35085a22cb33034f608ee21d65a655d1582c
1/*
2 * Copyright 2014 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <algorithm>
18
19#include "flatbuffers/flatbuffers.h"
20#include "flatbuffers/idl.h"
21#include "flatbuffers/util.h"
22
23namespace flatbuffers {
24
25const char *const kTypeNames[] = {
26  #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE) IDLTYPE,
27    FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
28  #undef FLATBUFFERS_TD
29  nullptr
30};
31
32const char kTypeSizes[] = {
33  #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE) sizeof(CTYPE),
34    FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
35  #undef FLATBUFFERS_TD
36};
37
38static void Error(const std::string &msg) {
39  throw msg;
40}
41
42// Ensure that integer values we parse fit inside the declared integer type.
43static void CheckBitsFit(int64_t val, size_t bits) {
44  auto mask = (1ll << bits) - 1;  // Bits we allow to be used.
45  if (bits < 64 &&
46      (val & ~mask) != 0 &&  // Positive or unsigned.
47      (val |  mask) != -1)   // Negative.
48    Error("constant does not fit in a " + NumToString(bits) + "-bit field");
49}
50
51// atot: templated version of atoi/atof: convert a string to an instance of T.
52template<typename T> inline T atot(const char *s) {
53  auto val = StringToInt(s);
54  CheckBitsFit(val, sizeof(T) * 8);
55  return (T)val;
56}
57template<> inline bool atot<bool>(const char *s) {
58  return 0 != atoi(s);
59}
60template<> inline float atot<float>(const char *s) {
61  return static_cast<float>(strtod(s, nullptr));
62}
63template<> inline double atot<double>(const char *s) {
64  return strtod(s, nullptr);
65}
66
67template<> inline Offset<void> atot<Offset<void>>(const char *s) {
68  return Offset<void>(atoi(s));
69}
70
71// Declare tokens we'll use. Single character tokens are represented by their
72// ascii character code (e.g. '{'), others above 256.
73#define FLATBUFFERS_GEN_TOKENS(TD) \
74  TD(Eof, 256, "end of file") \
75  TD(StringConstant, 257, "string constant") \
76  TD(IntegerConstant, 258, "integer constant") \
77  TD(FloatConstant, 259, "float constant") \
78  TD(Identifier, 260, "identifier") \
79  TD(Table, 261, "table") \
80  TD(Struct, 262, "struct") \
81  TD(Enum, 263, "enum") \
82  TD(Union, 264, "union") \
83  TD(NameSpace, 265, "namespace") \
84  TD(RootType, 266, "root_type")
85enum {
86  #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
87    FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
88  #undef FLATBUFFERS_TOKEN
89  #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE) kToken ## ENUM,
90    FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
91  #undef FLATBUFFERS_TD
92};
93
94static std::string TokenToString(int t) {
95  static const char *tokens[] = {
96    #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
97      FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
98    #undef FLATBUFFERS_TOKEN
99    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE) IDLTYPE,
100      FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
101    #undef FLATBUFFERS_TD
102  };
103  if (t < 256) {  // A single ascii char token.
104    std::string s;
105    s.append(1, t);
106    return s;
107  } else {       // Other tokens.
108    return tokens[t - 256];
109  }
110}
111
112void Parser::Next() {
113  doc_comment_.clear();
114  bool seen_newline = false;
115  for (;;) {
116    char c = *cursor_++;
117    token_ = c;
118    switch (c) {
119      case '\0': cursor_--; token_ = kTokenEof; return;
120      case ' ': case '\r': case '\t': break;
121      case '\n': line_++; seen_newline = true; break;
122      case '{': case '}': case '(': case ')': case '[': case ']': return;
123      case ',': case ':': case ';': case '=': return;
124      case '.':
125        if(!isdigit(*cursor_)) return;
126        Error("floating point constant can\'t start with \".\"");
127        break;
128      case '\"':
129        attribute_ = "";
130        while (*cursor_ != '\"') {
131          if (*cursor_ < ' ' && *cursor_ >= 0)
132            Error("illegal character in string constant");
133          if (*cursor_ == '\\') {
134            cursor_++;
135            switch (*cursor_) {
136              case 'n':  attribute_ += '\n'; cursor_++; break;
137              case 't':  attribute_ += '\t'; cursor_++; break;
138              case 'r':  attribute_ += '\r'; cursor_++; break;
139              case '\"': attribute_ += '\"'; cursor_++; break;
140              case '\\': attribute_ += '\\'; cursor_++; break;
141              default: Error("unknown escape code in string constant"); break;
142            }
143          } else { // printable chars + UTF-8 bytes
144            attribute_ += *cursor_++;
145          }
146        }
147        cursor_++;
148        token_ = kTokenStringConstant;
149        return;
150      case '/':
151        if (*cursor_ == '/') {
152          const char *start = ++cursor_;
153          while (*cursor_ && *cursor_ != '\n') cursor_++;
154          if (*start == '/') {  // documentation comment
155            if (!seen_newline)
156              Error("a documentation comment should be on a line on its own");
157            // todo: do we want to support multiline comments instead?
158            doc_comment_ += std::string(start + 1, cursor_);
159          }
160          break;
161        }
162        // fall thru
163      default:
164        if (isalpha(static_cast<unsigned char>(c))) {
165          // Collect all chars of an identifier:
166          const char *start = cursor_ - 1;
167          while (isalnum(static_cast<unsigned char>(*cursor_)) ||
168                 *cursor_ == '_')
169            cursor_++;
170          attribute_.clear();
171          attribute_.append(start, cursor_);
172          // First, see if it is a type keyword from the table of types:
173          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE) \
174            if (attribute_ == IDLTYPE) { \
175              token_ = kToken ## ENUM; \
176              return; \
177            }
178            FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
179          #undef FLATBUFFERS_TD
180          // If it's a boolean constant keyword, turn those into integers,
181          // which simplifies our logic downstream.
182          if (attribute_ == "true" || attribute_ == "false") {
183            attribute_ = NumToString(attribute_ == "true");
184            token_ = kTokenIntegerConstant;
185            return;
186          }
187          // Check for declaration keywords:
188          if (attribute_ == "table")     { token_ = kTokenTable;     return; }
189          if (attribute_ == "struct")    { token_ = kTokenStruct;    return; }
190          if (attribute_ == "enum")      { token_ = kTokenEnum;      return; }
191          if (attribute_ == "union")     { token_ = kTokenUnion;     return; }
192          if (attribute_ == "namespace") { token_ = kTokenNameSpace; return; }
193          if (attribute_ == "root_type") { token_ = kTokenRootType;  return; }
194          // If not, it is a user-defined identifier:
195          token_ = kTokenIdentifier;
196          return;
197        } else if (isdigit(static_cast<unsigned char>(c)) || c == '-') {
198          const char *start = cursor_ - 1;
199          while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
200          if (*cursor_ == '.') {
201            cursor_++;
202            while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
203            // See if this float has a scientific notation suffix. Both JSON
204            // and C++ (through strtod() we use) have the same format:
205            if (*cursor_ == 'e' || *cursor_ == 'E') {
206              cursor_++;
207              if (*cursor_ == '+' || *cursor_ == '-') cursor_++;
208              while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
209            }
210            token_ = kTokenFloatConstant;
211          } else {
212            token_ = kTokenIntegerConstant;
213          }
214          attribute_.clear();
215          attribute_.append(start, cursor_);
216          return;
217        }
218        std::string ch;
219        ch = c;
220        if (c < ' ' || c > '~') ch = "code: " + NumToString(c);
221        Error("illegal character: " + ch);
222        break;
223    }
224  }
225}
226
227// Check if a given token is next, if so, consume it as well.
228bool Parser::IsNext(int t) {
229  bool isnext = t == token_;
230  if (isnext) Next();
231  return isnext;
232}
233
234// Expect a given token to be next, consume it, or error if not present.
235void Parser::Expect(int t) {
236  if (t != token_) {
237    Error("expecting: " + TokenToString(t) + " instead got: " +
238          TokenToString(token_));
239  }
240  Next();
241}
242
243// Parse any IDL type.
244void Parser::ParseType(Type &type) {
245  if (token_ >= kTokenBOOL && token_ <= kTokenSTRING) {
246    type.base_type = static_cast<BaseType>(token_ - kTokenNONE);
247  } else {
248    if (token_ == kTokenIdentifier) {
249      auto enum_def = enums_.Lookup(attribute_);
250      if (enum_def) {
251        type = enum_def->underlying_type;
252        if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
253      } else {
254        type.base_type = BASE_TYPE_STRUCT;
255        type.struct_def = LookupCreateStruct(attribute_);
256      }
257    } else if (token_ == '[') {
258      Next();
259      Type subtype;
260      ParseType(subtype);
261      if (subtype.base_type == BASE_TYPE_VECTOR) {
262        // We could support this, but it will complicate things, and it's
263        // easier to work around with a struct around the inner vector.
264        Error("nested vector types not supported (wrap in table first).");
265      }
266      if (subtype.base_type == BASE_TYPE_UNION) {
267        // We could support this if we stored a struct of 2 elements per
268        // union element.
269        Error("vector of union types not supported (wrap in table first).");
270      }
271      type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
272      type.element = subtype.base_type;
273      Expect(']');
274      return;
275    } else {
276      Error("illegal type syntax");
277    }
278  }
279  Next();
280}
281
282FieldDef &Parser::AddField(StructDef &struct_def,
283                           const std::string &name,
284                           const Type &type) {
285  auto &field = *new FieldDef();
286  field.value.offset =
287    FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size()));
288  field.name = name;
289  field.value.type = type;
290  if (struct_def.fixed) {  // statically compute the field offset
291    auto size = InlineSize(type);
292    auto alignment = InlineAlignment(type);
293    // structs_ need to have a predictable format, so we need to align to
294    // the largest scalar
295    struct_def.minalign = std::max(struct_def.minalign, alignment);
296    struct_def.PadLastField(alignment);
297    field.value.offset = static_cast<voffset_t>(struct_def.bytesize);
298    struct_def.bytesize += size;
299  }
300  if (struct_def.fields.Add(name, &field))
301    Error("field already exists: " + name);
302  return field;
303}
304
305void Parser::ParseField(StructDef &struct_def) {
306  std::string name = attribute_;
307  std::string dc = doc_comment_;
308  Expect(kTokenIdentifier);
309  Expect(':');
310  Type type;
311  ParseType(type);
312
313  if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type))
314    Error("structs_ may contain only scalar or struct fields");
315
316  FieldDef *typefield = nullptr;
317  if (type.base_type == BASE_TYPE_UNION) {
318    // For union fields, add a second auto-generated field to hold the type,
319    // with _type appended as the name.
320    typefield = &AddField(struct_def, name + "_type",
321                          type.enum_def->underlying_type);
322  }
323
324  auto &field = AddField(struct_def, name, type);
325
326  if (token_ == '=') {
327    Next();
328    ParseSingleValue(field.value);
329  }
330
331  field.doc_comment = dc;
332  ParseMetaData(field);
333  field.deprecated = field.attributes.Lookup("deprecated") != nullptr;
334  if (field.deprecated && struct_def.fixed)
335    Error("can't deprecate fields in a struct");
336  auto nested = field.attributes.Lookup("nested_flatbuffer");
337  if (nested) {
338    if (nested->type.base_type != BASE_TYPE_STRING)
339      Error("nested_flatbuffer attribute must be a string (the root type)");
340    if (field.value.type.base_type != BASE_TYPE_VECTOR ||
341        field.value.type.element != BASE_TYPE_UCHAR)
342      Error("nested_flatbuffer attribute may only apply to a vector of ubyte");
343    // This will cause an error if the root type of the nested flatbuffer
344    // wasn't defined elsewhere.
345    LookupCreateStruct(nested->constant);
346  }
347
348  if (typefield) {
349    // If this field is a union, and it has a manually assigned id,
350    // the automatically added type field should have an id as well (of N - 1).
351    auto attr = field.attributes.Lookup("id");
352    if (attr) {
353      auto id = atoi(attr->constant.c_str());
354      auto val = new Value();
355      val->type = attr->type;
356      val->constant = NumToString(id - 1);
357      typefield->attributes.Add("id", val);
358    }
359  }
360
361  Expect(';');
362}
363
364void Parser::ParseAnyValue(Value &val, FieldDef *field) {
365  switch (val.type.base_type) {
366    case BASE_TYPE_UNION: {
367      assert(field);
368      if (!field_stack_.size() ||
369          field_stack_.back().second->value.type.base_type != BASE_TYPE_UTYPE)
370        Error("missing type field before this union value: " + field->name);
371      auto enum_idx = atot<unsigned char>(
372                                    field_stack_.back().first.constant.c_str());
373      auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
374      if (!enum_val) Error("illegal type id for: " + field->name);
375      val.constant = NumToString(ParseTable(*enum_val->struct_def));
376      break;
377    }
378    case BASE_TYPE_STRUCT:
379      val.constant = NumToString(ParseTable(*val.type.struct_def));
380      break;
381    case BASE_TYPE_STRING: {
382      auto s = attribute_;
383      Expect(kTokenStringConstant);
384      val.constant = NumToString(builder_.CreateString(s).o);
385      break;
386    }
387    case BASE_TYPE_VECTOR: {
388      Expect('[');
389      val.constant = NumToString(ParseVector(val.type.VectorType()));
390      break;
391    }
392    default:
393      ParseSingleValue(val);
394      break;
395  }
396}
397
398void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
399  auto off = atot<uoffset_t>(val.constant.c_str());
400  assert(struct_stack_.size() - off == struct_def.bytesize);
401  builder_.Align(struct_def.minalign);
402  builder_.PushBytes(&struct_stack_[off], struct_def.bytesize);
403  struct_stack_.resize(struct_stack_.size() - struct_def.bytesize);
404  builder_.AddStructOffset(val.offset, builder_.GetSize());
405}
406
407uoffset_t Parser::ParseTable(const StructDef &struct_def) {
408  Expect('{');
409  size_t fieldn = 0;
410  for (;;) {
411    std::string name = attribute_;
412    if (!IsNext(kTokenStringConstant)) Expect(kTokenIdentifier);
413    auto field = struct_def.fields.Lookup(name);
414    if (!field) Error("unknown field: " + name);
415    if (struct_def.fixed && (fieldn >= struct_def.fields.vec.size()
416                            || struct_def.fields.vec[fieldn] != field)) {
417       Error("struct field appearing out of order: " + name);
418    }
419    Expect(':');
420    Value val = field->value;
421    ParseAnyValue(val, field);
422    field_stack_.push_back(std::make_pair(val, field));
423    fieldn++;
424    if (IsNext('}')) break;
425    Expect(',');
426  }
427  if (struct_def.fixed && fieldn != struct_def.fields.vec.size())
428    Error("incomplete struct initialization: " + struct_def.name);
429  auto start = struct_def.fixed
430                 ? builder_.StartStruct(struct_def.minalign)
431                 : builder_.StartTable();
432
433  for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
434       size;
435       size /= 2) {
436    // Go through elements in reverse, since we're building the data backwards.
437    for (auto it = field_stack_.rbegin();
438             it != field_stack_.rbegin() + fieldn; ++it) {
439      auto &value = it->first;
440      auto field = it->second;
441      if (!struct_def.sortbysize || size == SizeOf(value.type.base_type)) {
442        switch (value.type.base_type) {
443          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE) \
444            case BASE_TYPE_ ## ENUM: \
445              builder_.Pad(field->padding); \
446              builder_.AddElement(value.offset, \
447                             atot<CTYPE>(       value.constant.c_str()), \
448                             atot<CTYPE>(field->value.constant.c_str())); \
449              break;
450            FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
451          #undef FLATBUFFERS_TD
452          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE) \
453            case BASE_TYPE_ ## ENUM: \
454              builder_.Pad(field->padding); \
455              if (IsStruct(field->value.type)) { \
456                SerializeStruct(*field->value.type.struct_def, value); \
457              } else { \
458                builder_.AddOffset(value.offset, \
459                  atot<CTYPE>(value.constant.c_str())); \
460              } \
461              break;
462            FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD);
463          #undef FLATBUFFERS_TD
464        }
465      }
466    }
467  }
468  for (size_t i = 0; i < fieldn; i++) field_stack_.pop_back();
469
470  if (struct_def.fixed) {
471    builder_.ClearOffsets();
472    builder_.EndStruct();
473    // Temporarily store this struct in a side buffer, since this data has to
474    // be stored in-line later in the parent object.
475    auto off = struct_stack_.size();
476    struct_stack_.insert(struct_stack_.end(),
477                         builder_.GetBufferPointer(),
478                         builder_.GetBufferPointer() + struct_def.bytesize);
479    builder_.PopBytes(struct_def.bytesize);
480    return static_cast<uoffset_t>(off);
481  } else {
482    return builder_.EndTable(
483      start,
484      static_cast<voffset_t>(struct_def.fields.vec.size()));
485  }
486}
487
488uoffset_t Parser::ParseVector(const Type &type) {
489  int count = 0;
490  if (token_ != ']') for (;;) {
491    Value val;
492    val.type = type;
493    ParseAnyValue(val, NULL);
494    field_stack_.push_back(std::make_pair(val, nullptr));
495    count++;
496    if (token_ == ']') break;
497    Expect(',');
498  }
499  Next();
500
501  builder_.StartVector(count * InlineSize(type), InlineAlignment((type)));
502  for (int i = 0; i < count; i++) {
503    // start at the back, since we're building the data backwards.
504    auto &val = field_stack_.back().first;
505    switch (val.type.base_type) {
506      #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE) \
507        case BASE_TYPE_ ## ENUM: \
508          if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
509          else builder_.PushElement(atot<CTYPE>(val.constant.c_str())); \
510          break;
511        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
512      #undef FLATBUFFERS_TD
513    }
514    field_stack_.pop_back();
515  }
516
517  builder_.ClearOffsets();
518  return builder_.EndVector(count);
519}
520
521void Parser::ParseMetaData(Definition &def) {
522  if (IsNext('(')) {
523    for (;;) {
524      auto name = attribute_;
525      Expect(kTokenIdentifier);
526      auto e = new Value();
527      def.attributes.Add(name, e);
528      if (IsNext(':')) {
529        ParseSingleValue(*e);
530      }
531      if (IsNext(')')) break;
532      Expect(',');
533    }
534  }
535}
536
537bool Parser::TryTypedValue(int dtoken,
538                           bool check,
539                           Value &e,
540                           BaseType req) {
541  bool match = dtoken == token_;
542  if (match) {
543    e.constant = attribute_;
544    if (!check) {
545      if (e.type.base_type == BASE_TYPE_NONE) {
546        e.type.base_type = req;
547      } else {
548        Error(std::string("type mismatch: expecting: ") +
549              kTypeNames[e.type.base_type] +
550              ", found: " +
551              kTypeNames[req]);
552      }
553    }
554    Next();
555  }
556  return match;
557}
558
559void Parser::ParseSingleValue(Value &e) {
560  // First check if derived from an enum, to allow strings/identifier values:
561  if (e.type.enum_def && (token_ == kTokenIdentifier ||
562                          token_ == kTokenStringConstant)) {
563    auto enum_val = e.type.enum_def->vals.Lookup(attribute_);
564    if (!enum_val)
565      Error("unknown enum value: " + attribute_ +
566            ", for enum: " + e.type.enum_def->name);
567    e.constant = NumToString(enum_val->value);
568    Next();
569  } else if (TryTypedValue(kTokenIntegerConstant,
570                    IsScalar(e.type.base_type),
571                    e,
572                    BASE_TYPE_INT) ||
573      TryTypedValue(kTokenFloatConstant,
574                    IsFloat(e.type.base_type),
575                    e,
576                    BASE_TYPE_FLOAT) ||
577      TryTypedValue(kTokenStringConstant,
578                    e.type.base_type == BASE_TYPE_STRING,
579                    e,
580                    BASE_TYPE_STRING)) {
581  } else {
582    Error("cannot parse value starting with: " + TokenToString(token_));
583  }
584}
585
586StructDef *Parser::LookupCreateStruct(const std::string &name) {
587  auto struct_def = structs_.Lookup(name);
588  if (!struct_def) {
589    // Rather than failing, we create a "pre declared" StructDef, due to
590    // circular references, and check for errors at the end of parsing.
591    struct_def = new StructDef();
592    structs_.Add(name, struct_def);
593    struct_def->name = name;
594    struct_def->predecl = true;
595  }
596  return struct_def;
597}
598
599void Parser::ParseEnum(bool is_union) {
600  std::string dc = doc_comment_;
601  Next();
602  std::string name = attribute_;
603  Expect(kTokenIdentifier);
604  auto &enum_def = *new EnumDef();
605  enum_def.name = name;
606  enum_def.doc_comment = dc;
607  enum_def.is_union = is_union;
608  if (enums_.Add(name, &enum_def)) Error("enum already exists: " + name);
609  if (is_union) {
610    enum_def.underlying_type.base_type = BASE_TYPE_UTYPE;
611    enum_def.underlying_type.enum_def = &enum_def;
612  } else {
613    // Give specialized error message, since this type spec used to
614    // be optional in the first FlatBuffers release.
615    if (!IsNext(':')) Error("must specify the underlying integer type for this"
616                            " enum (e.g. \': short\', which was the default).");
617    // Specify the integer type underlying this enum.
618    ParseType(enum_def.underlying_type);
619    if (!IsInteger(enum_def.underlying_type.base_type))
620      Error("underlying enum type must be integral");
621    // Make this type refer back to the enum it was derived from.
622    enum_def.underlying_type.enum_def = &enum_def;
623  }
624  ParseMetaData(enum_def);
625  Expect('{');
626  if (is_union) enum_def.vals.Add("NONE", new EnumVal("NONE", 0));
627  do {
628    std::string name = attribute_;
629    std::string dc = doc_comment_;
630    Expect(kTokenIdentifier);
631    auto prevsize = enum_def.vals.vec.size();
632    auto value = enum_def.vals.vec.size()
633      ? enum_def.vals.vec.back()->value + 1
634      : 0;
635    auto &ev = *new EnumVal(name, value);
636    if (enum_def.vals.Add(name, &ev))
637      Error("enum value already exists: " + name);
638    ev.doc_comment = dc;
639    if (is_union) {
640      ev.struct_def = LookupCreateStruct(name);
641    }
642    if (IsNext('=')) {
643      ev.value = atoi(attribute_.c_str());
644      Expect(kTokenIntegerConstant);
645      if (prevsize && enum_def.vals.vec[prevsize - 1]->value >= ev.value)
646        Error("enum values must be specified in ascending order");
647    }
648  } while (IsNext(','));
649  Expect('}');
650  if (enum_def.attributes.Lookup("bit_flags")) {
651    for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
652         ++it) {
653      if (static_cast<size_t>((*it)->value) >=
654           SizeOf(enum_def.underlying_type.base_type) * 8)
655        Error("bit flag out of range of underlying integral type");
656      (*it)->value = 1 << (*it)->value;
657    }
658  }
659}
660
661void Parser::ParseDecl() {
662  std::string dc = doc_comment_;
663  bool fixed = IsNext(kTokenStruct);
664  if (!fixed) Expect(kTokenTable);
665  std::string name = attribute_;
666  Expect(kTokenIdentifier);
667  auto &struct_def = *LookupCreateStruct(name);
668  if (!struct_def.predecl) Error("datatype already exists: " + name);
669  struct_def.predecl = false;
670  struct_def.name = name;
671  struct_def.doc_comment = dc;
672  struct_def.fixed = fixed;
673  // Move this struct to the back of the vector just in case it was predeclared,
674  // to preserve declartion order.
675  remove(structs_.vec.begin(), structs_.vec.end(), &struct_def);
676  structs_.vec.back() = &struct_def;
677  ParseMetaData(struct_def);
678  struct_def.sortbysize =
679    struct_def.attributes.Lookup("original_order") == nullptr && !fixed;
680  Expect('{');
681  while (token_ != '}') ParseField(struct_def);
682  auto force_align = struct_def.attributes.Lookup("force_align");
683  if (fixed && force_align) {
684    auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
685    if (force_align->type.base_type != BASE_TYPE_INT ||
686        align < struct_def.minalign ||
687        align > 256 ||
688        align & (align - 1))
689      Error("force_align must be a power of two integer ranging from the"
690            "struct\'s natural alignment to 256");
691    struct_def.minalign = align;
692  }
693  struct_def.PadLastField(struct_def.minalign);
694  // Check if this is a table that has manual id assignments
695  auto &fields = struct_def.fields.vec;
696  if (!struct_def.fixed && fields.size()) {
697    size_t num_id_fields = 0;
698    for (auto it = fields.begin(); it != fields.end(); ++it) {
699      if ((*it)->attributes.Lookup("id")) num_id_fields++;
700    }
701    // If any fields have ids..
702    if (num_id_fields) {
703      // Then all fields must have them.
704      if (num_id_fields != fields.size())
705        Error("either all fields or no fields must have an 'id' attribute");
706      // Simply sort by id, then the fields are the same as if no ids had
707      // been specified.
708      std::sort(fields.begin(), fields.end(),
709        [](const FieldDef *a, const FieldDef *b) -> bool {
710          auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
711          auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
712          return a_id < b_id;
713      });
714      // Verify we have a contiguous set, and reassign vtable offsets.
715      for (int i = 0; i < static_cast<int>(fields.size()); i++) {
716        if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str()))
717          Error("field id\'s must be consecutive from 0, id " +
718                NumToString(i) + " missing or set twice");
719        fields[i]->value.offset = FieldIndexToOffset(static_cast<voffset_t>(i));
720      }
721    }
722  }
723  Expect('}');
724}
725
726bool Parser::SetRootType(const char *name) {
727  root_struct_def = structs_.Lookup(name);
728  return root_struct_def != nullptr;
729}
730
731bool Parser::Parse(const char *source) {
732  source_ = cursor_ = source;
733  line_ = 1;
734  error_.clear();
735  builder_.Clear();
736  try {
737    Next();
738    while (token_ != kTokenEof) {
739      if (token_ == kTokenNameSpace) {
740        Next();
741        name_space_.clear();
742        for (;;) {
743          name_space_.push_back(attribute_);
744          Expect(kTokenIdentifier);
745          if (!IsNext('.')) break;
746        }
747        Expect(';');
748      } else if (token_ == '{') {
749        if (!root_struct_def) Error("no root type set to parse json with");
750        if (builder_.GetSize()) {
751          Error("cannot have more than one json object in a file");
752        }
753        builder_.Finish(Offset<Table>(ParseTable(*root_struct_def)));
754      } else if (token_ == kTokenEnum) {
755        ParseEnum(false);
756      } else if (token_ == kTokenUnion) {
757        ParseEnum(true);
758      } else if (token_ == kTokenRootType) {
759        Next();
760        auto root_type = attribute_;
761        Expect(kTokenIdentifier);
762        Expect(';');
763        if (!SetRootType(root_type.c_str()))
764          Error("unknown root type: " + root_type);
765        if (root_struct_def->fixed)
766          Error("root type must be a table");
767      } else {
768        ParseDecl();
769      }
770    }
771    for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
772      if ((*it)->predecl)
773        Error("type referenced but not defined: " + (*it)->name);
774    }
775    for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
776      auto &enum_def = **it;
777      if (enum_def.is_union) {
778        for (auto it = enum_def.vals.vec.begin();
779             it != enum_def.vals.vec.end();
780             ++it) {
781          auto &val = **it;
782          if (val.struct_def && val.struct_def->fixed)
783            Error("only tables can be union elements: " + val.name);
784        }
785      }
786    }
787  } catch (const std::string &msg) {
788    error_ = "line " + NumToString(line_) + ": " + msg;
789    return false;
790  }
791  assert(!struct_stack_.size());
792  return true;
793}
794
795}  // namespace flatbuffers
796