blob: 99513b8c8bbfe9b0ada93cb73c6596dcfb3afb2b [file] [log] [blame]
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001/*
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>
Gabriel Martinezdf4909e2014-11-04 10:00:56 -080018#include <list>
Christian Helmich89a68942017-07-29 02:27:51 +090019#include <iostream>
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080020
Wouter van Oortmerssend3ac0bc2016-06-15 13:54:17 -070021#ifdef _WIN32
22#if !defined(_USE_MATH_DEFINES)
23#define _USE_MATH_DEFINES // For M_PI.
24#endif // !defined(_USE_MATH_DEFINES)
25#endif // _WIN32
26
27#include <math.h>
28
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080029#include "flatbuffers/idl.h"
30#include "flatbuffers/util.h"
31
32namespace flatbuffers {
33
34const char *const kTypeNames[] = {
MikkelFJf2b37052017-08-02 17:07:43 +020035 #define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \
36 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
rw48dfc692014-12-16 00:32:11 -080037 IDLTYPE,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080038 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
39 #undef FLATBUFFERS_TD
40 nullptr
41};
42
43const char kTypeSizes[] = {
MikkelFJf2b37052017-08-02 17:07:43 +020044 #define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \
45 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen557c88c2014-09-16 17:37:17 -070046 sizeof(CTYPE),
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080047 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
48 #undef FLATBUFFERS_TD
49};
50
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -070051// The enums in the reflection schema should match the ones we use internally.
52// Compare the last element to check if these go out of sync.
53static_assert(BASE_TYPE_UNION ==
Wouter van Oortmerssen622b8d02015-06-15 15:57:48 -070054 static_cast<BaseType>(reflection::Union),
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -070055 "enums don't match");
56
Wouter van Oortmerssen451272b2015-12-29 16:33:00 -080057// Any parsing calls have to be wrapped in this macro, which automates
58// handling of recursive error checking a bit. It will check the received
59// CheckedError object, and return straight away on error.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080060#define ECHECK(call) { auto ce = (call); if (ce.Check()) return ce; }
Wouter van Oortmerssen451272b2015-12-29 16:33:00 -080061
62// These two functions are called hundreds of times below, so define a short
63// form:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080064#define NEXT() ECHECK(Next())
65#define EXPECT(tok) ECHECK(Expect(tok))
66
Ben Hamiltonf6416d82016-08-01 14:04:51 -070067static bool ValidateUTF8(const std::string &str) {
68 const char *s = &str[0];
69 const char * const sEnd = s + str.length();
70 while (s < sEnd) {
71 if (FromUTF8(&s) < 0) {
72 return false;
73 }
74 }
75 return true;
76}
77
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080078CheckedError Parser::Error(const std::string &msg) {
79 error_ = file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : "";
80 #ifdef _WIN32
81 error_ += "(" + NumToString(line_) + ")"; // MSVC alike
82 #else
83 if (file_being_parsed_.length()) error_ += ":";
84 error_ += NumToString(line_) + ":0"; // gcc alike
85 #endif
86 error_ += ": error: " + msg;
87 return CheckedError(true);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080088}
89
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080090inline CheckedError NoError() { return CheckedError(false); }
91
Jason Stubbsa07f0d42017-04-18 04:19:43 +100092inline std::string OutOfRangeErrorMsg(int64_t val, const std::string &op,
93 int64_t limit) {
94 const std::string cause = NumToString(val) + op + NumToString(limit);
95 return "constant does not fit (" + cause + ")";
96}
97
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080098// Ensure that integer values we parse fit inside the declared integer type.
Jason Stubbsa07f0d42017-04-18 04:19:43 +100099CheckedError Parser::CheckInRange(int64_t val, int64_t min, int64_t max) {
100 if (val < min)
101 return Error(OutOfRangeErrorMsg(val, " < ", min));
102 else if (val > max)
103 return Error(OutOfRangeErrorMsg(val, " > ", max));
104 else
105 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800106}
107
108// atot: templated version of atoi/atof: convert a string to an instance of T.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800109template<typename T> inline CheckedError atot(const char *s, Parser &parser,
110 T *val) {
111 int64_t i = StringToInt(s);
Stewart Milesa8923222017-07-13 06:27:39 -0700112 const int64_t min = flatbuffers::numeric_limits<T>::min();
113 const int64_t max = flatbuffers::numeric_limits<T>::max();
Jason Stubbsa07f0d42017-04-18 04:19:43 +1000114 ECHECK(parser.CheckInRange(i, min, max));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800115 *val = (T)i;
116 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800117}
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800118template<> inline CheckedError atot<uint64_t>(const char *s, Parser &parser,
119 uint64_t *val) {
120 (void)parser;
121 *val = StringToUInt(s);
122 return NoError();
123}
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800124template<> inline CheckedError atot<bool>(const char *s, Parser &parser,
125 bool *val) {
126 (void)parser;
127 *val = 0 != atoi(s);
128 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800129}
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800130template<> inline CheckedError atot<float>(const char *s, Parser &parser,
131 float *val) {
132 (void)parser;
133 *val = static_cast<float>(strtod(s, nullptr));
134 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800135}
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800136template<> inline CheckedError atot<double>(const char *s, Parser &parser,
137 double *val) {
138 (void)parser;
139 *val = strtod(s, nullptr);
140 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800141}
142
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800143template<> inline CheckedError atot<Offset<void>>(const char *s, Parser &parser,
144 Offset<void> *val) {
145 (void)parser;
146 *val = Offset<void>(atoi(s));
147 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800148}
149
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700150std::string Namespace::GetFullyQualifiedName(const std::string &name,
151 size_t max_components) const {
152 // Early exit if we don't have a defined namespace.
153 if (components.size() == 0 || !max_components) {
154 return name;
155 }
156 std::stringstream stream;
157 for (size_t i = 0; i < std::min(components.size(), max_components);
158 i++) {
159 if (i) {
160 stream << ".";
161 }
162 stream << components[i];
163 }
Wouter van Oortmerssen8c1a7232017-01-09 15:54:31 -0800164 if (name.length()) stream << "." << name;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700165 return stream.str();
166}
167
168
169
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800170// Declare tokens we'll use. Single character tokens are represented by their
171// ascii character code (e.g. '{'), others above 256.
172#define FLATBUFFERS_GEN_TOKENS(TD) \
173 TD(Eof, 256, "end of file") \
174 TD(StringConstant, 257, "string constant") \
175 TD(IntegerConstant, 258, "integer constant") \
176 TD(FloatConstant, 259, "float constant") \
177 TD(Identifier, 260, "identifier") \
178 TD(Table, 261, "table") \
179 TD(Struct, 262, "struct") \
180 TD(Enum, 263, "enum") \
181 TD(Union, 264, "union") \
182 TD(NameSpace, 265, "namespace") \
Wouter van Oortmerssen5da7bda2014-07-31 15:11:03 -0700183 TD(RootType, 266, "root_type") \
184 TD(FileIdentifier, 267, "file_identifier") \
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -0700185 TD(FileExtension, 268, "file_extension") \
Wouter van Oortmerssen09521432014-11-17 17:27:26 -0800186 TD(Include, 269, "include") \
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800187 TD(Attribute, 270, "attribute") \
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -0800188 TD(Null, 271, "null") \
Wouter van Oortmerssen3f936c52017-01-18 16:23:35 -0800189 TD(Service, 272, "rpc_service") \
rouziera2b1bfc2017-08-04 11:04:28 -0400190 TD(NativeInclude, 273, "native_include") \
191 TD(BooleanConstant, 274, "boolean constant")
Wouter van Oortmerssen8f80fec2014-07-29 10:29:38 -0700192#ifdef __GNUC__
193__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
194#endif
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800195enum {
Wouter van Oortmerssen75349ae2014-07-09 11:44:26 -0700196 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800197 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
198 #undef FLATBUFFERS_TOKEN
MikkelFJf2b37052017-08-02 17:07:43 +0200199 #define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \
200 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen557c88c2014-09-16 17:37:17 -0700201 kToken ## ENUM,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800202 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
203 #undef FLATBUFFERS_TD
204};
205
206static std::string TokenToString(int t) {
207 static const char *tokens[] = {
208 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
209 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
210 #undef FLATBUFFERS_TOKEN
MikkelFJf2b37052017-08-02 17:07:43 +0200211 #define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \
212 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
rw48dfc692014-12-16 00:32:11 -0800213 IDLTYPE,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800214 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
215 #undef FLATBUFFERS_TD
216 };
217 if (t < 256) { // A single ascii char token.
218 std::string s;
Wouter van Oortmerssen8e409022014-09-02 17:32:12 -0700219 s.append(1, static_cast<char>(t));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800220 return s;
221 } else { // Other tokens.
222 return tokens[t - 256];
223 }
224}
225
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700226std::string Parser::TokenToStringId(int t) {
227 return TokenToString(t) + (t == kTokenIdentifier ? ": " + attribute_ : "");
228}
229
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700230// Parses exactly nibbles worth of hex digits into a number, or error.
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800231CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) {
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700232 for (int i = 0; i < nibbles; i++)
Chris Pickett30013b42016-01-05 13:38:03 -0600233 if (!isxdigit(static_cast<const unsigned char>(cursor_[i])))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800234 return Error("escape code must be followed by " + NumToString(nibbles) +
235 " hex digits");
Hiroshi Matsunaga7cf74cb2015-01-09 03:38:14 +0900236 std::string target(cursor_, cursor_ + nibbles);
Sahil Jainb6ba3222016-08-25 23:37:30 -0400237 *val = StringToUInt(target.c_str(), nullptr, 16);
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700238 cursor_ += nibbles;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800239 return NoError();
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700240}
241
Oli Wilkinsoncbe87472016-01-18 18:58:53 +0000242CheckedError Parser::SkipByteOrderMark() {
243 if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError();
244 cursor_++;
Wouter van Oortmerssenf6330ab2016-04-22 11:26:47 -0700245 if (static_cast<unsigned char>(*cursor_) != 0xbb) return Error("invalid utf-8 byte order mark");
246 cursor_++;
247 if (static_cast<unsigned char>(*cursor_) != 0xbf) return Error("invalid utf-8 byte order mark");
248 cursor_++;
Oli Wilkinsoncbe87472016-01-18 18:58:53 +0000249 return NoError();
250}
251
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -0800252bool IsIdentifierStart(char c) {
253 return isalpha(static_cast<unsigned char>(c)) || c == '_';
254}
255
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800256CheckedError Parser::Next() {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800257 doc_comment_.clear();
258 bool seen_newline = false;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700259 attribute_.clear();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800260 for (;;) {
261 char c = *cursor_++;
262 token_ = c;
263 switch (c) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800264 case '\0': cursor_--; token_ = kTokenEof; return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800265 case ' ': case '\r': case '\t': break;
266 case '\n': line_++; seen_newline = true; break;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800267 case '{': case '}': case '(': case ')': case '[': case ']':
268 case ',': case ':': case ';': case '=': return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800269 case '.':
Chris Pickett30013b42016-01-05 13:38:03 -0600270 if(!isdigit(static_cast<const unsigned char>(*cursor_))) return NoError();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800271 return Error("floating point constant can\'t start with \".\"");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800272 case '\"':
Ben Gertzfield6704b192016-04-28 12:27:38 -0700273 case '\'': {
274 int unicode_high_surrogate = -1;
275
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700276 while (*cursor_ != c) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800277 if (*cursor_ < ' ' && *cursor_ >= 0)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800278 return Error("illegal character in string constant");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800279 if (*cursor_ == '\\') {
280 cursor_++;
Ben Gertzfield6704b192016-04-28 12:27:38 -0700281 if (unicode_high_surrogate != -1 &&
282 *cursor_ != 'u') {
283 return Error(
284 "illegal Unicode sequence (unpaired high surrogate)");
285 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800286 switch (*cursor_) {
287 case 'n': attribute_ += '\n'; cursor_++; break;
288 case 't': attribute_ += '\t'; cursor_++; break;
289 case 'r': attribute_ += '\r'; cursor_++; break;
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700290 case 'b': attribute_ += '\b'; cursor_++; break;
291 case 'f': attribute_ += '\f'; cursor_++; break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800292 case '\"': attribute_ += '\"'; cursor_++; break;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700293 case '\'': attribute_ += '\''; cursor_++; break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800294 case '\\': attribute_ += '\\'; cursor_++; break;
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700295 case '/': attribute_ += '/'; cursor_++; break;
296 case 'x': { // Not in the JSON standard
297 cursor_++;
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800298 uint64_t val;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800299 ECHECK(ParseHexNum(2, &val));
300 attribute_ += static_cast<char>(val);
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700301 break;
302 }
303 case 'u': {
304 cursor_++;
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800305 uint64_t val;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800306 ECHECK(ParseHexNum(4, &val));
Ben Gertzfield6704b192016-04-28 12:27:38 -0700307 if (val >= 0xD800 && val <= 0xDBFF) {
308 if (unicode_high_surrogate != -1) {
309 return Error(
310 "illegal Unicode sequence (multiple high surrogates)");
311 } else {
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -0700312 unicode_high_surrogate = static_cast<int>(val);
Ben Gertzfield6704b192016-04-28 12:27:38 -0700313 }
314 } else if (val >= 0xDC00 && val <= 0xDFFF) {
315 if (unicode_high_surrogate == -1) {
316 return Error(
317 "illegal Unicode sequence (unpaired low surrogate)");
318 } else {
319 int code_point = 0x10000 +
320 ((unicode_high_surrogate & 0x03FF) << 10) +
321 (val & 0x03FF);
322 ToUTF8(code_point, &attribute_);
323 unicode_high_surrogate = -1;
324 }
325 } else {
326 if (unicode_high_surrogate != -1) {
327 return Error(
328 "illegal Unicode sequence (unpaired high surrogate)");
329 }
330 ToUTF8(static_cast<int>(val), &attribute_);
331 }
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700332 break;
333 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800334 default: return Error("unknown escape code in string constant");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800335 }
336 } else { // printable chars + UTF-8 bytes
Ben Gertzfield6704b192016-04-28 12:27:38 -0700337 if (unicode_high_surrogate != -1) {
338 return Error(
339 "illegal Unicode sequence (unpaired high surrogate)");
340 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800341 attribute_ += *cursor_++;
342 }
343 }
Ben Gertzfield6704b192016-04-28 12:27:38 -0700344 if (unicode_high_surrogate != -1) {
345 return Error(
346 "illegal Unicode sequence (unpaired high surrogate)");
347 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800348 cursor_++;
Ben Hamiltonf6416d82016-08-01 14:04:51 -0700349 if (!opts.allow_non_utf8 && !ValidateUTF8(attribute_)) {
350 return Error("illegal UTF-8 sequence");
351 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800352 token_ = kTokenStringConstant;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800353 return NoError();
Ben Gertzfield6704b192016-04-28 12:27:38 -0700354 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800355 case '/':
356 if (*cursor_ == '/') {
357 const char *start = ++cursor_;
Mormegila8d69622015-04-14 18:09:08 +0200358 while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800359 if (*start == '/') { // documentation comment
Zbigniew Mandziejewicz07d59652014-10-22 22:40:03 +0800360 if (cursor_ != source_ && !seen_newline)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800361 return Error(
362 "a documentation comment should be on a line on its own");
Gabriel Martinez730c0ca2014-09-24 11:46:32 -0700363 doc_comment_.push_back(std::string(start + 1, cursor_));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800364 }
365 break;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700366 } else if (*cursor_ == '*') {
367 cursor_++;
368 // TODO: make nested.
369 while (*cursor_ != '*' || cursor_[1] != '/') {
Wouter van Oortmerssenab51b032016-10-07 17:07:39 -0700370 if (*cursor_ == '\n') line_++;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800371 if (!*cursor_) return Error("end of file in comment");
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700372 cursor_++;
373 }
374 cursor_ += 2;
375 break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800376 }
377 // fall thru
378 default:
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -0800379 if (IsIdentifierStart(c)) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800380 // Collect all chars of an identifier:
381 const char *start = cursor_ - 1;
382 while (isalnum(static_cast<unsigned char>(*cursor_)) ||
383 *cursor_ == '_')
384 cursor_++;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800385 attribute_.append(start, cursor_);
386 // First, see if it is a type keyword from the table of types:
MikkelFJf2b37052017-08-02 17:07:43 +0200387 #define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \
388 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
389 if (attribute_ == IDLTYPE || attribute_ == ALIASTYPE) { \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800390 token_ = kToken ## ENUM; \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800391 return NoError(); \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800392 }
393 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
394 #undef FLATBUFFERS_TD
395 // If it's a boolean constant keyword, turn those into integers,
396 // which simplifies our logic downstream.
397 if (attribute_ == "true" || attribute_ == "false") {
398 attribute_ = NumToString(attribute_ == "true");
rouziera2b1bfc2017-08-04 11:04:28 -0400399 token_ = kTokenBooleanConstant;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800400 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800401 }
402 // Check for declaration keywords:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800403 if (attribute_ == "table") {
404 token_ = kTokenTable;
405 return NoError();
406 }
407 if (attribute_ == "struct") {
408 token_ = kTokenStruct;
409 return NoError();
410 }
411 if (attribute_ == "enum") {
412 token_ = kTokenEnum;
413 return NoError();
414 }
415 if (attribute_ == "union") {
416 token_ = kTokenUnion;
417 return NoError();
418 }
419 if (attribute_ == "namespace") {
420 token_ = kTokenNameSpace;
421 return NoError();
422 }
423 if (attribute_ == "root_type") {
424 token_ = kTokenRootType;
425 return NoError();
426 }
427 if (attribute_ == "include") {
428 token_ = kTokenInclude;
429 return NoError();
430 }
431 if (attribute_ == "attribute") {
432 token_ = kTokenAttribute;
433 return NoError();
434 }
Wouter van Oortmerssen5da7bda2014-07-31 15:11:03 -0700435 if (attribute_ == "file_identifier") {
436 token_ = kTokenFileIdentifier;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800437 return NoError();
Wouter van Oortmerssen5da7bda2014-07-31 15:11:03 -0700438 }
439 if (attribute_ == "file_extension") {
440 token_ = kTokenFileExtension;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800441 return NoError();
Wouter van Oortmerssen5da7bda2014-07-31 15:11:03 -0700442 }
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800443 if (attribute_ == "null") {
444 token_ = kTokenNull;
445 return NoError();
446 }
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -0800447 if (attribute_ == "rpc_service") {
448 token_ = kTokenService;
449 return NoError();
450 }
Wouter van Oortmerssen3f936c52017-01-18 16:23:35 -0800451 if (attribute_ == "native_include") {
452 token_ = kTokenNativeInclude;
453 return NoError();
454 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800455 // If not, it is a user-defined identifier:
456 token_ = kTokenIdentifier;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800457 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800458 } else if (isdigit(static_cast<unsigned char>(c)) || c == '-') {
459 const char *start = cursor_ - 1;
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800460 if (c == '-' && *cursor_ == '0' &&
461 (cursor_[1] == 'x' || cursor_[1] == 'X')) {
Ramanf6f88e52016-07-12 19:47:53 +0200462 ++start;
463 ++cursor_;
464 attribute_.append(&c, &c + 1);
465 c = '0';
466 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700467 if (c == '0' && (*cursor_ == 'x' || *cursor_ == 'X')) {
468 cursor_++;
469 while (isxdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
470 attribute_.append(start + 2, cursor_);
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800471 attribute_ = NumToString(static_cast<int64_t>(
472 StringToUInt(attribute_.c_str(), nullptr, 16)));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700473 token_ = kTokenIntegerConstant;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800474 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700475 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800476 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700477 if (*cursor_ == '.' || *cursor_ == 'e' || *cursor_ == 'E') {
478 if (*cursor_ == '.') {
479 cursor_++;
480 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
481 }
Wouter van Oortmerssen93df5692014-07-10 13:40:55 -0700482 // See if this float has a scientific notation suffix. Both JSON
483 // and C++ (through strtod() we use) have the same format:
484 if (*cursor_ == 'e' || *cursor_ == 'E') {
485 cursor_++;
486 if (*cursor_ == '+' || *cursor_ == '-') cursor_++;
487 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
488 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800489 token_ = kTokenFloatConstant;
490 } else {
491 token_ = kTokenIntegerConstant;
492 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800493 attribute_.append(start, cursor_);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800494 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800495 }
496 std::string ch;
497 ch = c;
498 if (c < ' ' || c > '~') ch = "code: " + NumToString(c);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800499 return Error("illegal character: " + ch);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800500 }
501 }
502}
503
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800504// Check if a given token is next.
505bool Parser::Is(int t) {
506 return t == token_;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800507}
508
509// Expect a given token to be next, consume it, or error if not present.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800510CheckedError Parser::Expect(int t) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800511 if (t != token_) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800512 return Error("expecting: " + TokenToString(t) + " instead got: " +
513 TokenToStringId(token_));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800514 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800515 NEXT();
516 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800517}
518
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800519CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) {
520 while (Is('.')) {
521 NEXT();
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700522 *id += ".";
523 *id += attribute_;
524 if (last) *last = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800525 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700526 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800527 return NoError();
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700528}
529
530EnumDef *Parser::LookupEnum(const std::string &id) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700531 // Search thru parent namespaces.
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -0700532 for (int components = static_cast<int>(current_namespace_->components.size());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700533 components >= 0; components--) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800534 auto ed = enums_.Lookup(
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -0700535 current_namespace_->GetFullyQualifiedName(id, components));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700536 if (ed) return ed;
537 }
538 return nullptr;
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700539}
540
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800541CheckedError Parser::ParseTypeIdent(Type &type) {
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700542 std::string id = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800543 EXPECT(kTokenIdentifier);
544 ECHECK(ParseNamespacing(&id, nullptr));
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700545 auto enum_def = LookupEnum(id);
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700546 if (enum_def) {
547 type = enum_def->underlying_type;
548 if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
549 } else {
550 type.base_type = BASE_TYPE_STRUCT;
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700551 type.struct_def = LookupCreateStruct(id);
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700552 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800553 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700554}
555
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800556// Parse any IDL type.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800557CheckedError Parser::ParseType(Type &type) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800558 if (token_ >= kTokenBOOL && token_ <= kTokenSTRING) {
559 type.base_type = static_cast<BaseType>(token_ - kTokenNONE);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800560 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800561 } else {
562 if (token_ == kTokenIdentifier) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800563 ECHECK(ParseTypeIdent(type));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800564 } else if (token_ == '[') {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800565 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800566 Type subtype;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800567 ECHECK(ParseType(subtype));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800568 if (subtype.base_type == BASE_TYPE_VECTOR) {
569 // We could support this, but it will complicate things, and it's
570 // easier to work around with a struct around the inner vector.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800571 return Error(
572 "nested vector types not supported (wrap in table first).");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800573 }
Wouter van Oortmerssen3fb6a862014-07-14 17:49:04 -0700574 type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800575 type.element = subtype.base_type;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800576 EXPECT(']');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800577 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800578 return Error("illegal type syntax");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800579 }
580 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800581 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800582}
583
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800584CheckedError Parser::AddField(StructDef &struct_def, const std::string &name,
585 const Type &type, FieldDef **dest) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800586 auto &field = *new FieldDef();
587 field.value.offset =
588 FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size()));
589 field.name = name;
Gabriel Martinezdf4909e2014-11-04 10:00:56 -0800590 field.file = struct_def.file;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800591 field.value.type = type;
592 if (struct_def.fixed) { // statically compute the field offset
593 auto size = InlineSize(type);
594 auto alignment = InlineAlignment(type);
595 // structs_ need to have a predictable format, so we need to align to
596 // the largest scalar
597 struct_def.minalign = std::max(struct_def.minalign, alignment);
598 struct_def.PadLastField(alignment);
Wouter van Oortmerssen12563072014-06-30 15:56:31 -0700599 field.value.offset = static_cast<voffset_t>(struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800600 struct_def.bytesize += size;
601 }
602 if (struct_def.fields.Add(name, &field))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800603 return Error("field already exists: " + name);
604 *dest = &field;
605 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800606}
607
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800608CheckedError Parser::ParseField(StructDef &struct_def) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800609 std::string name = attribute_;
Wouter van Oortmerssene9f1f4d2017-06-02 15:55:02 -0700610
Wouter van Oortmerssen8a58aaf2017-08-10 14:22:03 -0700611 if (structs_.Lookup(name))
Wouter van Oortmerssene9f1f4d2017-06-02 15:55:02 -0700612 return Error("field name can not be the same as table/struct name");
613
Gabriel Martinez730c0ca2014-09-24 11:46:32 -0700614 std::vector<std::string> dc = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800615 EXPECT(kTokenIdentifier);
616 EXPECT(':');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800617 Type type;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800618 ECHECK(ParseType(type));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800619
620 if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800621 return Error("structs_ may contain only scalar or struct fields");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800622
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700623 FieldDef *typefield = nullptr;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800624 if (type.base_type == BASE_TYPE_UNION) {
625 // For union fields, add a second auto-generated field to hold the type,
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700626 // with a special suffix.
627 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
628 type.enum_def->underlying_type, &typefield));
Bei Li68bbe982017-01-24 11:52:36 -0800629 } else if (type.base_type == BASE_TYPE_VECTOR &&
630 type.element == BASE_TYPE_UNION) {
Kamil Rojewski46bb05d2017-08-11 18:24:36 +0200631 // Only cpp, js and ts supports the union vector feature so far.
632 if (!SupportsVectorOfUnions()) {
Bei Li68bbe982017-01-24 11:52:36 -0800633 return Error("Vectors of unions are not yet supported in all "
634 "the specified programming languages.");
635 }
636 // For vector of union fields, add a second auto-generated vector field to
637 // hold the types, with a special suffix.
638 Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def);
639 union_vector.element = BASE_TYPE_UTYPE;
640 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
641 union_vector, &typefield));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800642 }
643
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800644 FieldDef *field;
645 ECHECK(AddField(struct_def, name, type, &field));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800646
647 if (token_ == '=') {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800648 NEXT();
Wouter van Oortmerssen15dc1a82014-09-03 12:23:15 -0700649 if (!IsScalar(type.base_type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800650 return Error("default values currently only supported for scalars");
651 ECHECK(ParseSingleValue(field->value));
Wouter van Oortmerssenfd542c72016-04-20 12:05:21 -0700652 }
653 if (IsFloat(field->value.type.base_type)) {
654 if (!strpbrk(field->value.constant.c_str(), ".eE"))
655 field->value.constant += ".0";
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800656 }
657
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -0700658 if (type.enum_def &&
659 IsScalar(type.base_type) &&
660 !struct_def.fixed &&
661 !type.enum_def->attributes.Lookup("bit_flags") &&
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700662 !type.enum_def->ReverseLookup(static_cast<int>(
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800663 StringToInt(field->value.constant.c_str()))))
664 return Error("enum " + type.enum_def->name +
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -0700665 " does not have a declaration for this field\'s default of " +
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800666 field->value.constant);
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -0700667
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800668 field->doc_comment = dc;
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -0800669 ECHECK(ParseMetaData(&field->attributes));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800670 field->deprecated = field->attributes.Lookup("deprecated") != nullptr;
671 auto hash_name = field->attributes.Lookup("hash");
Alex Amesd5753212015-02-13 15:58:29 -0800672 if (hash_name) {
673 switch (type.base_type) {
674 case BASE_TYPE_INT:
675 case BASE_TYPE_UINT: {
676 if (FindHashFunction32(hash_name->constant.c_str()) == nullptr)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800677 return Error("Unknown hashing algorithm for 32 bit types: " +
Alex Amesd5753212015-02-13 15:58:29 -0800678 hash_name->constant);
679 break;
680 }
681 case BASE_TYPE_LONG:
682 case BASE_TYPE_ULONG: {
683 if (FindHashFunction64(hash_name->constant.c_str()) == nullptr)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800684 return Error("Unknown hashing algorithm for 64 bit types: " +
Alex Amesd5753212015-02-13 15:58:29 -0800685 hash_name->constant);
686 break;
687 }
688 default:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800689 return Error(
690 "only int, uint, long and ulong data types support hashing.");
Alex Amesd5753212015-02-13 15:58:29 -0800691 }
692 }
Wouter van Oortmerssendc2fa212016-10-05 16:59:15 -0700693 auto cpp_type = field->attributes.Lookup("cpp_type");
694 if (cpp_type) {
695 if (!hash_name)
696 return Error("cpp_type can only be used with a hashed field");
697 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800698 if (field->deprecated && struct_def.fixed)
699 return Error("can't deprecate fields in a struct");
700 field->required = field->attributes.Lookup("required") != nullptr;
701 if (field->required && (struct_def.fixed ||
702 IsScalar(field->value.type.base_type)))
703 return Error("only non-scalar fields in tables may be 'required'");
704 field->key = field->attributes.Lookup("key") != nullptr;
705 if (field->key) {
Wouter van Oortmerssen35508992015-01-07 17:51:31 -0800706 if (struct_def.has_key)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800707 return Error("only one field may be set as 'key'");
Wouter van Oortmerssen35508992015-01-07 17:51:31 -0800708 struct_def.has_key = true;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800709 if (!IsScalar(field->value.type.base_type)) {
710 field->required = true;
711 if (field->value.type.base_type != BASE_TYPE_STRING)
712 return Error("'key' field must be string or scalar type");
Wouter van Oortmerssen35508992015-01-07 17:51:31 -0800713 }
714 }
Wouter van Oortmerssen641b3972016-12-02 14:25:08 -0800715
716 field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
717 if (field->native_inline && !IsStruct(field->value.type))
718 return Error("native_inline can only be defined on structs'");
719
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800720 auto nested = field->attributes.Lookup("nested_flatbuffer");
Wouter van Oortmerssen3e201a92014-07-15 17:50:22 -0700721 if (nested) {
722 if (nested->type.base_type != BASE_TYPE_STRING)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800723 return Error(
724 "nested_flatbuffer attribute must be a string (the root type)");
725 if (field->value.type.base_type != BASE_TYPE_VECTOR ||
726 field->value.type.element != BASE_TYPE_UCHAR)
727 return Error(
728 "nested_flatbuffer attribute may only apply to a vector of ubyte");
Wouter van Oortmerssen3e201a92014-07-15 17:50:22 -0700729 // This will cause an error if the root type of the nested flatbuffer
730 // wasn't defined elsewhere.
731 LookupCreateStruct(nested->constant);
Christian Helmich89a68942017-07-29 02:27:51 +0900732
733 // Keep a pointer to StructDef in FieldDef to simplify re-use later
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -0700734 auto nested_qualified_name =
735 current_namespace_->GetFullyQualifiedName(nested->constant);
Christian Helmich89a68942017-07-29 02:27:51 +0900736 field->nested_flatbuffer = structs_.Lookup(nested_qualified_name);
Wouter van Oortmerssen3e201a92014-07-15 17:50:22 -0700737 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800738
Wouter van Oortmerssendddd0862017-06-02 16:41:22 -0700739 if (field->attributes.Lookup("flexbuffer")) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700740 field->flexbuffer = true;
Wouter van Oortmerssendddd0862017-06-02 16:41:22 -0700741 uses_flexbuffers_ = true;
742 if (field->value.type.base_type != BASE_TYPE_VECTOR ||
743 field->value.type.element != BASE_TYPE_UCHAR)
744 return Error(
745 "flexbuffer attribute may only apply to a vector of ubyte");
746 }
747
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700748 if (typefield) {
Kamil Rojewski7cc72e42017-08-11 18:19:28 +0200749 if (!IsScalar(typefield->value.type.base_type)) {
750 // this is a union vector field
751 typefield->required = field->required;
752 }
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700753 // If this field is a union, and it has a manually assigned id,
754 // the automatically added type field should have an id as well (of N - 1).
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800755 auto attr = field->attributes.Lookup("id");
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700756 if (attr) {
757 auto id = atoi(attr->constant.c_str());
758 auto val = new Value();
759 val->type = attr->type;
760 val->constant = NumToString(id - 1);
761 typefield->attributes.Add("id", val);
762 }
763 }
764
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800765 EXPECT(';');
766 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800767}
768
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -0700769CheckedError Parser::ParseString(Value &val) {
770 auto s = attribute_;
771 EXPECT(kTokenStringConstant);
772 val.constant = NumToString(builder_.CreateString(s).o);
773 return NoError();
774}
775
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -0700776CheckedError Parser::ParseComma() {
777 if (!opts.protobuf_ascii_alike) EXPECT(',');
778 return NoError();
779}
780
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800781CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700782 size_t parent_fieldn,
783 const StructDef *parent_struct_def) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800784 switch (val.type.base_type) {
785 case BASE_TYPE_UNION: {
786 assert(field);
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700787 std::string constant;
Wouter van Oortmersseneac29052017-01-18 12:02:31 -0800788 // Find corresponding type field we may have already parsed.
789 for (auto elem = field_stack_.rbegin();
790 elem != field_stack_.rbegin() + parent_fieldn; ++elem) {
791 auto &type = elem->second->value.type;
792 if (type.base_type == BASE_TYPE_UTYPE &&
793 type.enum_def == val.type.enum_def) {
794 constant = elem->first.constant;
795 break;
796 }
797 }
798 if (constant.empty()) {
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700799 // We haven't seen the type field yet. Sadly a lot of JSON writers
800 // output these in alphabetical order, meaning it comes after this
801 // value. So we scan past the value to find it, then come back here.
802 auto type_name = field->name + UnionTypeFieldSuffix();
803 assert(parent_struct_def);
804 auto type_field = parent_struct_def->fields.Lookup(type_name);
805 assert(type_field); // Guaranteed by ParseField().
806 // Remember where we are in the source file, so we can come back here.
807 auto backup = *static_cast<ParserState *>(this);
808 ECHECK(SkipAnyJsonValue()); // The table.
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -0700809 ECHECK(ParseComma());
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700810 auto next_name = attribute_;
811 if (Is(kTokenStringConstant)) {
812 NEXT();
813 } else {
814 EXPECT(kTokenIdentifier);
815 }
816 if (next_name != type_name)
817 return Error("missing type field after this union value: " +
818 type_name);
819 EXPECT(':');
820 Value type_val = type_field->value;
821 ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr));
822 constant = type_val.constant;
823 // Got the information we needed, now rewind:
824 *static_cast<ParserState *>(this) = backup;
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700825 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800826 uint8_t enum_idx;
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700827 ECHECK(atot(constant.c_str(), *this, &enum_idx));
Wouter van Oortmerssen3fb6a862014-07-14 17:49:04 -0700828 auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800829 if (!enum_val) return Error("illegal type id for: " + field->name);
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -0700830 if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
831 ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
832 nullptr));
833 if (enum_val->union_type.struct_def->fixed) {
834 // All BASE_TYPE_UNION values are offsets, so turn this into one.
835 SerializeStruct(*enum_val->union_type.struct_def, val);
836 builder_.ClearOffsets();
837 val.constant = NumToString(builder_.GetSize());
838 }
839 } else if (enum_val->union_type.base_type == BASE_TYPE_STRING) {
840 ECHECK(ParseString(val));
841 } else {
842 assert(false);
843 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800844 break;
845 }
846 case BASE_TYPE_STRUCT:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800847 ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800848 break;
849 case BASE_TYPE_STRING: {
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -0700850 ECHECK(ParseString(val));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800851 break;
852 }
853 case BASE_TYPE_VECTOR: {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800854 uoffset_t off;
855 ECHECK(ParseVector(val.type.VectorType(), &off));
856 val.constant = NumToString(off);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800857 break;
858 }
Alex Amesd5753212015-02-13 15:58:29 -0800859 case BASE_TYPE_INT:
860 case BASE_TYPE_UINT:
861 case BASE_TYPE_LONG:
862 case BASE_TYPE_ULONG: {
863 if (field && field->attributes.Lookup("hash") &&
864 (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800865 ECHECK(ParseHash(val, field));
Alex Amesd5753212015-02-13 15:58:29 -0800866 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800867 ECHECK(ParseSingleValue(val));
Alex Amesd5753212015-02-13 15:58:29 -0800868 }
869 break;
870 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800871 default:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800872 ECHECK(ParseSingleValue(val));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800873 break;
874 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800875 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800876}
877
878void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700879 assert(val.constant.length() == struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800880 builder_.Align(struct_def.minalign);
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700881 builder_.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()),
882 struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800883 builder_.AddStructOffset(val.offset, builder_.GetSize());
884}
885
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700886CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
887 const StructDef *struct_def,
Stewart Milesa8923222017-07-13 06:27:39 -0700888 ParseTableDelimitersBody body,
889 void *state) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700890 // We allow tables both as JSON object{ .. } with field names
Guillaume Giraudb1740682017-06-08 01:58:19 +0200891 // or vector[..] with all fields in order
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700892 char terminator = '}';
893 bool is_nested_vector = struct_def && Is('[');
894 if (is_nested_vector) {
Guillaume Giraudb1740682017-06-08 01:58:19 +0200895 NEXT();
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700896 terminator = ']';
Guillaume Giraudb1740682017-06-08 01:58:19 +0200897 } else {
898 EXPECT('{');
899 }
Wouter van Oortmerssen6c2dc412015-01-16 16:57:04 -0800900 for (;;) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700901 if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
Guillaume Giraudb1740682017-06-08 01:58:19 +0200902 std::string name;
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700903 if (is_nested_vector) {
904 if (fieldn > struct_def->fields.vec.size()) {
Guillaume Giraudb1740682017-06-08 01:58:19 +0200905 return Error("too many unnamed fields in nested array");
906 }
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700907 name = struct_def->fields.vec[fieldn]->name;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800908 } else {
Guillaume Giraudb1740682017-06-08 01:58:19 +0200909 name = attribute_;
910 if (Is(kTokenStringConstant)) {
911 NEXT();
912 } else {
913 EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
914 }
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -0700915 if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800916 }
Stewart Milesa8923222017-07-13 06:27:39 -0700917 ECHECK(body(name, fieldn, struct_def, state));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700918 if (Is(terminator)) break;
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -0700919 ECHECK(ParseComma());
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700920 }
921 NEXT();
922 if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
923 return Error("wrong number of unnamed fields in table vector");
924 }
925 return NoError();
926}
927
928CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
929 uoffset_t *ovalue) {
Stewart Milesa8923222017-07-13 06:27:39 -0700930 size_t fieldn_outer = 0;
931 auto err = ParseTableDelimiters(fieldn_outer, &struct_def,
932 [](const std::string &name, size_t &fieldn,
933 const StructDef *struct_def_inner,
934 void *state) -> CheckedError {
935 Parser *parser = static_cast<Parser *>(state);
schoetbi2e2063c2017-07-19 17:58:48 +0200936 if (name == "$schema") {
Stewart Milesa8923222017-07-13 06:27:39 -0700937 ECHECK(parser->Expect(kTokenStringConstant));
schoetbi2e2063c2017-07-19 17:58:48 +0200938 return NoError();
939 }
Stewart Milesa8923222017-07-13 06:27:39 -0700940 auto field = struct_def_inner->fields.Lookup(name);
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800941 if (!field) {
Stewart Milesa8923222017-07-13 06:27:39 -0700942 if (!parser->opts.skip_unexpected_fields_in_json) {
943 return parser->Error("unknown field: " + name);
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800944 } else {
Stewart Milesa8923222017-07-13 06:27:39 -0700945 ECHECK(parser->SkipAnyJsonValue());
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800946 }
947 } else {
Stewart Milesa8923222017-07-13 06:27:39 -0700948 if (parser->Is(kTokenNull)) {
949 ECHECK(parser->Next()); // Ignore this field.
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800950 } else {
951 Value val = field->value;
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700952 if (field->flexbuffer) {
953 flexbuffers::Builder builder(1024,
954 flexbuffers::BUILDER_FLAG_SHARE_ALL);
Stewart Milesa8923222017-07-13 06:27:39 -0700955 ECHECK(parser->ParseFlexBufferValue(&builder));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700956 builder.Finish();
Stewart Milesa8923222017-07-13 06:27:39 -0700957 auto off = parser->builder_.CreateVector(builder.GetBuffer());
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700958 val.constant = NumToString(off.o);
Christian Helmich89a68942017-07-29 02:27:51 +0900959 } else if (field->nested_flatbuffer) {
960 ECHECK(parser->ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700961 } else {
Stewart Milesa8923222017-07-13 06:27:39 -0700962 ECHECK(parser->ParseAnyValue(val, field, fieldn, struct_def_inner));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700963 }
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800964 // Hardcoded insertion-sort with error-check.
965 // If fields are specified in order, then this loop exits immediately.
Stewart Milesa8923222017-07-13 06:27:39 -0700966 auto elem = parser->field_stack_.rbegin();
967 for (; elem != parser->field_stack_.rbegin() + fieldn; ++elem) {
Wouter van Oortmersseneac29052017-01-18 12:02:31 -0800968 auto existing_field = elem->second;
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800969 if (existing_field == field)
Stewart Milesa8923222017-07-13 06:27:39 -0700970 return parser->Error("field set more than once: " + field->name);
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800971 if (existing_field->value.offset < field->value.offset) break;
972 }
Wouter van Oortmersseneac29052017-01-18 12:02:31 -0800973 // Note: elem points to before the insertion point, thus .base() points
974 // to the correct spot.
Stewart Milesa8923222017-07-13 06:27:39 -0700975 parser->field_stack_.insert(elem.base(),
976 std::make_pair(val, field));
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800977 fieldn++;
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800978 }
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700979 }
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700980 return NoError();
Stewart Milesa8923222017-07-13 06:27:39 -0700981 }, this);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700982 ECHECK(err);
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800983
sfariv55dec4d2017-05-18 09:32:04 -0700984 // Check if all required fields are parsed.
985 for (auto field_it = struct_def.fields.vec.begin();
986 field_it != struct_def.fields.vec.end();
987 ++field_it) {
988 auto required_field = *field_it;
989 if (!required_field->required) {
990 continue;
991 }
992 bool found = false;
Stewart Milesa8923222017-07-13 06:27:39 -0700993 for (auto pf_it = field_stack_.end() - fieldn_outer;
sfariv55dec4d2017-05-18 09:32:04 -0700994 pf_it != field_stack_.end();
995 ++pf_it) {
996 auto parsed_field = pf_it->second;
997 if (parsed_field == required_field) {
998 found = true;
999 break;
1000 }
1001 }
1002 if (!found) {
1003 return Error("required field is missing: " + required_field->name + " in " + struct_def.name);
1004 }
1005 }
1006
Stewart Milesa8923222017-07-13 06:27:39 -07001007 if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001008 return Error("struct: wrong number of initializers: " + struct_def.name);
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -07001009
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001010 auto start = struct_def.fixed
1011 ? builder_.StartStruct(struct_def.minalign)
1012 : builder_.StartTable();
1013
1014 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1015 size;
1016 size /= 2) {
1017 // Go through elements in reverse, since we're building the data backwards.
Stewart Milesa8923222017-07-13 06:27:39 -07001018 for (auto it = field_stack_.rbegin(); it != field_stack_.rbegin() +
1019 fieldn_outer;
1020 ++it) {
Shuhei Tanuma721d2192015-11-06 07:14:21 +09001021 auto &field_value = it->first;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001022 auto field = it->second;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001023 if (!struct_def.sortbysize ||
1024 size == SizeOf(field_value.type.base_type)) {
Shuhei Tanuma721d2192015-11-06 07:14:21 +09001025 switch (field_value.type.base_type) {
MikkelFJf2b37052017-08-02 17:07:43 +02001026 #define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \
1027 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001028 case BASE_TYPE_ ## ENUM: \
1029 builder_.Pad(field->padding); \
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -07001030 if (struct_def.fixed) { \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001031 CTYPE val; \
1032 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1033 builder_.PushElement(val); \
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -07001034 } else { \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001035 CTYPE val, valdef; \
1036 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1037 ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \
1038 builder_.AddElement(field_value.offset, val, valdef); \
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -07001039 } \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001040 break;
1041 FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
1042 #undef FLATBUFFERS_TD
MikkelFJf2b37052017-08-02 17:07:43 +02001043 #define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \
1044 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001045 case BASE_TYPE_ ## ENUM: \
1046 builder_.Pad(field->padding); \
1047 if (IsStruct(field->value.type)) { \
Shuhei Tanuma721d2192015-11-06 07:14:21 +09001048 SerializeStruct(*field->value.type.struct_def, field_value); \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001049 } else { \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001050 CTYPE val; \
1051 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1052 builder_.AddOffset(field_value.offset, val); \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001053 } \
1054 break;
1055 FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD);
1056 #undef FLATBUFFERS_TD
1057 }
1058 }
1059 }
1060 }
Stewart Milesa8923222017-07-13 06:27:39 -07001061 for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001062
1063 if (struct_def.fixed) {
1064 builder_.ClearOffsets();
1065 builder_.EndStruct();
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -07001066 assert(value);
1067 // Temporarily store this struct in the value string, since it is to
1068 // be serialized in-place elsewhere.
1069 value->assign(
1070 reinterpret_cast<const char *>(builder_.GetCurrentBufferPointer()),
1071 struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001072 builder_.PopBytes(struct_def.bytesize);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001073 assert(!ovalue);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001074 } else {
Wouter van Oortmerssenac1015e2017-08-21 13:44:23 -07001075 auto val = builder_.EndTable(start);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001076 if (ovalue) *ovalue = val;
1077 if (value) *value = NumToString(val);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001078 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001079 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001080}
1081
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001082CheckedError Parser::ParseVectorDelimiters(size_t &count,
Stewart Milesa8923222017-07-13 06:27:39 -07001083 ParseVectorDelimitersBody body,
1084 void *state) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001085 EXPECT('[');
Wouter van Oortmerssen6c2dc412015-01-16 16:57:04 -08001086 for (;;) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001087 if ((!opts.strict_json || !count) && Is(']')) break;
Stewart Milesa8923222017-07-13 06:27:39 -07001088 ECHECK(body(count, state));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001089 count++;
1090 if (Is(']')) break;
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -07001091 ECHECK(ParseComma());
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001092 }
1093 NEXT();
1094 return NoError();
1095}
1096
1097CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
1098 size_t count = 0;
Stewart Milesa8923222017-07-13 06:27:39 -07001099 std::pair<Parser *, const Type &> parser_and_type_state(this, type);
1100 auto err = ParseVectorDelimiters(count,
1101 [](size_t &, void *state) -> CheckedError {
1102 auto *parser_and_type =
1103 static_cast<std::pair<Parser *, const Type &> *>(state);
1104 auto *parser = parser_and_type->first;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001105 Value val;
Stewart Milesa8923222017-07-13 06:27:39 -07001106 val.type = parser_and_type->second;
1107 ECHECK(parser->ParseAnyValue(val, nullptr, 0, nullptr));
1108 parser->field_stack_.push_back(std::make_pair(val, nullptr));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001109 return NoError();
Stewart Milesa8923222017-07-13 06:27:39 -07001110 }, &parser_and_type_state);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001111 ECHECK(err);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001112
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -07001113 builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
1114 InlineAlignment(type));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001115 for (size_t i = 0; i < count; i++) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001116 // start at the back, since we're building the data backwards.
1117 auto &val = field_stack_.back().first;
1118 switch (val.type.base_type) {
MikkelFJf2b37052017-08-02 17:07:43 +02001119 #define FLATBUFFERS_TD(ENUM, IDLTYPE, ALIASTYPE, \
1120 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001121 case BASE_TYPE_ ## ENUM: \
1122 if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001123 else { \
1124 CTYPE elem; \
1125 ECHECK(atot(val.constant.c_str(), *this, &elem)); \
1126 builder_.PushElement(elem); \
1127 } \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001128 break;
1129 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1130 #undef FLATBUFFERS_TD
1131 }
1132 field_stack_.pop_back();
1133 }
1134
1135 builder_.ClearOffsets();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001136 *ovalue = builder_.EndVector(count);
1137 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001138}
1139
Christian Helmich89a68942017-07-29 02:27:51 +09001140CheckedError Parser::ParseNestedFlatbuffer(Value &val, FieldDef *field,
1141 size_t fieldn,
1142 const StructDef *parent_struct_def) {
1143 if (token_ == '[') {// backwards compat for 'legacy' ubyte buffers
1144 ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def));
1145 } else {
1146 auto cursor_at_value_begin = cursor_;
1147 ECHECK(SkipAnyJsonValue());
1148 std::string substring(cursor_at_value_begin -1 , cursor_ -1);
1149
1150 // Create and initialize new parser
1151 Parser nested_parser;
1152 assert(field->nested_flatbuffer);
1153 nested_parser.root_struct_def_ = field->nested_flatbuffer;
1154 nested_parser.enums_ = enums_;
1155 nested_parser.opts = opts;
1156 nested_parser.uses_flexbuffers_ = uses_flexbuffers_;
1157
1158 // Parse JSON substring into new flatbuffer builder using nested_parser
1159 if (!nested_parser.Parse(substring.c_str(), nullptr, nullptr)) {
1160 ECHECK(Error(nested_parser.error_));
1161 }
1162 auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(), nested_parser.builder_.GetSize());
1163 val.constant = NumToString(off.o);
1164
1165 // Clean nested_parser before destruction to avoid deleting the elements in the SymbolTables
1166 nested_parser.enums_.dict.clear();
1167 nested_parser.enums_.vec.clear();
1168 }
1169 return NoError();
1170}
1171
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001172CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001173 if (Is('(')) {
1174 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001175 for (;;) {
1176 auto name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001177 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen09521432014-11-17 17:27:26 -08001178 if (known_attributes_.find(name) == known_attributes_.end())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001179 return Error("user define attributes must be declared before use: " +
1180 name);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001181 auto e = new Value();
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001182 attributes->Add(name, e);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001183 if (Is(':')) {
1184 NEXT();
1185 ECHECK(ParseSingleValue(*e));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001186 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001187 if (Is(')')) { NEXT(); break; }
1188 EXPECT(',');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001189 }
1190 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001191 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001192}
1193
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001194CheckedError Parser::TryTypedValue(int dtoken, bool check, Value &e,
1195 BaseType req, bool *destmatch) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001196 bool match = dtoken == token_;
1197 if (match) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001198 *destmatch = true;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001199 e.constant = attribute_;
1200 if (!check) {
1201 if (e.type.base_type == BASE_TYPE_NONE) {
1202 e.type.base_type = req;
1203 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001204 return Error(std::string("type mismatch: expecting: ") +
1205 kTypeNames[e.type.base_type] +
1206 ", found: " +
1207 kTypeNames[req]);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001208 }
1209 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001210 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001211 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001212 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001213}
1214
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001215CheckedError Parser::ParseEnumFromString(Type &type, int64_t *result) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001216 *result = 0;
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001217 // Parse one or more enum identifiers, separated by spaces.
1218 const char *next = attribute_.c_str();
1219 do {
1220 const char *divider = strchr(next, ' ');
1221 std::string word;
1222 if (divider) {
1223 word = std::string(next, divider);
1224 next = divider + strspn(divider, " ");
1225 } else {
1226 word = next;
1227 next += word.length();
1228 }
1229 if (type.enum_def) { // The field has an enum type
1230 auto enum_val = type.enum_def->vals.Lookup(word);
1231 if (!enum_val)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001232 return Error("unknown enum value: " + word +
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001233 ", for enum: " + type.enum_def->name);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001234 *result |= enum_val->value;
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001235 } else { // No enum type, probably integral field.
1236 if (!IsInteger(type.base_type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001237 return Error("not a valid value for this field: " + word);
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001238 // TODO: could check if its a valid number constant here.
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -07001239 const char *dot = strrchr(word.c_str(), '.');
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001240 if (!dot)
1241 return Error("enum values need to be qualified by an enum type");
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001242 std::string enum_def_str(word.c_str(), dot);
1243 std::string enum_val_str(dot + 1, word.c_str() + word.length());
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -07001244 auto enum_def = LookupEnum(enum_def_str);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001245 if (!enum_def) return Error("unknown enum: " + enum_def_str);
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001246 auto enum_val = enum_def->vals.Lookup(enum_val_str);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001247 if (!enum_val) return Error("unknown enum value: " + enum_val_str);
1248 *result |= enum_val->value;
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001249 }
1250 } while(*next);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001251 return NoError();
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001252}
1253
Alex Amesd5753212015-02-13 15:58:29 -08001254
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001255CheckedError Parser::ParseHash(Value &e, FieldDef* field) {
Alex Amesd5753212015-02-13 15:58:29 -08001256 assert(field);
1257 Value *hash_name = field->attributes.Lookup("hash");
1258 switch (e.type.base_type) {
Wouter van Oortmerssen46497e42017-04-17 17:40:02 -07001259 case BASE_TYPE_INT: {
1260 auto hash = FindHashFunction32(hash_name->constant.c_str());
1261 int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
1262 e.constant = NumToString(hashed_value);
1263 break;
1264 }
Alex Amesd5753212015-02-13 15:58:29 -08001265 case BASE_TYPE_UINT: {
1266 auto hash = FindHashFunction32(hash_name->constant.c_str());
1267 uint32_t hashed_value = hash(attribute_.c_str());
1268 e.constant = NumToString(hashed_value);
1269 break;
1270 }
Wouter van Oortmerssen46497e42017-04-17 17:40:02 -07001271 case BASE_TYPE_LONG: {
1272 auto hash = FindHashFunction64(hash_name->constant.c_str());
1273 int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
1274 e.constant = NumToString(hashed_value);
1275 break;
1276 }
Alex Amesd5753212015-02-13 15:58:29 -08001277 case BASE_TYPE_ULONG: {
1278 auto hash = FindHashFunction64(hash_name->constant.c_str());
1279 uint64_t hashed_value = hash(attribute_.c_str());
1280 e.constant = NumToString(hashed_value);
1281 break;
1282 }
1283 default:
1284 assert(0);
1285 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001286 NEXT();
1287 return NoError();
Alex Amesd5753212015-02-13 15:58:29 -08001288}
1289
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001290CheckedError Parser::TokenError() {
1291 return Error("cannot parse value starting with: " +
1292 TokenToStringId(token_));
1293}
1294
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001295CheckedError Parser::ParseSingleValue(Value &e) {
Wouter van Oortmerssend3ac0bc2016-06-15 13:54:17 -07001296 // First see if this could be a conversion function:
1297 if (token_ == kTokenIdentifier && *cursor_ == '(') {
1298 auto functionname = attribute_;
1299 NEXT();
1300 EXPECT('(');
1301 ECHECK(ParseSingleValue(e));
1302 EXPECT(')');
1303 #define FLATBUFFERS_FN_DOUBLE(name, op) \
1304 if (functionname == name) { \
1305 auto x = strtod(e.constant.c_str(), nullptr); \
1306 e.constant = NumToString(op); \
1307 }
1308 FLATBUFFERS_FN_DOUBLE("deg", x / M_PI * 180);
1309 FLATBUFFERS_FN_DOUBLE("rad", x * M_PI / 180);
1310 FLATBUFFERS_FN_DOUBLE("sin", sin(x));
1311 FLATBUFFERS_FN_DOUBLE("cos", cos(x));
1312 FLATBUFFERS_FN_DOUBLE("tan", tan(x));
1313 FLATBUFFERS_FN_DOUBLE("asin", asin(x));
1314 FLATBUFFERS_FN_DOUBLE("acos", acos(x));
1315 FLATBUFFERS_FN_DOUBLE("atan", atan(x));
1316 // TODO(wvo): add more useful conversion functions here.
1317 #undef FLATBUFFERS_FN_DOUBLE
1318 // Then check if this could be a string/identifier enum value:
1319 } else if (e.type.base_type != BASE_TYPE_STRING &&
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001320 e.type.base_type != BASE_TYPE_NONE &&
1321 (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001322 if (IsIdentifierStart(attribute_[0])) { // Enum value.
1323 int64_t val;
1324 ECHECK(ParseEnumFromString(e.type, &val));
1325 e.constant = NumToString(val);
1326 NEXT();
1327 } else { // Numeric constant in string.
1328 if (IsInteger(e.type.base_type)) {
Sahil Jainb6ba3222016-08-25 23:37:30 -04001329 char *end;
1330 e.constant = NumToString(StringToInt(attribute_.c_str(), &end));
1331 if (*end)
1332 return Error("invalid integer: " + attribute_);
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001333 } else if (IsFloat(e.type.base_type)) {
Sahil Jainb6ba3222016-08-25 23:37:30 -04001334 char *end;
1335 e.constant = NumToString(strtod(attribute_.c_str(), &end));
1336 if (*end)
1337 return Error("invalid float: " + attribute_);
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001338 } else {
1339 assert(0); // Shouldn't happen, we covered all types.
1340 e.constant = "0";
1341 }
Wouter van Oortmerssen83dc5ed2016-04-11 11:08:09 -07001342 NEXT();
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001343 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001344 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001345 bool match = false;
1346 ECHECK(TryTypedValue(kTokenIntegerConstant,
1347 IsScalar(e.type.base_type),
1348 e,
1349 BASE_TYPE_INT,
1350 &match));
rouziera2b1bfc2017-08-04 11:04:28 -04001351 ECHECK(TryTypedValue(kTokenBooleanConstant,
1352 IsBool(e.type.base_type),
1353 e,
1354 BASE_TYPE_BOOL,
1355 &match));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001356 ECHECK(TryTypedValue(kTokenFloatConstant,
1357 IsFloat(e.type.base_type),
1358 e,
1359 BASE_TYPE_FLOAT,
1360 &match));
1361 ECHECK(TryTypedValue(kTokenStringConstant,
1362 e.type.base_type == BASE_TYPE_STRING,
1363 e,
1364 BASE_TYPE_STRING,
1365 &match));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001366 if (!match) return TokenError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001367 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001368 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001369}
1370
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001371StructDef *Parser::LookupCreateStruct(const std::string &name,
1372 bool create_if_new, bool definition) {
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001373 std::string qualified_name = current_namespace_->GetFullyQualifiedName(name);
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001374 // See if it exists pre-declared by an unqualified use.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001375 auto struct_def = structs_.Lookup(name);
1376 if (struct_def && struct_def->predecl) {
1377 if (definition) {
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001378 // Make sure it has the current namespace, and is registered under its
1379 // qualified name.
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001380 struct_def->defined_namespace = current_namespace_;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001381 structs_.Move(name, qualified_name);
1382 }
1383 return struct_def;
1384 }
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001385 // See if it exists pre-declared by an qualified use.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001386 struct_def = structs_.Lookup(qualified_name);
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001387 if (struct_def && struct_def->predecl) {
1388 if (definition) {
1389 // Make sure it has the current namespace.
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001390 struct_def->defined_namespace = current_namespace_;
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001391 }
1392 return struct_def;
1393 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001394 if (!definition) {
1395 // Search thru parent namespaces.
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001396 for (size_t components = current_namespace_->components.size();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001397 components && !struct_def; components--) {
1398 struct_def = structs_.Lookup(
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001399 current_namespace_->GetFullyQualifiedName(name, components - 1));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001400 }
1401 }
1402 if (!struct_def && create_if_new) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001403 struct_def = new StructDef();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001404 if (definition) {
1405 structs_.Add(qualified_name, struct_def);
1406 struct_def->name = name;
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001407 struct_def->defined_namespace = current_namespace_;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001408 } else {
1409 // Not a definition.
1410 // Rather than failing, we create a "pre declared" StructDef, due to
1411 // circular references, and check for errors at the end of parsing.
1412 // It is defined in the root namespace, since we don't know what the
1413 // final namespace will be.
1414 // TODO: maybe safer to use special namespace?
1415 structs_.Add(name, struct_def);
1416 struct_def->name = name;
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001417 struct_def->defined_namespace = empty_namespace_;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001418 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001419 }
1420 return struct_def;
1421}
1422
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001423CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
Max Galkinc3807fa2015-03-07 08:49:55 -08001424 std::vector<std::string> enum_comment = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001425 NEXT();
Max Galkinc3807fa2015-03-07 08:49:55 -08001426 std::string enum_name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001427 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001428 auto &enum_def = *new EnumDef();
Max Galkinc3807fa2015-03-07 08:49:55 -08001429 enum_def.name = enum_name;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001430 enum_def.file = file_being_parsed_;
Max Galkinc3807fa2015-03-07 08:49:55 -08001431 enum_def.doc_comment = enum_comment;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001432 enum_def.is_union = is_union;
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001433 enum_def.defined_namespace = current_namespace_;
1434 if (enums_.Add(current_namespace_->GetFullyQualifiedName(enum_name),
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001435 &enum_def))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001436 return Error("enum already exists: " + enum_name);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001437 if (is_union) {
1438 enum_def.underlying_type.base_type = BASE_TYPE_UTYPE;
1439 enum_def.underlying_type.enum_def = &enum_def;
Wouter van Oortmerssena5f50012014-07-02 12:01:21 -07001440 } else {
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -08001441 if (opts.proto_mode) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001442 enum_def.underlying_type.base_type = BASE_TYPE_INT;
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001443 } else {
1444 // Give specialized error message, since this type spec used to
1445 // be optional in the first FlatBuffers release.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001446 if (!Is(':')) {
1447 return Error("must specify the underlying integer type for this"
1448 " enum (e.g. \': short\', which was the default).");
1449 } else {
1450 NEXT();
1451 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001452 // Specify the integer type underlying this enum.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001453 ECHECK(ParseType(enum_def.underlying_type));
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001454 if (!IsInteger(enum_def.underlying_type.base_type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001455 return Error("underlying enum type must be integral");
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001456 }
Wouter van Oortmerssen3fb6a862014-07-14 17:49:04 -07001457 // Make this type refer back to the enum it was derived from.
1458 enum_def.underlying_type.enum_def = &enum_def;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001459 }
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001460 ECHECK(ParseMetaData(&enum_def.attributes));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001461 EXPECT('{');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001462 if (is_union) enum_def.vals.Add("NONE", new EnumVal("NONE", 0));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001463 for (;;) {
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -08001464 if (opts.proto_mode && attribute_ == "option") {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001465 ECHECK(ParseProtoOption());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001466 } else {
1467 auto value_name = attribute_;
1468 auto full_name = value_name;
1469 std::vector<std::string> value_comment = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001470 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen36390322016-06-17 18:16:11 -07001471 if (is_union) {
1472 ECHECK(ParseNamespacing(&full_name, &value_name));
Wouter van Oortmerssend70f5ac2016-07-29 10:45:32 -07001473 if (opts.union_value_namespacing) {
1474 // Since we can't namespace the actual enum identifiers, turn
1475 // namespace parts into part of the identifier.
1476 value_name = full_name;
1477 std::replace(value_name.begin(), value_name.end(), '.', '_');
1478 }
Wouter van Oortmerssen36390322016-06-17 18:16:11 -07001479 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001480 auto prevsize = enum_def.vals.vec.size();
1481 auto value = enum_def.vals.vec.size()
1482 ? enum_def.vals.vec.back()->value + 1
1483 : 0;
1484 auto &ev = *new EnumVal(value_name, value);
1485 if (enum_def.vals.Add(value_name, &ev))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001486 return Error("enum value already exists: " + value_name);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001487 ev.doc_comment = value_comment;
1488 if (is_union) {
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -07001489 if (Is(':')) {
1490 NEXT();
1491 ECHECK(ParseType(ev.union_type));
1492 if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
1493 ev.union_type.base_type != BASE_TYPE_STRING)
1494 return Error("union value type may only be table/struct/string");
1495 enum_def.uses_type_aliases = true;
1496 } else {
1497 ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
1498 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001499 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001500 if (Is('=')) {
1501 NEXT();
Wouter van Oortmerssend7793082016-02-10 11:25:31 -08001502 ev.value = StringToInt(attribute_.c_str());
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001503 EXPECT(kTokenIntegerConstant);
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -08001504 if (!opts.proto_mode && prevsize &&
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001505 enum_def.vals.vec[prevsize - 1]->value >= ev.value)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001506 return Error("enum values must be specified in ascending order");
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001507 }
Wouter van Oortmerssen9d01bfa2017-05-10 17:21:47 -07001508 if (is_union) {
1509 if (ev.value < 0 || ev.value >= 256)
1510 return Error("union enum value must fit in a ubyte");
1511 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001512 if (opts.proto_mode && Is('[')) {
1513 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001514 // ignore attributes on enums.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001515 while (token_ != ']') NEXT();
1516 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001517 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001518 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001519 if (!Is(opts.proto_mode ? ';' : ',')) break;
1520 NEXT();
1521 if (Is('}')) break;
1522 }
1523 EXPECT('}');
Wouter van Oortmerssen127d3502014-07-17 15:12:37 -07001524 if (enum_def.attributes.Lookup("bit_flags")) {
1525 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
1526 ++it) {
1527 if (static_cast<size_t>((*it)->value) >=
1528 SizeOf(enum_def.underlying_type.base_type) * 8)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001529 return Error("bit flag out of range of underlying integral type");
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001530 (*it)->value = 1LL << (*it)->value;
Wouter van Oortmerssen127d3502014-07-17 15:12:37 -07001531 }
1532 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001533 if (dest) *dest = &enum_def;
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001534 types_.Add(current_namespace_->GetFullyQualifiedName(enum_def.name),
Wouter van Oortmerssen9b3d8b32017-01-27 15:28:57 -08001535 new Type(BASE_TYPE_UNION, nullptr, &enum_def));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001536 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001537}
1538
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001539CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001540 auto &struct_def = *LookupCreateStruct(name, true, true);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001541 if (!struct_def.predecl) return Error("datatype already exists: " + name);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001542 struct_def.predecl = false;
1543 struct_def.name = name;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001544 struct_def.file = file_being_parsed_;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001545 // Move this struct to the back of the vector just in case it was predeclared,
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001546 // to preserve declaration order.
Dmitry Ermolov370693a2017-04-20 02:55:41 +03001547 *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001548 *dest = &struct_def;
1549 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001550}
1551
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001552CheckedError Parser::CheckClash(std::vector<FieldDef*> &fields,
1553 StructDef *struct_def,
1554 const char *suffix,
1555 BaseType basetype) {
1556 auto len = strlen(suffix);
1557 for (auto it = fields.begin(); it != fields.end(); ++it) {
1558 auto &fname = (*it)->name;
1559 if (fname.length() > len &&
1560 fname.compare(fname.length() - len, len, suffix) == 0 &&
1561 (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
1562 auto field = struct_def->fields.Lookup(
1563 fname.substr(0, fname.length() - len));
1564 if (field && field->value.type.base_type == basetype)
1565 return Error("Field " + fname +
1566 " would clash with generated functions for field " +
1567 field->name);
1568 }
1569 }
1570 return NoError();
1571}
Wouter van Oortmerssend7793082016-02-10 11:25:31 -08001572
Kamil Rojewski46bb05d2017-08-11 18:24:36 +02001573bool Parser::SupportsVectorOfUnions() const {
1574 return opts.lang_to_generate != 0 && (opts.lang_to_generate &
1575 ~(IDLOptions::kCpp | IDLOptions::kJs | IDLOptions::kTs | IDLOptions::kPhp)) == 0;
1576}
1577
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001578Namespace *Parser::UniqueNamespace(Namespace *ns) {
1579 for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) {
1580 if (ns->components == (*it)->components) {
1581 delete ns;
1582 return *it;
1583 }
1584 }
1585 namespaces_.push_back(ns);
1586 return ns;
1587}
1588
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001589static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
1590 auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
1591 auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
1592 return a_id < b_id;
1593}
1594
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001595CheckedError Parser::ParseDecl() {
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001596 std::vector<std::string> dc = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001597 bool fixed = Is(kTokenStruct);
1598 if (fixed) NEXT() else EXPECT(kTokenTable);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001599 std::string name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001600 EXPECT(kTokenIdentifier);
1601 StructDef *struct_def;
1602 ECHECK(StartStruct(name, &struct_def));
1603 struct_def->doc_comment = dc;
1604 struct_def->fixed = fixed;
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001605 ECHECK(ParseMetaData(&struct_def->attributes));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001606 struct_def->sortbysize =
1607 struct_def->attributes.Lookup("original_order") == nullptr && !fixed;
1608 EXPECT('{');
1609 while (token_ != '}') ECHECK(ParseField(*struct_def));
1610 auto force_align = struct_def->attributes.Lookup("force_align");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001611 if (fixed && force_align) {
1612 auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
1613 if (force_align->type.base_type != BASE_TYPE_INT ||
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001614 align < struct_def->minalign ||
Wouter van Oortmerssen6862b2f2016-10-17 18:02:19 -07001615 align > FLATBUFFERS_MAX_ALIGNMENT ||
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001616 align & (align - 1))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001617 return Error("force_align must be a power of two integer ranging from the"
Wouter van Oortmerssen6862b2f2016-10-17 18:02:19 -07001618 "struct\'s natural alignment to " +
1619 NumToString(FLATBUFFERS_MAX_ALIGNMENT));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001620 struct_def->minalign = align;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001621 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001622 struct_def->PadLastField(struct_def->minalign);
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001623 // Check if this is a table that has manual id assignments
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001624 auto &fields = struct_def->fields.vec;
1625 if (!struct_def->fixed && fields.size()) {
Wouter van Oortmerssen7fcbe722014-07-08 16:35:14 -07001626 size_t num_id_fields = 0;
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001627 for (auto it = fields.begin(); it != fields.end(); ++it) {
1628 if ((*it)->attributes.Lookup("id")) num_id_fields++;
1629 }
1630 // If any fields have ids..
1631 if (num_id_fields) {
1632 // Then all fields must have them.
1633 if (num_id_fields != fields.size())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001634 return Error(
1635 "either all fields or no fields must have an 'id' attribute");
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001636 // Simply sort by id, then the fields are the same as if no ids had
1637 // been specified.
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001638 std::sort(fields.begin(), fields.end(), compareFieldDefs);
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001639 // Verify we have a contiguous set, and reassign vtable offsets.
1640 for (int i = 0; i < static_cast<int>(fields.size()); i++) {
1641 if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str()))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001642 return Error("field id\'s must be consecutive from 0, id " +
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001643 NumToString(i) + " missing or set twice");
1644 fields[i]->value.offset = FieldIndexToOffset(static_cast<voffset_t>(i));
1645 }
1646 }
1647 }
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001648
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -07001649 ECHECK(CheckClash(fields, struct_def, UnionTypeFieldSuffix(),
1650 BASE_TYPE_UNION));
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001651 ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION));
1652 ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR));
1653 ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR));
1654 ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
1655 ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001656 EXPECT('}');
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001657 types_.Add(current_namespace_->GetFullyQualifiedName(struct_def->name),
Wouter van Oortmerssen9b3d8b32017-01-27 15:28:57 -08001658 new Type(BASE_TYPE_STRUCT, struct_def, nullptr));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001659 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001660}
1661
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001662CheckedError Parser::ParseService() {
1663 std::vector<std::string> service_comment = doc_comment_;
1664 NEXT();
1665 auto service_name = attribute_;
1666 EXPECT(kTokenIdentifier);
1667 auto &service_def = *new ServiceDef();
1668 service_def.name = service_name;
1669 service_def.file = file_being_parsed_;
1670 service_def.doc_comment = service_comment;
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001671 service_def.defined_namespace = current_namespace_;
1672 if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name),
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001673 &service_def))
1674 return Error("service already exists: " + service_name);
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001675 ECHECK(ParseMetaData(&service_def.attributes));
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001676 EXPECT('{');
1677 do {
1678 auto rpc_name = attribute_;
1679 EXPECT(kTokenIdentifier);
1680 EXPECT('(');
1681 Type reqtype, resptype;
1682 ECHECK(ParseTypeIdent(reqtype));
1683 EXPECT(')');
1684 EXPECT(':');
1685 ECHECK(ParseTypeIdent(resptype));
1686 if (reqtype.base_type != BASE_TYPE_STRUCT || reqtype.struct_def->fixed ||
1687 resptype.base_type != BASE_TYPE_STRUCT || resptype.struct_def->fixed)
1688 return Error("rpc request and response types must be tables");
1689 auto &rpc = *new RPCCall();
1690 rpc.name = rpc_name;
1691 rpc.request = reqtype.struct_def;
1692 rpc.response = resptype.struct_def;
1693 if (service_def.calls.Add(rpc_name, &rpc))
1694 return Error("rpc already exists: " + rpc_name);
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001695 ECHECK(ParseMetaData(&rpc.attributes));
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001696 EXPECT(';');
1697 } while (token_ != '}');
1698 NEXT();
1699 return NoError();
1700}
1701
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001702bool Parser::SetRootType(const char *name) {
Wouter van Oortmerssen4dcaec72015-12-09 16:41:12 -08001703 root_struct_def_ = structs_.Lookup(name);
1704 if (!root_struct_def_)
1705 root_struct_def_ = structs_.Lookup(
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001706 current_namespace_->GetFullyQualifiedName(name));
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07001707 return root_struct_def_ != nullptr;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001708}
1709
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001710void Parser::MarkGenerated() {
Wouter van Oortmerssen3881bbd2015-11-30 16:42:48 -08001711 // This function marks all existing definitions as having already
1712 // been generated, which signals no code for included files should be
1713 // generated.
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001714 for (auto it = enums_.vec.begin();
1715 it != enums_.vec.end(); ++it) {
1716 (*it)->generated = true;
1717 }
1718 for (auto it = structs_.vec.begin();
1719 it != structs_.vec.end(); ++it) {
Robbie McElrath0e85eee2017-06-26 09:07:02 -07001720 if (!(*it)->predecl) {
1721 (*it)->generated = true;
1722 }
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001723 }
Wouter van Oortmerssen48f37f92016-04-13 18:16:05 -07001724 for (auto it = services_.vec.begin();
1725 it != services_.vec.end(); ++it) {
1726 (*it)->generated = true;
1727 }
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001728}
1729
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001730CheckedError Parser::ParseNamespace() {
1731 NEXT();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001732 auto ns = new Namespace();
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001733 namespaces_.push_back(ns); // Store it here to not leak upon error.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001734 if (token_ != ';') {
1735 for (;;) {
1736 ns->components.push_back(attribute_);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001737 EXPECT(kTokenIdentifier);
1738 if (Is('.')) NEXT() else break;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001739 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001740 }
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001741 namespaces_.pop_back();
1742 current_namespace_ = UniqueNamespace(ns);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001743 EXPECT(';');
1744 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001745}
1746
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001747static bool compareEnumVals(const EnumVal *a, const EnumVal* b) {
1748 return a->value < b->value;
1749}
1750
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001751// Best effort parsing of .proto declarations, with the aim to turn them
1752// in the closest corresponding FlatBuffer equivalent.
1753// We parse everything as identifiers instead of keywords, since we don't
1754// want protobuf keywords to become invalid identifiers in FlatBuffers.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001755CheckedError Parser::ParseProtoDecl() {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001756 bool isextend = attribute_ == "extend";
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001757 if (attribute_ == "package") {
1758 // These are identical in syntax to FlatBuffer's namespace decl.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001759 ECHECK(ParseNamespace());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001760 } else if (attribute_ == "message" || isextend) {
Advay Mengle3ad85362015-03-31 02:03:11 -07001761 std::vector<std::string> struct_comment = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001762 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001763 StructDef *struct_def = nullptr;
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001764 Namespace *parent_namespace = nullptr;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001765 if (isextend) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001766 if (Is('.')) NEXT(); // qualified names may start with a . ?
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001767 auto id = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001768 EXPECT(kTokenIdentifier);
1769 ECHECK(ParseNamespacing(&id, nullptr));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001770 struct_def = LookupCreateStruct(id, false);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001771 if (!struct_def)
1772 return Error("cannot extend unknown message type: " + id);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001773 } else {
1774 std::string name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001775 EXPECT(kTokenIdentifier);
1776 ECHECK(StartStruct(name, &struct_def));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001777 // Since message definitions can be nested, we create a new namespace.
1778 auto ns = new Namespace();
1779 // Copy of current namespace.
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001780 *ns = *current_namespace_;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001781 // But with current message name.
1782 ns->components.push_back(name);
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001783 parent_namespace = current_namespace_;
1784 current_namespace_ = UniqueNamespace(ns);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001785 }
1786 struct_def->doc_comment = struct_comment;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001787 ECHECK(ParseProtoFields(struct_def, isextend, false));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001788 if (!isextend) {
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001789 current_namespace_ = parent_namespace;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001790 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001791 if (Is(';')) NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001792 } else if (attribute_ == "enum") {
1793 // These are almost the same, just with different terminator:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001794 EnumDef *enum_def;
1795 ECHECK(ParseEnum(false, &enum_def));
1796 if (Is(';')) NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001797 // Protobuf allows them to be specified in any order, so sort afterwards.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001798 auto &v = enum_def->vals.vec;
Wouter van Oortmerssend7793082016-02-10 11:25:31 -08001799 std::sort(v.begin(), v.end(), compareEnumVals);
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001800
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001801 // Temp: remove any duplicates, as .fbs files can't handle them.
1802 for (auto it = v.begin(); it != v.end(); ) {
1803 if (it != v.begin() && it[0]->value == it[-1]->value) it = v.erase(it);
1804 else ++it;
1805 }
1806 } else if (attribute_ == "syntax") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001807 NEXT();
1808 EXPECT('=');
1809 EXPECT(kTokenStringConstant);
1810 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001811 } else if (attribute_ == "option") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001812 ECHECK(ParseProtoOption());
1813 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001814 } else if (attribute_ == "service") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001815 NEXT();
1816 EXPECT(kTokenIdentifier);
1817 ECHECK(ParseProtoCurliesOrIdent());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001818 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001819 return Error("don\'t know how to parse .proto declaration starting with " +
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001820 TokenToStringId(token_));
1821 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001822 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001823}
1824
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001825CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend,
1826 bool inside_oneof) {
1827 EXPECT('{');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001828 while (token_ != '}') {
1829 if (attribute_ == "message" || attribute_ == "extend" ||
1830 attribute_ == "enum") {
1831 // Nested declarations.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001832 ECHECK(ParseProtoDecl());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001833 } else if (attribute_ == "extensions") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001834 NEXT();
1835 EXPECT(kTokenIntegerConstant);
1836 if (Is(kTokenIdentifier)) {
1837 NEXT(); // to
1838 NEXT(); // num
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001839 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001840 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001841 } else if (attribute_ == "option") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001842 ECHECK(ParseProtoOption());
1843 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001844 } else if (attribute_ == "reserved") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001845 NEXT();
1846 EXPECT(kTokenIntegerConstant);
1847 while (Is(',')) { NEXT(); EXPECT(kTokenIntegerConstant); }
1848 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001849 } else {
1850 std::vector<std::string> field_comment = doc_comment_;
1851 // Parse the qualifier.
1852 bool required = false;
1853 bool repeated = false;
1854 bool oneof = false;
1855 if (!inside_oneof) {
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001856 if (attribute_ == "optional") {
1857 // This is the default.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001858 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001859 } else if (attribute_ == "required") {
1860 required = true;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001861 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001862 } else if (attribute_ == "repeated") {
1863 repeated = true;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001864 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001865 } else if (attribute_ == "oneof") {
1866 oneof = true;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001867 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001868 } else {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001869 // can't error, proto3 allows decls without any of the above.
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001870 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001871 }
1872 StructDef *anonymous_struct = nullptr;
1873 Type type;
1874 if (attribute_ == "group" || oneof) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001875 if (!oneof) EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001876 auto name = "Anonymous" + NumToString(anonymous_counter++);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001877 ECHECK(StartStruct(name, &anonymous_struct));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001878 type = Type(BASE_TYPE_STRUCT, anonymous_struct);
1879 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001880 ECHECK(ParseTypeFromProtoType(&type));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001881 }
1882 // Repeated elements get mapped to a vector.
1883 if (repeated) {
1884 type.element = type.base_type;
1885 type.base_type = BASE_TYPE_VECTOR;
1886 }
1887 std::string name = attribute_;
1888 // Protos may use our keywords "attribute" & "namespace" as an identifier.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001889 if (Is(kTokenAttribute) || Is(kTokenNameSpace)) {
1890 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001891 // TODO: simpler to just not make these keywords?
1892 name += "_"; // Have to make it not a keyword.
1893 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001894 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001895 }
1896 if (!oneof) {
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001897 // Parse the field id. Since we're just translating schemas, not
1898 // any kind of binary compatibility, we can safely ignore these, and
1899 // assign our own.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001900 EXPECT('=');
1901 EXPECT(kTokenIntegerConstant);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001902 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001903 FieldDef *field = nullptr;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001904 if (isextend) {
1905 // We allow a field to be re-defined when extending.
1906 // TODO: are there situations where that is problematic?
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001907 field = struct_def->fields.Lookup(name);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001908 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001909 if (!field) ECHECK(AddField(*struct_def, name, type, &field));
1910 field->doc_comment = field_comment;
1911 if (!IsScalar(type.base_type)) field->required = required;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001912 // See if there's a default specified.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001913 if (Is('[')) {
1914 NEXT();
1915 for (;;) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001916 auto key = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001917 ECHECK(ParseProtoKey());
1918 EXPECT('=');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001919 auto val = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001920 ECHECK(ParseProtoCurliesOrIdent());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001921 if (key == "default") {
1922 // Temp: skip non-numeric defaults (enums).
1923 auto numeric = strpbrk(val.c_str(), "0123456789-+.");
1924 if (IsScalar(type.base_type) && numeric == val.c_str())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001925 field->value.constant = val;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001926 } else if (key == "deprecated") {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001927 field->deprecated = val == "true";
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001928 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001929 if (!Is(',')) break;
1930 NEXT();
1931 }
1932 EXPECT(']');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001933 }
1934 if (anonymous_struct) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001935 ECHECK(ParseProtoFields(anonymous_struct, false, oneof));
1936 if (Is(';')) NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001937 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001938 EXPECT(';');
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001939 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001940 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001941 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001942 NEXT();
1943 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001944}
1945
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001946CheckedError Parser::ParseProtoKey() {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001947 if (token_ == '(') {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001948 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001949 // Skip "(a.b)" style custom attributes.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001950 while (token_ == '.' || token_ == kTokenIdentifier) NEXT();
1951 EXPECT(')');
1952 while (Is('.')) { NEXT(); EXPECT(kTokenIdentifier); }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001953 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001954 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001955 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001956 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001957}
1958
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001959CheckedError Parser::ParseProtoCurliesOrIdent() {
1960 if (Is('{')) {
1961 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001962 for (int nesting = 1; nesting; ) {
1963 if (token_ == '{') nesting++;
1964 else if (token_ == '}') nesting--;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001965 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001966 }
1967 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001968 NEXT(); // Any single token.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001969 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001970 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001971}
1972
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001973CheckedError Parser::ParseProtoOption() {
1974 NEXT();
1975 ECHECK(ParseProtoKey());
1976 EXPECT('=');
1977 ECHECK(ParseProtoCurliesOrIdent());
1978 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001979}
1980
1981// Parse a protobuf type, and map it to the corresponding FlatBuffer one.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001982CheckedError Parser::ParseTypeFromProtoType(Type *type) {
Wouter van Oortmerssen69776b92017-08-14 14:45:29 -07001983 struct type_lookup { const char *proto_type; BaseType fb_type, element; };
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001984 static type_lookup lookup[] = {
Wouter van Oortmerssen69776b92017-08-14 14:45:29 -07001985 { "float", BASE_TYPE_FLOAT, BASE_TYPE_NONE },
1986 { "double", BASE_TYPE_DOUBLE, BASE_TYPE_NONE },
1987 { "int32", BASE_TYPE_INT, BASE_TYPE_NONE },
1988 { "int64", BASE_TYPE_LONG, BASE_TYPE_NONE },
1989 { "uint32", BASE_TYPE_UINT, BASE_TYPE_NONE },
1990 { "uint64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
1991 { "sint32", BASE_TYPE_INT, BASE_TYPE_NONE },
1992 { "sint64", BASE_TYPE_LONG, BASE_TYPE_NONE },
1993 { "fixed32", BASE_TYPE_UINT, BASE_TYPE_NONE },
1994 { "fixed64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
1995 { "sfixed32", BASE_TYPE_INT, BASE_TYPE_NONE },
1996 { "sfixed64", BASE_TYPE_LONG, BASE_TYPE_NONE },
1997 { "bool", BASE_TYPE_BOOL, BASE_TYPE_NONE },
1998 { "string", BASE_TYPE_STRING, BASE_TYPE_NONE },
1999 { "bytes", BASE_TYPE_VECTOR, BASE_TYPE_UCHAR },
2000 { nullptr, BASE_TYPE_NONE, BASE_TYPE_NONE }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07002001 };
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07002002 for (auto tl = lookup; tl->proto_type; tl++) {
2003 if (attribute_ == tl->proto_type) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002004 type->base_type = tl->fb_type;
Wouter van Oortmerssen69776b92017-08-14 14:45:29 -07002005 type->element = tl->element;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002006 NEXT();
2007 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07002008 }
2009 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002010 if (Is('.')) NEXT(); // qualified names may start with a . ?
2011 ECHECK(ParseTypeIdent(*type));
2012 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07002013}
2014
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002015CheckedError Parser::SkipAnyJsonValue() {
2016 switch (token_) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002017 case '{': {
Stewart Milesa8923222017-07-13 06:27:39 -07002018 size_t fieldn_outer = 0;
2019 return ParseTableDelimiters(fieldn_outer, nullptr,
2020 [](const std::string &,
2021 size_t &fieldn, const StructDef *,
2022 void *state) -> CheckedError {
2023 auto *parser = static_cast<Parser *>(state);
2024 ECHECK(parser->SkipAnyJsonValue());
2025 fieldn++;
2026 return NoError();
2027 },
2028 this);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002029 }
2030 case '[': {
2031 size_t count = 0;
Stewart Milesa8923222017-07-13 06:27:39 -07002032 return ParseVectorDelimiters(count, [](size_t &,
2033 void *state) -> CheckedError {
2034 return static_cast<Parser *>(state)->SkipAnyJsonValue();
2035 },
2036 this);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002037 }
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002038 case kTokenStringConstant:
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002039 EXPECT(kTokenStringConstant);
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002040 break;
2041 case kTokenIntegerConstant:
2042 EXPECT(kTokenIntegerConstant);
2043 break;
2044 case kTokenFloatConstant:
2045 EXPECT(kTokenFloatConstant);
2046 break;
rouziera2b1bfc2017-08-04 11:04:28 -04002047 case kTokenBooleanConstant:
2048 EXPECT(kTokenBooleanConstant);
2049 break;
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002050 default:
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002051 return TokenError();
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002052 }
2053 return NoError();
2054}
2055
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002056CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
2057 switch (token_) {
2058 case '{': {
Stewart Milesa8923222017-07-13 06:27:39 -07002059 std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state(
2060 this, builder);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002061 auto start = builder->StartMap();
Stewart Milesa8923222017-07-13 06:27:39 -07002062 size_t fieldn_outer = 0;
2063 auto err = ParseTableDelimiters(fieldn_outer, nullptr,
2064 [](const std::string &name,
2065 size_t &fieldn, const StructDef *,
2066 void *state) -> CheckedError {
2067 auto *parser_and_builder =
2068 static_cast<std::pair<Parser *, flexbuffers::Builder *> *>(
2069 state);
2070 auto *parser = parser_and_builder->first;
2071 auto *current_builder = parser_and_builder->second;
2072 current_builder->Key(name);
2073 ECHECK(parser->ParseFlexBufferValue(current_builder));
2074 fieldn++;
2075 return NoError();
2076 },
2077 &parser_and_builder_state);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002078 ECHECK(err);
2079 builder->EndMap(start);
2080 break;
Nalinichandra Penkecbab2662016-02-22 14:27:08 -06002081 }
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002082 case '[':{
2083 auto start = builder->StartVector();
2084 size_t count = 0;
Stewart Milesa8923222017-07-13 06:27:39 -07002085 std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state(
2086 this, builder);
2087 ECHECK(ParseVectorDelimiters(count, [](size_t &,
2088 void *state) -> CheckedError {
2089 auto *parser_and_builder =
2090 static_cast<std::pair<Parser *, flexbuffers::Builder *> *>(
2091 state);
2092 return parser_and_builder->first->ParseFlexBufferValue(
2093 parser_and_builder->second);
2094 },
2095 &parser_and_builder_state));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002096 builder->EndVector(start, false, false);
2097 break;
Nalinichandra Penkecbab2662016-02-22 14:27:08 -06002098 }
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002099 case kTokenStringConstant:
2100 builder->String(attribute_);
2101 EXPECT(kTokenStringConstant);
2102 break;
2103 case kTokenIntegerConstant:
2104 builder->Int(StringToInt(attribute_.c_str()));
2105 EXPECT(kTokenIntegerConstant);
2106 break;
rouziera2b1bfc2017-08-04 11:04:28 -04002107 case kTokenBooleanConstant:
2108 builder->Bool(StringToInt(attribute_.c_str()) != 0);
2109 EXPECT(kTokenBooleanConstant);
2110 break;
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002111 case kTokenFloatConstant:
2112 builder->Double(strtod(attribute_.c_str(), nullptr));
2113 EXPECT(kTokenFloatConstant);
2114 break;
2115 default:
2116 return TokenError();
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002117 }
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002118 return NoError();
2119}
2120
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002121bool Parser::ParseFlexBuffer(const char *source, const char *source_filename,
2122 flexbuffers::Builder *builder) {
2123 auto ok = !StartParseFile(source, source_filename).Check() &&
2124 !ParseFlexBufferValue(builder).Check();
2125 if (ok) builder->Finish();
2126 return ok;
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002127}
2128
Wouter van Oortmerssen30642c52014-09-22 15:49:43 -07002129bool Parser::Parse(const char *source, const char **include_paths,
2130 const char *source_filename) {
Robbie McElrath0e85eee2017-06-26 09:07:02 -07002131 return !ParseRoot(source, include_paths, source_filename).Check();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002132}
2133
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002134CheckedError Parser::StartParseFile(const char *source, const char *source_filename) {
2135 file_being_parsed_ = source_filename ? source_filename : "";
2136 source_ = cursor_ = source;
2137 line_ = 1;
2138 error_.clear();
2139 ECHECK(SkipByteOrderMark());
2140 NEXT();
2141 if (Is(kTokenEof))
2142 return Error("input file is empty");
2143 return NoError();
2144}
2145
Robbie McElrath0e85eee2017-06-26 09:07:02 -07002146CheckedError Parser::ParseRoot(const char *source, const char **include_paths,
2147 const char *source_filename) {
2148 ECHECK(DoParse(source, include_paths, source_filename, nullptr));
2149
2150 // Check that all types were defined.
2151 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
2152 if ((*it)->predecl) {
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07002153 return Error("type referenced but not defined (check namespace): " +
2154 (*it)->name);
Robbie McElrath0e85eee2017-06-26 09:07:02 -07002155 }
2156 }
2157
2158 // This check has to happen here and not earlier, because only now do we
2159 // know for sure what the type of these are.
2160 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
2161 auto &enum_def = **it;
2162 if (enum_def.is_union) {
2163 for (auto val_it = enum_def.vals.vec.begin();
2164 val_it != enum_def.vals.vec.end();
2165 ++val_it) {
2166 auto &val = **val_it;
Kamil Rojewski46bb05d2017-08-11 18:24:36 +02002167 if (!SupportsVectorOfUnions() &&
Robbie McElrath0e85eee2017-06-26 09:07:02 -07002168 val.union_type.struct_def && val.union_type.struct_def->fixed)
2169 return Error(
2170 "only tables can be union elements in the generated language: "
2171 + val.name);
2172 }
2173 }
2174 }
2175 return NoError();
2176}
2177
2178CheckedError Parser::DoParse(const char *source,
2179 const char **include_paths,
2180 const char *source_filename,
2181 const char *include_filename) {
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002182 if (source_filename &&
Pavel Kalinnikov642254b2017-06-02 17:50:18 +02002183 included_files_.find(source_filename) == included_files_.end()) {
2184 included_files_[source_filename] = include_filename ? include_filename : "";
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002185 files_included_per_file_[source_filename] = std::set<std::string>();
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002186 }
2187 if (!include_paths) {
Wouter van Oortmerssen1e6f8f52015-06-22 10:23:42 -07002188 static const char *current_directory[] = { "", nullptr };
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002189 include_paths = current_directory;
2190 }
Yonggang Lifea6b522017-01-03 13:54:15 -08002191 field_stack_.clear();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002192 builder_.Clear();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07002193 // Start with a blank namespace just in case this file doesn't have one.
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07002194 current_namespace_ = empty_namespace_;
Louis-Paul CORDIERe7e4dc72017-03-10 17:50:44 +01002195
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002196 ECHECK(StartParseFile(source, source_filename));
Louis-Paul CORDIERe7e4dc72017-03-10 17:50:44 +01002197
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002198 // Includes must come before type declarations:
2199 for (;;) {
2200 // Parse pre-include proto statements if any:
2201 if (opts.proto_mode &&
2202 (attribute_ == "option" || attribute_ == "syntax" ||
2203 attribute_ == "package")) {
2204 ECHECK(ParseProtoDecl());
Wouter van Oortmerssen3f936c52017-01-18 16:23:35 -08002205 } else if (Is(kTokenNativeInclude)) {
2206 NEXT();
Stewart Milesa8923222017-07-13 06:27:39 -07002207 vector_emplace_back(&native_included_files_, attribute_);
Wouter van Oortmerssen3f936c52017-01-18 16:23:35 -08002208 EXPECT(kTokenStringConstant);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002209 } else if (Is(kTokenInclude) ||
2210 (opts.proto_mode &&
2211 attribute_ == "import" &&
2212 Is(kTokenIdentifier))) {
2213 NEXT();
2214 if (opts.proto_mode && attribute_ == "public") NEXT();
Wouter van Oortmerssenaaf55982017-05-18 17:18:43 -07002215 auto name = flatbuffers::PosixPath(attribute_.c_str());
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002216 EXPECT(kTokenStringConstant);
2217 // Look for the file in include_paths.
2218 std::string filepath;
2219 for (auto paths = include_paths; paths && *paths; paths++) {
2220 filepath = flatbuffers::ConCatPathFileName(*paths, name);
2221 if(FileExists(filepath.c_str())) break;
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07002222 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002223 if (filepath.empty())
2224 return Error("unable to locate include file: " + name);
2225 if (source_filename)
2226 files_included_per_file_[source_filename].insert(filepath);
Pavel Kalinnikov642254b2017-06-02 17:50:18 +02002227 if (included_files_.find(filepath) == included_files_.end()) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002228 // We found an include file that we have not parsed yet.
2229 // Load it and parse it.
2230 std::string contents;
2231 if (!LoadFile(filepath.c_str(), true, &contents))
2232 return Error("unable to load include file: " + name);
Wouter van Oortmerssen22743ca2017-05-24 15:21:26 -07002233 ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
2234 name.c_str()));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002235 // We generally do not want to output code for any included files:
2236 if (!opts.generate_all) MarkGenerated();
Wouter van Oortmerssen432e7582017-08-14 10:41:39 -07002237 // Reset these just in case the included file had them, and the
Wouter van Oortmerssendca33dd2017-08-14 09:22:12 -07002238 // parent doesn't.
2239 root_struct_def_ = nullptr;
Wouter van Oortmerssen432e7582017-08-14 10:41:39 -07002240 file_identifier_.clear();
2241 file_extension_.clear();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002242 // This is the easiest way to continue this file after an include:
2243 // instead of saving and restoring all the state, we simply start the
2244 // file anew. This will cause it to encounter the same include
2245 // statement again, but this time it will skip it, because it was
2246 // entered into included_files_.
2247 // This is recursive, but only go as deep as the number of include
2248 // statements.
Wouter van Oortmerssen22743ca2017-05-24 15:21:26 -07002249 return DoParse(source, include_paths, source_filename, include_filename);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002250 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002251 EXPECT(';');
2252 } else {
2253 break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002254 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002255 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002256 // Now parse all other kinds of declarations:
2257 while (token_ != kTokenEof) {
2258 if (opts.proto_mode) {
2259 ECHECK(ParseProtoDecl());
2260 } else if (token_ == kTokenNameSpace) {
2261 ECHECK(ParseNamespace());
2262 } else if (token_ == '{') {
2263 if (!root_struct_def_)
2264 return Error("no root type set to parse json with");
2265 if (builder_.GetSize()) {
2266 return Error("cannot have more than one json object in a file");
2267 }
2268 uoffset_t toff;
2269 ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
2270 builder_.Finish(Offset<Table>(toff),
2271 file_identifier_.length() ? file_identifier_.c_str() : nullptr);
2272 } else if (token_ == kTokenEnum) {
2273 ECHECK(ParseEnum(false, nullptr));
2274 } else if (token_ == kTokenUnion) {
2275 ECHECK(ParseEnum(true, nullptr));
2276 } else if (token_ == kTokenRootType) {
2277 NEXT();
2278 auto root_type = attribute_;
2279 EXPECT(kTokenIdentifier);
2280 ECHECK(ParseNamespacing(&root_type, nullptr));
2281 if (!SetRootType(root_type.c_str()))
2282 return Error("unknown root type: " + root_type);
2283 if (root_struct_def_->fixed)
2284 return Error("root type must be a table");
2285 EXPECT(';');
2286 } else if (token_ == kTokenFileIdentifier) {
2287 NEXT();
2288 file_identifier_ = attribute_;
2289 EXPECT(kTokenStringConstant);
2290 if (file_identifier_.length() !=
2291 FlatBufferBuilder::kFileIdentifierLength)
2292 return Error("file_identifier must be exactly " +
2293 NumToString(FlatBufferBuilder::kFileIdentifierLength) +
2294 " characters");
2295 EXPECT(';');
2296 } else if (token_ == kTokenFileExtension) {
2297 NEXT();
2298 file_extension_ = attribute_;
2299 EXPECT(kTokenStringConstant);
2300 EXPECT(';');
2301 } else if(token_ == kTokenInclude) {
2302 return Error("includes must come before declarations");
2303 } else if(token_ == kTokenAttribute) {
2304 NEXT();
2305 auto name = attribute_;
2306 EXPECT(kTokenStringConstant);
2307 EXPECT(';');
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002308 known_attributes_[name] = false;
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08002309 } else if (token_ == kTokenService) {
2310 ECHECK(ParseService());
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002311 } else {
2312 ECHECK(ParseDecl());
2313 }
2314 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002315 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002316}
2317
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002318std::set<std::string> Parser::GetIncludedFilesRecursive(
2319 const std::string &file_name) const {
2320 std::set<std::string> included_files;
2321 std::list<std::string> to_process;
2322
2323 if (file_name.empty()) return included_files;
2324 to_process.push_back(file_name);
2325
2326 while (!to_process.empty()) {
2327 std::string current = to_process.front();
2328 to_process.pop_front();
2329 included_files.insert(current);
2330
Stewart Milesa8923222017-07-13 06:27:39 -07002331 // Workaround the lack of const accessor in C++98 maps.
2332 auto &new_files =
2333 (*const_cast<std::map<std::string, std::set<std::string>> *>(
2334 &files_included_per_file_))[current];
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002335 for (auto it = new_files.begin(); it != new_files.end(); ++it) {
2336 if (included_files.find(*it) == included_files.end())
2337 to_process.push_back(*it);
2338 }
2339 }
2340
2341 return included_files;
2342}
2343
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002344// Schema serialization functionality:
2345
Chandra Penkeb63ebad2016-01-06 08:31:53 -08002346template<typename T> bool compareName(const T* a, const T* b) {
Xun Liudf0991b2016-09-14 10:33:06 -07002347 return a->defined_namespace->GetFullyQualifiedName(a->name)
2348 < b->defined_namespace->GetFullyQualifiedName(b->name);
Chandra Penkeb63ebad2016-01-06 08:31:53 -08002349}
2350
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002351template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
2352 // Pre-sort these vectors, such that we can set the correct indices for them.
2353 auto vec = defvec;
Chandra Penkeb63ebad2016-01-06 08:31:53 -08002354 std::sort(vec.begin(), vec.end(), compareName<T>);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002355 for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
2356}
2357
2358void Parser::Serialize() {
2359 builder_.Clear();
2360 AssignIndices(structs_.vec);
2361 AssignIndices(enums_.vec);
2362 std::vector<Offset<reflection::Object>> object_offsets;
2363 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002364 auto offset = (*it)->Serialize(&builder_, *this);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002365 object_offsets.push_back(offset);
2366 (*it)->serialized_location = offset.o;
2367 }
2368 std::vector<Offset<reflection::Enum>> enum_offsets;
2369 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002370 auto offset = (*it)->Serialize(&builder_, *this);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002371 enum_offsets.push_back(offset);
2372 (*it)->serialized_location = offset.o;
2373 }
2374 auto schema_offset = reflection::CreateSchema(
2375 builder_,
2376 builder_.CreateVectorOfSortedTables(&object_offsets),
2377 builder_.CreateVectorOfSortedTables(&enum_offsets),
2378 builder_.CreateString(file_identifier_),
2379 builder_.CreateString(file_extension_),
Wouter van Oortmerssen36c7e9a2015-06-29 15:21:48 -07002380 root_struct_def_
2381 ? root_struct_def_->serialized_location
2382 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002383 builder_.Finish(schema_offset, reflection::SchemaIdentifier());
2384}
2385
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002386Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
2387 const Parser &parser) const {
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002388 std::vector<Offset<reflection::Field>> field_offsets;
2389 for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
Wouter van Oortmerssen622b8d02015-06-15 15:57:48 -07002390 field_offsets.push_back(
2391 (*it)->Serialize(builder,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002392 static_cast<uint16_t>(it - fields.vec.begin()), parser));
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002393 }
Xun Liudf0991b2016-09-14 10:33:06 -07002394 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002395 return reflection::CreateObject(*builder,
Xun Liudf0991b2016-09-14 10:33:06 -07002396 builder->CreateString(qualified_name),
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002397 builder->CreateVectorOfSortedTables(
2398 &field_offsets),
Wouter van Oortmerssencb2b2be2015-06-23 16:06:35 -07002399 fixed,
2400 static_cast<int>(minalign),
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002401 static_cast<int>(bytesize),
Wouter van Oortmerssen1fb6b9e2017-02-13 16:15:55 -08002402 SerializeAttributes(builder, parser),
2403 parser.opts.binary_schema_comments
2404 ? builder->CreateVectorOfStrings(
2405 doc_comment)
2406 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002407}
2408
2409Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002410 uint16_t id,
2411 const Parser &parser) const {
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002412 return reflection::CreateField(*builder,
2413 builder->CreateString(name),
2414 value.type.Serialize(builder),
2415 id,
2416 value.offset,
2417 IsInteger(value.type.base_type)
2418 ? StringToInt(value.constant.c_str())
2419 : 0,
2420 IsFloat(value.type.base_type)
2421 ? strtod(value.constant.c_str(), nullptr)
2422 : 0.0,
2423 deprecated,
2424 required,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002425 key,
Wouter van Oortmerssen1fb6b9e2017-02-13 16:15:55 -08002426 SerializeAttributes(builder, parser),
2427 parser.opts.binary_schema_comments
2428 ? builder->CreateVectorOfStrings(doc_comment)
2429 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002430 // TODO: value.constant is almost always "0", we could save quite a bit of
2431 // space by sharing it. Same for common values of value.type.
2432}
2433
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002434Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
2435 const Parser &parser) const {
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002436 std::vector<Offset<reflection::EnumVal>> enumval_offsets;
2437 for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
2438 enumval_offsets.push_back((*it)->Serialize(builder));
2439 }
Xun Liudf0991b2016-09-14 10:33:06 -07002440 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002441 return reflection::CreateEnum(*builder,
Xun Liudf0991b2016-09-14 10:33:06 -07002442 builder->CreateString(qualified_name),
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002443 builder->CreateVector(enumval_offsets),
2444 is_union,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002445 underlying_type.Serialize(builder),
Wouter van Oortmerssen1fb6b9e2017-02-13 16:15:55 -08002446 SerializeAttributes(builder, parser),
2447 parser.opts.binary_schema_comments
2448 ? builder->CreateVectorOfStrings(doc_comment)
2449 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002450}
2451
2452Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const
2453 {
2454 return reflection::CreateEnumVal(*builder,
2455 builder->CreateString(name),
2456 value,
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -07002457 union_type.struct_def
2458 ? union_type.struct_def->
2459 serialized_location
2460 : 0,
2461 union_type.Serialize(builder));
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002462}
2463
2464Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
2465 return reflection::CreateType(*builder,
2466 static_cast<reflection::BaseType>(base_type),
2467 static_cast<reflection::BaseType>(element),
2468 struct_def ? struct_def->index :
2469 (enum_def ? enum_def->index : -1));
2470}
2471
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002472flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<
2473 reflection::KeyValue>>>
2474 Definition::SerializeAttributes(FlatBufferBuilder *builder,
2475 const Parser &parser) const {
2476 std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -07002477 for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) {
2478 auto it = parser.known_attributes_.find(kv->first);
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002479 assert(it != parser.known_attributes_.end());
2480 if (!it->second) { // Custom attribute.
2481 attrs.push_back(
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -07002482 reflection::CreateKeyValue(*builder, builder->CreateString(kv->first),
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002483 builder->CreateString(
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -07002484 kv->second->constant)));
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002485 }
2486 }
2487 if (attrs.size()) {
2488 return builder->CreateVectorOfSortedTables(&attrs);
2489 } else {
2490 return 0;
2491 }
2492}
2493
Wouter van Oortmerssen05b00c52016-07-20 17:24:50 -07002494std::string Parser::ConformTo(const Parser &base) {
2495 for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) {
2496 auto &struct_def = **sit;
2497 auto qualified_name =
2498 struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name);
2499 auto struct_def_base = base.structs_.Lookup(qualified_name);
2500 if (!struct_def_base) continue;
2501 for (auto fit = struct_def.fields.vec.begin();
2502 fit != struct_def.fields.vec.end(); ++fit) {
2503 auto &field = **fit;
2504 auto field_base = struct_def_base->fields.Lookup(field.name);
2505 if (field_base) {
2506 if (field.value.offset != field_base->value.offset)
2507 return "offsets differ for field: " + field.name;
2508 if (field.value.constant != field_base->value.constant)
2509 return "defaults differ for field: " + field.name;
2510 if (!EqualByName(field.value.type, field_base->value.type))
2511 return "types differ for field: " + field.name;
2512 } else {
2513 // Doesn't have to exist, deleting fields is fine.
2514 // But we should check if there is a field that has the same offset
2515 // but is incompatible (in the case of field renaming).
2516 for (auto fbit = struct_def_base->fields.vec.begin();
2517 fbit != struct_def_base->fields.vec.end(); ++fbit) {
2518 field_base = *fbit;
2519 if (field.value.offset == field_base->value.offset) {
2520 if (!EqualByName(field.value.type, field_base->value.type))
2521 return "field renamed to different type: " + field.name;
2522 break;
2523 }
2524 }
2525 }
2526 }
2527 }
2528 for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) {
2529 auto &enum_def = **eit;
2530 auto qualified_name =
2531 enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name);
2532 auto enum_def_base = base.enums_.Lookup(qualified_name);
2533 if (!enum_def_base) continue;
2534 for (auto evit = enum_def.vals.vec.begin();
2535 evit != enum_def.vals.vec.end(); ++evit) {
2536 auto &enum_val = **evit;
2537 auto enum_val_base = enum_def_base->vals.Lookup(enum_val.name);
2538 if (enum_val_base) {
2539 if (enum_val.value != enum_val_base->value)
2540 return "values differ for enum: " + enum_val.name;
2541 }
2542 }
2543 }
2544 return "";
2545}
2546
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002547} // namespace flatbuffers