blob: 5c7a69f6facb5e7550c3aa44c68248c014e82756 [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>
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080019
Wouter van Oortmerssend3ac0bc2016-06-15 13:54:17 -070020#ifdef _WIN32
21#if !defined(_USE_MATH_DEFINES)
22#define _USE_MATH_DEFINES // For M_PI.
23#endif // !defined(_USE_MATH_DEFINES)
24#endif // _WIN32
25
26#include <math.h>
27
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080028#include "flatbuffers/idl.h"
29#include "flatbuffers/util.h"
30
31namespace flatbuffers {
32
33const char *const kTypeNames[] = {
rw48dfc692014-12-16 00:32:11 -080034 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
35 IDLTYPE,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080036 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
37 #undef FLATBUFFERS_TD
38 nullptr
39};
40
41const char kTypeSizes[] = {
rw48dfc692014-12-16 00:32:11 -080042 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen557c88c2014-09-16 17:37:17 -070043 sizeof(CTYPE),
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080044 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
45 #undef FLATBUFFERS_TD
46};
47
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -070048// The enums in the reflection schema should match the ones we use internally.
49// Compare the last element to check if these go out of sync.
50static_assert(BASE_TYPE_UNION ==
Wouter van Oortmerssen622b8d02015-06-15 15:57:48 -070051 static_cast<BaseType>(reflection::Union),
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -070052 "enums don't match");
53
Wouter van Oortmerssen451272b2015-12-29 16:33:00 -080054// Any parsing calls have to be wrapped in this macro, which automates
55// handling of recursive error checking a bit. It will check the received
56// CheckedError object, and return straight away on error.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080057#define ECHECK(call) { auto ce = (call); if (ce.Check()) return ce; }
Wouter van Oortmerssen451272b2015-12-29 16:33:00 -080058
59// These two functions are called hundreds of times below, so define a short
60// form:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080061#define NEXT() ECHECK(Next())
62#define EXPECT(tok) ECHECK(Expect(tok))
63
Ben Hamiltonf6416d82016-08-01 14:04:51 -070064static bool ValidateUTF8(const std::string &str) {
65 const char *s = &str[0];
66 const char * const sEnd = s + str.length();
67 while (s < sEnd) {
68 if (FromUTF8(&s) < 0) {
69 return false;
70 }
71 }
72 return true;
73}
74
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080075CheckedError Parser::Error(const std::string &msg) {
76 error_ = file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : "";
77 #ifdef _WIN32
78 error_ += "(" + NumToString(line_) + ")"; // MSVC alike
79 #else
80 if (file_being_parsed_.length()) error_ += ":";
81 error_ += NumToString(line_) + ":0"; // gcc alike
82 #endif
83 error_ += ": error: " + msg;
84 return CheckedError(true);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080085}
86
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080087inline CheckedError NoError() { return CheckedError(false); }
88
Jason Stubbsa07f0d42017-04-18 04:19:43 +100089inline std::string OutOfRangeErrorMsg(int64_t val, const std::string &op,
90 int64_t limit) {
91 const std::string cause = NumToString(val) + op + NumToString(limit);
92 return "constant does not fit (" + cause + ")";
93}
94
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080095// Ensure that integer values we parse fit inside the declared integer type.
Jason Stubbsa07f0d42017-04-18 04:19:43 +100096CheckedError Parser::CheckInRange(int64_t val, int64_t min, int64_t max) {
97 if (val < min)
98 return Error(OutOfRangeErrorMsg(val, " < ", min));
99 else if (val > max)
100 return Error(OutOfRangeErrorMsg(val, " > ", max));
101 else
102 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800103}
104
105// atot: templated version of atoi/atof: convert a string to an instance of T.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800106template<typename T> inline CheckedError atot(const char *s, Parser &parser,
107 T *val) {
108 int64_t i = StringToInt(s);
Jason Stubbsa07f0d42017-04-18 04:19:43 +1000109 const int64_t min = std::numeric_limits<T>::min();
110 const int64_t max = std::numeric_limits<T>::max();
111 ECHECK(parser.CheckInRange(i, min, max));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800112 *val = (T)i;
113 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800114}
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800115template<> inline CheckedError atot<uint64_t>(const char *s, Parser &parser,
116 uint64_t *val) {
117 (void)parser;
118 *val = StringToUInt(s);
119 return NoError();
120}
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800121template<> inline CheckedError atot<bool>(const char *s, Parser &parser,
122 bool *val) {
123 (void)parser;
124 *val = 0 != atoi(s);
125 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800126}
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800127template<> inline CheckedError atot<float>(const char *s, Parser &parser,
128 float *val) {
129 (void)parser;
130 *val = static_cast<float>(strtod(s, nullptr));
131 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800132}
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800133template<> inline CheckedError atot<double>(const char *s, Parser &parser,
134 double *val) {
135 (void)parser;
136 *val = strtod(s, nullptr);
137 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800138}
139
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800140template<> inline CheckedError atot<Offset<void>>(const char *s, Parser &parser,
141 Offset<void> *val) {
142 (void)parser;
143 *val = Offset<void>(atoi(s));
144 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800145}
146
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700147std::string Namespace::GetFullyQualifiedName(const std::string &name,
148 size_t max_components) const {
149 // Early exit if we don't have a defined namespace.
150 if (components.size() == 0 || !max_components) {
151 return name;
152 }
153 std::stringstream stream;
154 for (size_t i = 0; i < std::min(components.size(), max_components);
155 i++) {
156 if (i) {
157 stream << ".";
158 }
159 stream << components[i];
160 }
Wouter van Oortmerssen8c1a7232017-01-09 15:54:31 -0800161 if (name.length()) stream << "." << name;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700162 return stream.str();
163}
164
165
166
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800167// Declare tokens we'll use. Single character tokens are represented by their
168// ascii character code (e.g. '{'), others above 256.
169#define FLATBUFFERS_GEN_TOKENS(TD) \
170 TD(Eof, 256, "end of file") \
171 TD(StringConstant, 257, "string constant") \
172 TD(IntegerConstant, 258, "integer constant") \
173 TD(FloatConstant, 259, "float constant") \
174 TD(Identifier, 260, "identifier") \
175 TD(Table, 261, "table") \
176 TD(Struct, 262, "struct") \
177 TD(Enum, 263, "enum") \
178 TD(Union, 264, "union") \
179 TD(NameSpace, 265, "namespace") \
Wouter van Oortmerssen5da7bda2014-07-31 15:11:03 -0700180 TD(RootType, 266, "root_type") \
181 TD(FileIdentifier, 267, "file_identifier") \
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -0700182 TD(FileExtension, 268, "file_extension") \
Wouter van Oortmerssen09521432014-11-17 17:27:26 -0800183 TD(Include, 269, "include") \
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800184 TD(Attribute, 270, "attribute") \
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -0800185 TD(Null, 271, "null") \
Wouter van Oortmerssen3f936c52017-01-18 16:23:35 -0800186 TD(Service, 272, "rpc_service") \
187 TD(NativeInclude, 273, "native_include")
Wouter van Oortmerssen8f80fec2014-07-29 10:29:38 -0700188#ifdef __GNUC__
189__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
190#endif
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800191enum {
Wouter van Oortmerssen75349ae2014-07-09 11:44:26 -0700192 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800193 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
194 #undef FLATBUFFERS_TOKEN
rw48dfc692014-12-16 00:32:11 -0800195 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen557c88c2014-09-16 17:37:17 -0700196 kToken ## ENUM,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800197 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
198 #undef FLATBUFFERS_TD
199};
200
201static std::string TokenToString(int t) {
202 static const char *tokens[] = {
203 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
204 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
205 #undef FLATBUFFERS_TOKEN
rw48dfc692014-12-16 00:32:11 -0800206 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
207 IDLTYPE,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800208 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
209 #undef FLATBUFFERS_TD
210 };
211 if (t < 256) { // A single ascii char token.
212 std::string s;
Wouter van Oortmerssen8e409022014-09-02 17:32:12 -0700213 s.append(1, static_cast<char>(t));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800214 return s;
215 } else { // Other tokens.
216 return tokens[t - 256];
217 }
218}
219
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700220std::string Parser::TokenToStringId(int t) {
221 return TokenToString(t) + (t == kTokenIdentifier ? ": " + attribute_ : "");
222}
223
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700224// Parses exactly nibbles worth of hex digits into a number, or error.
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800225CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) {
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700226 for (int i = 0; i < nibbles; i++)
Chris Pickett30013b42016-01-05 13:38:03 -0600227 if (!isxdigit(static_cast<const unsigned char>(cursor_[i])))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800228 return Error("escape code must be followed by " + NumToString(nibbles) +
229 " hex digits");
Hiroshi Matsunaga7cf74cb2015-01-09 03:38:14 +0900230 std::string target(cursor_, cursor_ + nibbles);
Sahil Jainb6ba3222016-08-25 23:37:30 -0400231 *val = StringToUInt(target.c_str(), nullptr, 16);
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700232 cursor_ += nibbles;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800233 return NoError();
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700234}
235
Oli Wilkinsoncbe87472016-01-18 18:58:53 +0000236CheckedError Parser::SkipByteOrderMark() {
237 if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError();
238 cursor_++;
Wouter van Oortmerssenf6330ab2016-04-22 11:26:47 -0700239 if (static_cast<unsigned char>(*cursor_) != 0xbb) return Error("invalid utf-8 byte order mark");
240 cursor_++;
241 if (static_cast<unsigned char>(*cursor_) != 0xbf) return Error("invalid utf-8 byte order mark");
242 cursor_++;
Oli Wilkinsoncbe87472016-01-18 18:58:53 +0000243 return NoError();
244}
245
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -0800246bool IsIdentifierStart(char c) {
247 return isalpha(static_cast<unsigned char>(c)) || c == '_';
248}
249
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800250CheckedError Parser::Next() {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800251 doc_comment_.clear();
252 bool seen_newline = false;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700253 attribute_.clear();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800254 for (;;) {
255 char c = *cursor_++;
256 token_ = c;
257 switch (c) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800258 case '\0': cursor_--; token_ = kTokenEof; return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800259 case ' ': case '\r': case '\t': break;
260 case '\n': line_++; seen_newline = true; break;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800261 case '{': case '}': case '(': case ')': case '[': case ']':
262 case ',': case ':': case ';': case '=': return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800263 case '.':
Chris Pickett30013b42016-01-05 13:38:03 -0600264 if(!isdigit(static_cast<const unsigned char>(*cursor_))) return NoError();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800265 return Error("floating point constant can\'t start with \".\"");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800266 case '\"':
Ben Gertzfield6704b192016-04-28 12:27:38 -0700267 case '\'': {
268 int unicode_high_surrogate = -1;
269
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700270 while (*cursor_ != c) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800271 if (*cursor_ < ' ' && *cursor_ >= 0)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800272 return Error("illegal character in string constant");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800273 if (*cursor_ == '\\') {
274 cursor_++;
Ben Gertzfield6704b192016-04-28 12:27:38 -0700275 if (unicode_high_surrogate != -1 &&
276 *cursor_ != 'u') {
277 return Error(
278 "illegal Unicode sequence (unpaired high surrogate)");
279 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800280 switch (*cursor_) {
281 case 'n': attribute_ += '\n'; cursor_++; break;
282 case 't': attribute_ += '\t'; cursor_++; break;
283 case 'r': attribute_ += '\r'; cursor_++; break;
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700284 case 'b': attribute_ += '\b'; cursor_++; break;
285 case 'f': attribute_ += '\f'; cursor_++; break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800286 case '\"': attribute_ += '\"'; cursor_++; break;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700287 case '\'': attribute_ += '\''; cursor_++; break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800288 case '\\': attribute_ += '\\'; cursor_++; break;
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700289 case '/': attribute_ += '/'; cursor_++; break;
290 case 'x': { // Not in the JSON standard
291 cursor_++;
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800292 uint64_t val;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800293 ECHECK(ParseHexNum(2, &val));
294 attribute_ += static_cast<char>(val);
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700295 break;
296 }
297 case 'u': {
298 cursor_++;
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800299 uint64_t val;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800300 ECHECK(ParseHexNum(4, &val));
Ben Gertzfield6704b192016-04-28 12:27:38 -0700301 if (val >= 0xD800 && val <= 0xDBFF) {
302 if (unicode_high_surrogate != -1) {
303 return Error(
304 "illegal Unicode sequence (multiple high surrogates)");
305 } else {
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -0700306 unicode_high_surrogate = static_cast<int>(val);
Ben Gertzfield6704b192016-04-28 12:27:38 -0700307 }
308 } else if (val >= 0xDC00 && val <= 0xDFFF) {
309 if (unicode_high_surrogate == -1) {
310 return Error(
311 "illegal Unicode sequence (unpaired low surrogate)");
312 } else {
313 int code_point = 0x10000 +
314 ((unicode_high_surrogate & 0x03FF) << 10) +
315 (val & 0x03FF);
316 ToUTF8(code_point, &attribute_);
317 unicode_high_surrogate = -1;
318 }
319 } else {
320 if (unicode_high_surrogate != -1) {
321 return Error(
322 "illegal Unicode sequence (unpaired high surrogate)");
323 }
324 ToUTF8(static_cast<int>(val), &attribute_);
325 }
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700326 break;
327 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800328 default: return Error("unknown escape code in string constant");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800329 }
330 } else { // printable chars + UTF-8 bytes
Ben Gertzfield6704b192016-04-28 12:27:38 -0700331 if (unicode_high_surrogate != -1) {
332 return Error(
333 "illegal Unicode sequence (unpaired high surrogate)");
334 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800335 attribute_ += *cursor_++;
336 }
337 }
Ben Gertzfield6704b192016-04-28 12:27:38 -0700338 if (unicode_high_surrogate != -1) {
339 return Error(
340 "illegal Unicode sequence (unpaired high surrogate)");
341 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800342 cursor_++;
Ben Hamiltonf6416d82016-08-01 14:04:51 -0700343 if (!opts.allow_non_utf8 && !ValidateUTF8(attribute_)) {
344 return Error("illegal UTF-8 sequence");
345 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800346 token_ = kTokenStringConstant;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800347 return NoError();
Ben Gertzfield6704b192016-04-28 12:27:38 -0700348 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800349 case '/':
350 if (*cursor_ == '/') {
351 const char *start = ++cursor_;
Mormegila8d69622015-04-14 18:09:08 +0200352 while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800353 if (*start == '/') { // documentation comment
Zbigniew Mandziejewicz07d59652014-10-22 22:40:03 +0800354 if (cursor_ != source_ && !seen_newline)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800355 return Error(
356 "a documentation comment should be on a line on its own");
Gabriel Martinez730c0ca2014-09-24 11:46:32 -0700357 doc_comment_.push_back(std::string(start + 1, cursor_));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800358 }
359 break;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700360 } else if (*cursor_ == '*') {
361 cursor_++;
362 // TODO: make nested.
363 while (*cursor_ != '*' || cursor_[1] != '/') {
Wouter van Oortmerssenab51b032016-10-07 17:07:39 -0700364 if (*cursor_ == '\n') line_++;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800365 if (!*cursor_) return Error("end of file in comment");
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700366 cursor_++;
367 }
368 cursor_ += 2;
369 break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800370 }
371 // fall thru
372 default:
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -0800373 if (IsIdentifierStart(c)) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800374 // Collect all chars of an identifier:
375 const char *start = cursor_ - 1;
376 while (isalnum(static_cast<unsigned char>(*cursor_)) ||
377 *cursor_ == '_')
378 cursor_++;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800379 attribute_.append(start, cursor_);
380 // First, see if it is a type keyword from the table of types:
rw48dfc692014-12-16 00:32:11 -0800381 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
382 PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800383 if (attribute_ == IDLTYPE) { \
384 token_ = kToken ## ENUM; \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800385 return NoError(); \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800386 }
387 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
388 #undef FLATBUFFERS_TD
389 // If it's a boolean constant keyword, turn those into integers,
390 // which simplifies our logic downstream.
391 if (attribute_ == "true" || attribute_ == "false") {
392 attribute_ = NumToString(attribute_ == "true");
393 token_ = kTokenIntegerConstant;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800394 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800395 }
396 // Check for declaration keywords:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800397 if (attribute_ == "table") {
398 token_ = kTokenTable;
399 return NoError();
400 }
401 if (attribute_ == "struct") {
402 token_ = kTokenStruct;
403 return NoError();
404 }
405 if (attribute_ == "enum") {
406 token_ = kTokenEnum;
407 return NoError();
408 }
409 if (attribute_ == "union") {
410 token_ = kTokenUnion;
411 return NoError();
412 }
413 if (attribute_ == "namespace") {
414 token_ = kTokenNameSpace;
415 return NoError();
416 }
417 if (attribute_ == "root_type") {
418 token_ = kTokenRootType;
419 return NoError();
420 }
421 if (attribute_ == "include") {
422 token_ = kTokenInclude;
423 return NoError();
424 }
425 if (attribute_ == "attribute") {
426 token_ = kTokenAttribute;
427 return NoError();
428 }
Wouter van Oortmerssen5da7bda2014-07-31 15:11:03 -0700429 if (attribute_ == "file_identifier") {
430 token_ = kTokenFileIdentifier;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800431 return NoError();
Wouter van Oortmerssen5da7bda2014-07-31 15:11:03 -0700432 }
433 if (attribute_ == "file_extension") {
434 token_ = kTokenFileExtension;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800435 return NoError();
Wouter van Oortmerssen5da7bda2014-07-31 15:11:03 -0700436 }
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800437 if (attribute_ == "null") {
438 token_ = kTokenNull;
439 return NoError();
440 }
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -0800441 if (attribute_ == "rpc_service") {
442 token_ = kTokenService;
443 return NoError();
444 }
Wouter van Oortmerssen3f936c52017-01-18 16:23:35 -0800445 if (attribute_ == "native_include") {
446 token_ = kTokenNativeInclude;
447 return NoError();
448 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800449 // If not, it is a user-defined identifier:
450 token_ = kTokenIdentifier;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800451 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800452 } else if (isdigit(static_cast<unsigned char>(c)) || c == '-') {
453 const char *start = cursor_ - 1;
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800454 if (c == '-' && *cursor_ == '0' &&
455 (cursor_[1] == 'x' || cursor_[1] == 'X')) {
Ramanf6f88e52016-07-12 19:47:53 +0200456 ++start;
457 ++cursor_;
458 attribute_.append(&c, &c + 1);
459 c = '0';
460 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700461 if (c == '0' && (*cursor_ == 'x' || *cursor_ == 'X')) {
462 cursor_++;
463 while (isxdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
464 attribute_.append(start + 2, cursor_);
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800465 attribute_ = NumToString(static_cast<int64_t>(
466 StringToUInt(attribute_.c_str(), nullptr, 16)));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700467 token_ = kTokenIntegerConstant;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800468 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700469 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800470 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700471 if (*cursor_ == '.' || *cursor_ == 'e' || *cursor_ == 'E') {
472 if (*cursor_ == '.') {
473 cursor_++;
474 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
475 }
Wouter van Oortmerssen93df5692014-07-10 13:40:55 -0700476 // See if this float has a scientific notation suffix. Both JSON
477 // and C++ (through strtod() we use) have the same format:
478 if (*cursor_ == 'e' || *cursor_ == 'E') {
479 cursor_++;
480 if (*cursor_ == '+' || *cursor_ == '-') cursor_++;
481 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
482 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800483 token_ = kTokenFloatConstant;
484 } else {
485 token_ = kTokenIntegerConstant;
486 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800487 attribute_.append(start, cursor_);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800488 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800489 }
490 std::string ch;
491 ch = c;
492 if (c < ' ' || c > '~') ch = "code: " + NumToString(c);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800493 return Error("illegal character: " + ch);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800494 }
495 }
496}
497
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800498// Check if a given token is next.
499bool Parser::Is(int t) {
500 return t == token_;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800501}
502
503// Expect a given token to be next, consume it, or error if not present.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800504CheckedError Parser::Expect(int t) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800505 if (t != token_) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800506 return Error("expecting: " + TokenToString(t) + " instead got: " +
507 TokenToStringId(token_));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800508 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800509 NEXT();
510 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800511}
512
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800513CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) {
514 while (Is('.')) {
515 NEXT();
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700516 *id += ".";
517 *id += attribute_;
518 if (last) *last = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800519 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700520 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800521 return NoError();
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700522}
523
524EnumDef *Parser::LookupEnum(const std::string &id) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700525 // Search thru parent namespaces.
526 for (int components = static_cast<int>(namespaces_.back()->components.size());
527 components >= 0; components--) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800528 auto ed = enums_.Lookup(
529 namespaces_.back()->GetFullyQualifiedName(id, components));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700530 if (ed) return ed;
531 }
532 return nullptr;
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700533}
534
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800535CheckedError Parser::ParseTypeIdent(Type &type) {
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700536 std::string id = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800537 EXPECT(kTokenIdentifier);
538 ECHECK(ParseNamespacing(&id, nullptr));
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700539 auto enum_def = LookupEnum(id);
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700540 if (enum_def) {
541 type = enum_def->underlying_type;
542 if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
543 } else {
544 type.base_type = BASE_TYPE_STRUCT;
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700545 type.struct_def = LookupCreateStruct(id);
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700546 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800547 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700548}
549
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800550// Parse any IDL type.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800551CheckedError Parser::ParseType(Type &type) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800552 if (token_ >= kTokenBOOL && token_ <= kTokenSTRING) {
553 type.base_type = static_cast<BaseType>(token_ - kTokenNONE);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800554 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800555 } else {
556 if (token_ == kTokenIdentifier) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800557 ECHECK(ParseTypeIdent(type));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800558 } else if (token_ == '[') {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800559 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800560 Type subtype;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800561 ECHECK(ParseType(subtype));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800562 if (subtype.base_type == BASE_TYPE_VECTOR) {
563 // We could support this, but it will complicate things, and it's
564 // easier to work around with a struct around the inner vector.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800565 return Error(
566 "nested vector types not supported (wrap in table first).");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800567 }
Wouter van Oortmerssen3fb6a862014-07-14 17:49:04 -0700568 type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800569 type.element = subtype.base_type;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800570 EXPECT(']');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800571 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800572 return Error("illegal type syntax");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800573 }
574 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800575 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800576}
577
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800578CheckedError Parser::AddField(StructDef &struct_def, const std::string &name,
579 const Type &type, FieldDef **dest) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800580 auto &field = *new FieldDef();
581 field.value.offset =
582 FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size()));
583 field.name = name;
Gabriel Martinezdf4909e2014-11-04 10:00:56 -0800584 field.file = struct_def.file;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800585 field.value.type = type;
586 if (struct_def.fixed) { // statically compute the field offset
587 auto size = InlineSize(type);
588 auto alignment = InlineAlignment(type);
589 // structs_ need to have a predictable format, so we need to align to
590 // the largest scalar
591 struct_def.minalign = std::max(struct_def.minalign, alignment);
592 struct_def.PadLastField(alignment);
Wouter van Oortmerssen12563072014-06-30 15:56:31 -0700593 field.value.offset = static_cast<voffset_t>(struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800594 struct_def.bytesize += size;
595 }
596 if (struct_def.fields.Add(name, &field))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800597 return Error("field already exists: " + name);
598 *dest = &field;
599 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800600}
601
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800602CheckedError Parser::ParseField(StructDef &struct_def) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800603 std::string name = attribute_;
Wouter van Oortmerssene9f1f4d2017-06-02 15:55:02 -0700604
605 if (name == struct_def.name)
606 return Error("field name can not be the same as table/struct name");
607
Gabriel Martinez730c0ca2014-09-24 11:46:32 -0700608 std::vector<std::string> dc = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800609 EXPECT(kTokenIdentifier);
610 EXPECT(':');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800611 Type type;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800612 ECHECK(ParseType(type));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800613
614 if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800615 return Error("structs_ may contain only scalar or struct fields");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800616
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700617 FieldDef *typefield = nullptr;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800618 if (type.base_type == BASE_TYPE_UNION) {
619 // For union fields, add a second auto-generated field to hold the type,
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700620 // with a special suffix.
621 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
622 type.enum_def->underlying_type, &typefield));
Bei Li68bbe982017-01-24 11:52:36 -0800623 } else if (type.base_type == BASE_TYPE_VECTOR &&
624 type.element == BASE_TYPE_UNION) {
625 // Only cpp supports the union vector feature so far.
626 if (opts.lang_to_generate != IDLOptions::kCpp) {
627 return Error("Vectors of unions are not yet supported in all "
628 "the specified programming languages.");
629 }
630 // For vector of union fields, add a second auto-generated vector field to
631 // hold the types, with a special suffix.
632 Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def);
633 union_vector.element = BASE_TYPE_UTYPE;
634 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
635 union_vector, &typefield));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800636 }
637
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800638 FieldDef *field;
639 ECHECK(AddField(struct_def, name, type, &field));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800640
641 if (token_ == '=') {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800642 NEXT();
Wouter van Oortmerssen15dc1a82014-09-03 12:23:15 -0700643 if (!IsScalar(type.base_type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800644 return Error("default values currently only supported for scalars");
645 ECHECK(ParseSingleValue(field->value));
Wouter van Oortmerssenfd542c72016-04-20 12:05:21 -0700646 }
647 if (IsFloat(field->value.type.base_type)) {
648 if (!strpbrk(field->value.constant.c_str(), ".eE"))
649 field->value.constant += ".0";
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800650 }
651
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -0700652 if (type.enum_def &&
653 IsScalar(type.base_type) &&
654 !struct_def.fixed &&
655 !type.enum_def->attributes.Lookup("bit_flags") &&
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700656 !type.enum_def->ReverseLookup(static_cast<int>(
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800657 StringToInt(field->value.constant.c_str()))))
658 return Error("enum " + type.enum_def->name +
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -0700659 " does not have a declaration for this field\'s default of " +
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800660 field->value.constant);
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -0700661
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800662 field->doc_comment = dc;
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -0800663 ECHECK(ParseMetaData(&field->attributes));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800664 field->deprecated = field->attributes.Lookup("deprecated") != nullptr;
665 auto hash_name = field->attributes.Lookup("hash");
Alex Amesd5753212015-02-13 15:58:29 -0800666 if (hash_name) {
667 switch (type.base_type) {
668 case BASE_TYPE_INT:
669 case BASE_TYPE_UINT: {
670 if (FindHashFunction32(hash_name->constant.c_str()) == nullptr)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800671 return Error("Unknown hashing algorithm for 32 bit types: " +
Alex Amesd5753212015-02-13 15:58:29 -0800672 hash_name->constant);
673 break;
674 }
675 case BASE_TYPE_LONG:
676 case BASE_TYPE_ULONG: {
677 if (FindHashFunction64(hash_name->constant.c_str()) == nullptr)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800678 return Error("Unknown hashing algorithm for 64 bit types: " +
Alex Amesd5753212015-02-13 15:58:29 -0800679 hash_name->constant);
680 break;
681 }
682 default:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800683 return Error(
684 "only int, uint, long and ulong data types support hashing.");
Alex Amesd5753212015-02-13 15:58:29 -0800685 }
686 }
Wouter van Oortmerssendc2fa212016-10-05 16:59:15 -0700687 auto cpp_type = field->attributes.Lookup("cpp_type");
688 if (cpp_type) {
689 if (!hash_name)
690 return Error("cpp_type can only be used with a hashed field");
691 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800692 if (field->deprecated && struct_def.fixed)
693 return Error("can't deprecate fields in a struct");
694 field->required = field->attributes.Lookup("required") != nullptr;
695 if (field->required && (struct_def.fixed ||
696 IsScalar(field->value.type.base_type)))
697 return Error("only non-scalar fields in tables may be 'required'");
698 field->key = field->attributes.Lookup("key") != nullptr;
699 if (field->key) {
Wouter van Oortmerssen35508992015-01-07 17:51:31 -0800700 if (struct_def.has_key)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800701 return Error("only one field may be set as 'key'");
Wouter van Oortmerssen35508992015-01-07 17:51:31 -0800702 struct_def.has_key = true;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800703 if (!IsScalar(field->value.type.base_type)) {
704 field->required = true;
705 if (field->value.type.base_type != BASE_TYPE_STRING)
706 return Error("'key' field must be string or scalar type");
Wouter van Oortmerssen35508992015-01-07 17:51:31 -0800707 }
708 }
Wouter van Oortmerssen641b3972016-12-02 14:25:08 -0800709
710 field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
711 if (field->native_inline && !IsStruct(field->value.type))
712 return Error("native_inline can only be defined on structs'");
713
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800714 auto nested = field->attributes.Lookup("nested_flatbuffer");
Wouter van Oortmerssen3e201a92014-07-15 17:50:22 -0700715 if (nested) {
716 if (nested->type.base_type != BASE_TYPE_STRING)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800717 return Error(
718 "nested_flatbuffer attribute must be a string (the root type)");
719 if (field->value.type.base_type != BASE_TYPE_VECTOR ||
720 field->value.type.element != BASE_TYPE_UCHAR)
721 return Error(
722 "nested_flatbuffer attribute may only apply to a vector of ubyte");
Wouter van Oortmerssen3e201a92014-07-15 17:50:22 -0700723 // This will cause an error if the root type of the nested flatbuffer
724 // wasn't defined elsewhere.
725 LookupCreateStruct(nested->constant);
726 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800727
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700728 if (typefield) {
729 // If this field is a union, and it has a manually assigned id,
730 // the automatically added type field should have an id as well (of N - 1).
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800731 auto attr = field->attributes.Lookup("id");
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700732 if (attr) {
733 auto id = atoi(attr->constant.c_str());
734 auto val = new Value();
735 val->type = attr->type;
736 val->constant = NumToString(id - 1);
737 typefield->attributes.Add("id", val);
738 }
739 }
740
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800741 EXPECT(';');
742 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800743}
744
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -0700745CheckedError Parser::ParseString(Value &val) {
746 auto s = attribute_;
747 EXPECT(kTokenStringConstant);
748 val.constant = NumToString(builder_.CreateString(s).o);
749 return NoError();
750}
751
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800752CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700753 size_t parent_fieldn,
754 const StructDef *parent_struct_def) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800755 switch (val.type.base_type) {
756 case BASE_TYPE_UNION: {
757 assert(field);
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700758 std::string constant;
Wouter van Oortmersseneac29052017-01-18 12:02:31 -0800759 // Find corresponding type field we may have already parsed.
760 for (auto elem = field_stack_.rbegin();
761 elem != field_stack_.rbegin() + parent_fieldn; ++elem) {
762 auto &type = elem->second->value.type;
763 if (type.base_type == BASE_TYPE_UTYPE &&
764 type.enum_def == val.type.enum_def) {
765 constant = elem->first.constant;
766 break;
767 }
768 }
769 if (constant.empty()) {
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700770 // We haven't seen the type field yet. Sadly a lot of JSON writers
771 // output these in alphabetical order, meaning it comes after this
772 // value. So we scan past the value to find it, then come back here.
773 auto type_name = field->name + UnionTypeFieldSuffix();
774 assert(parent_struct_def);
775 auto type_field = parent_struct_def->fields.Lookup(type_name);
776 assert(type_field); // Guaranteed by ParseField().
777 // Remember where we are in the source file, so we can come back here.
778 auto backup = *static_cast<ParserState *>(this);
779 ECHECK(SkipAnyJsonValue()); // The table.
780 EXPECT(',');
781 auto next_name = attribute_;
782 if (Is(kTokenStringConstant)) {
783 NEXT();
784 } else {
785 EXPECT(kTokenIdentifier);
786 }
787 if (next_name != type_name)
788 return Error("missing type field after this union value: " +
789 type_name);
790 EXPECT(':');
791 Value type_val = type_field->value;
792 ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr));
793 constant = type_val.constant;
794 // Got the information we needed, now rewind:
795 *static_cast<ParserState *>(this) = backup;
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700796 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800797 uint8_t enum_idx;
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700798 ECHECK(atot(constant.c_str(), *this, &enum_idx));
Wouter van Oortmerssen3fb6a862014-07-14 17:49:04 -0700799 auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800800 if (!enum_val) return Error("illegal type id for: " + field->name);
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -0700801 if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
802 ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
803 nullptr));
804 if (enum_val->union_type.struct_def->fixed) {
805 // All BASE_TYPE_UNION values are offsets, so turn this into one.
806 SerializeStruct(*enum_val->union_type.struct_def, val);
807 builder_.ClearOffsets();
808 val.constant = NumToString(builder_.GetSize());
809 }
810 } else if (enum_val->union_type.base_type == BASE_TYPE_STRING) {
811 ECHECK(ParseString(val));
812 } else {
813 assert(false);
814 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800815 break;
816 }
817 case BASE_TYPE_STRUCT:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800818 ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800819 break;
820 case BASE_TYPE_STRING: {
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -0700821 ECHECK(ParseString(val));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800822 break;
823 }
824 case BASE_TYPE_VECTOR: {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800825 EXPECT('[');
826 uoffset_t off;
827 ECHECK(ParseVector(val.type.VectorType(), &off));
828 val.constant = NumToString(off);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800829 break;
830 }
Alex Amesd5753212015-02-13 15:58:29 -0800831 case BASE_TYPE_INT:
832 case BASE_TYPE_UINT:
833 case BASE_TYPE_LONG:
834 case BASE_TYPE_ULONG: {
835 if (field && field->attributes.Lookup("hash") &&
836 (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800837 ECHECK(ParseHash(val, field));
Alex Amesd5753212015-02-13 15:58:29 -0800838 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800839 ECHECK(ParseSingleValue(val));
Alex Amesd5753212015-02-13 15:58:29 -0800840 }
841 break;
842 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800843 default:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800844 ECHECK(ParseSingleValue(val));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800845 break;
846 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800847 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800848}
849
850void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700851 assert(val.constant.length() == struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800852 builder_.Align(struct_def.minalign);
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700853 builder_.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()),
854 struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800855 builder_.AddStructOffset(val.offset, builder_.GetSize());
856}
857
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800858CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
859 uoffset_t *ovalue) {
860 EXPECT('{');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800861 size_t fieldn = 0;
Wouter van Oortmerssen6c2dc412015-01-16 16:57:04 -0800862 for (;;) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800863 if ((!opts.strict_json || !fieldn) && Is('}')) { NEXT(); break; }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800864 std::string name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800865 if (Is(kTokenStringConstant)) {
866 NEXT();
867 } else {
868 EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
869 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800870 auto field = struct_def.fields.Lookup(name);
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800871 if (!field) {
872 if (!opts.skip_unexpected_fields_in_json) {
873 return Error("unknown field: " + name);
874 } else {
875 EXPECT(':');
876 ECHECK(SkipAnyJsonValue());
877 }
878 } else {
879 EXPECT(':');
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800880 if (Is(kTokenNull)) {
881 NEXT(); // Ignore this field.
882 } else {
883 Value val = field->value;
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700884 ECHECK(ParseAnyValue(val, field, fieldn, &struct_def));
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800885 // Hardcoded insertion-sort with error-check.
886 // If fields are specified in order, then this loop exits immediately.
Wouter van Oortmersseneac29052017-01-18 12:02:31 -0800887 auto elem = field_stack_.rbegin();
888 for (; elem != field_stack_.rbegin() + fieldn; ++elem) {
889 auto existing_field = elem->second;
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800890 if (existing_field == field)
891 return Error("field set more than once: " + field->name);
892 if (existing_field->value.offset < field->value.offset) break;
893 }
Wouter van Oortmersseneac29052017-01-18 12:02:31 -0800894 // Note: elem points to before the insertion point, thus .base() points
895 // to the correct spot.
896 field_stack_.insert(elem.base(), std::make_pair(val, field));
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800897 fieldn++;
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800898 }
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700899 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800900 if (Is('}')) { NEXT(); break; }
901 EXPECT(',');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800902 }
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800903
sfariv55dec4d2017-05-18 09:32:04 -0700904 // Check if all required fields are parsed.
905 for (auto field_it = struct_def.fields.vec.begin();
906 field_it != struct_def.fields.vec.end();
907 ++field_it) {
908 auto required_field = *field_it;
909 if (!required_field->required) {
910 continue;
911 }
912 bool found = false;
913 for (auto pf_it = field_stack_.end() - fieldn;
914 pf_it != field_stack_.end();
915 ++pf_it) {
916 auto parsed_field = pf_it->second;
917 if (parsed_field == required_field) {
918 found = true;
919 break;
920 }
921 }
922 if (!found) {
923 return Error("required field is missing: " + required_field->name + " in " + struct_def.name);
924 }
925 }
926
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800927 if (struct_def.fixed && fieldn != struct_def.fields.vec.size())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800928 return Error("struct: wrong number of initializers: " + struct_def.name);
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700929
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800930 auto start = struct_def.fixed
931 ? builder_.StartStruct(struct_def.minalign)
932 : builder_.StartTable();
933
934 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
935 size;
936 size /= 2) {
937 // Go through elements in reverse, since we're building the data backwards.
938 for (auto it = field_stack_.rbegin();
939 it != field_stack_.rbegin() + fieldn; ++it) {
Shuhei Tanuma721d2192015-11-06 07:14:21 +0900940 auto &field_value = it->first;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800941 auto field = it->second;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800942 if (!struct_def.sortbysize ||
943 size == SizeOf(field_value.type.base_type)) {
Shuhei Tanuma721d2192015-11-06 07:14:21 +0900944 switch (field_value.type.base_type) {
rw48dfc692014-12-16 00:32:11 -0800945 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
946 PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800947 case BASE_TYPE_ ## ENUM: \
948 builder_.Pad(field->padding); \
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -0700949 if (struct_def.fixed) { \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800950 CTYPE val; \
951 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
952 builder_.PushElement(val); \
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -0700953 } else { \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800954 CTYPE val, valdef; \
955 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
956 ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \
957 builder_.AddElement(field_value.offset, val, valdef); \
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -0700958 } \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800959 break;
960 FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
961 #undef FLATBUFFERS_TD
rw48dfc692014-12-16 00:32:11 -0800962 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
963 PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800964 case BASE_TYPE_ ## ENUM: \
965 builder_.Pad(field->padding); \
966 if (IsStruct(field->value.type)) { \
Shuhei Tanuma721d2192015-11-06 07:14:21 +0900967 SerializeStruct(*field->value.type.struct_def, field_value); \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800968 } else { \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800969 CTYPE val; \
970 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
971 builder_.AddOffset(field_value.offset, val); \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800972 } \
973 break;
974 FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD);
975 #undef FLATBUFFERS_TD
976 }
977 }
978 }
979 }
980 for (size_t i = 0; i < fieldn; i++) field_stack_.pop_back();
981
982 if (struct_def.fixed) {
983 builder_.ClearOffsets();
984 builder_.EndStruct();
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700985 assert(value);
986 // Temporarily store this struct in the value string, since it is to
987 // be serialized in-place elsewhere.
988 value->assign(
989 reinterpret_cast<const char *>(builder_.GetCurrentBufferPointer()),
990 struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800991 builder_.PopBytes(struct_def.bytesize);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800992 assert(!ovalue);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800993 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800994 auto val = builder_.EndTable(start,
995 static_cast<voffset_t>(struct_def.fields.vec.size()));
996 if (ovalue) *ovalue = val;
997 if (value) *value = NumToString(val);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800998 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800999 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001000}
1001
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001002CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001003 int count = 0;
Wouter van Oortmerssen6c2dc412015-01-16 16:57:04 -08001004 for (;;) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001005 if ((!opts.strict_json || !count) && Is(']')) { NEXT(); break; }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001006 Value val;
1007 val.type = type;
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -07001008 ECHECK(ParseAnyValue(val, nullptr, 0, nullptr));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001009 field_stack_.push_back(std::make_pair(val, nullptr));
1010 count++;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001011 if (Is(']')) { NEXT(); break; }
1012 EXPECT(',');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001013 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001014
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -07001015 builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
1016 InlineAlignment(type));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001017 for (int i = 0; i < count; i++) {
1018 // start at the back, since we're building the data backwards.
1019 auto &val = field_stack_.back().first;
1020 switch (val.type.base_type) {
rw48dfc692014-12-16 00:32:11 -08001021 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001022 case BASE_TYPE_ ## ENUM: \
1023 if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001024 else { \
1025 CTYPE elem; \
1026 ECHECK(atot(val.constant.c_str(), *this, &elem)); \
1027 builder_.PushElement(elem); \
1028 } \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001029 break;
1030 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1031 #undef FLATBUFFERS_TD
1032 }
1033 field_stack_.pop_back();
1034 }
1035
1036 builder_.ClearOffsets();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001037 *ovalue = builder_.EndVector(count);
1038 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001039}
1040
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001041CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001042 if (Is('(')) {
1043 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001044 for (;;) {
1045 auto name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001046 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen09521432014-11-17 17:27:26 -08001047 if (known_attributes_.find(name) == known_attributes_.end())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001048 return Error("user define attributes must be declared before use: " +
1049 name);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001050 auto e = new Value();
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001051 attributes->Add(name, e);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001052 if (Is(':')) {
1053 NEXT();
1054 ECHECK(ParseSingleValue(*e));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001055 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001056 if (Is(')')) { NEXT(); break; }
1057 EXPECT(',');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001058 }
1059 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001060 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001061}
1062
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001063CheckedError Parser::TryTypedValue(int dtoken, bool check, Value &e,
1064 BaseType req, bool *destmatch) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001065 bool match = dtoken == token_;
1066 if (match) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001067 *destmatch = true;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001068 e.constant = attribute_;
1069 if (!check) {
1070 if (e.type.base_type == BASE_TYPE_NONE) {
1071 e.type.base_type = req;
1072 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001073 return Error(std::string("type mismatch: expecting: ") +
1074 kTypeNames[e.type.base_type] +
1075 ", found: " +
1076 kTypeNames[req]);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001077 }
1078 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001079 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001080 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001081 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001082}
1083
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001084CheckedError Parser::ParseEnumFromString(Type &type, int64_t *result) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001085 *result = 0;
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001086 // Parse one or more enum identifiers, separated by spaces.
1087 const char *next = attribute_.c_str();
1088 do {
1089 const char *divider = strchr(next, ' ');
1090 std::string word;
1091 if (divider) {
1092 word = std::string(next, divider);
1093 next = divider + strspn(divider, " ");
1094 } else {
1095 word = next;
1096 next += word.length();
1097 }
1098 if (type.enum_def) { // The field has an enum type
1099 auto enum_val = type.enum_def->vals.Lookup(word);
1100 if (!enum_val)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001101 return Error("unknown enum value: " + word +
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001102 ", for enum: " + type.enum_def->name);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001103 *result |= enum_val->value;
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001104 } else { // No enum type, probably integral field.
1105 if (!IsInteger(type.base_type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001106 return Error("not a valid value for this field: " + word);
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001107 // TODO: could check if its a valid number constant here.
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -07001108 const char *dot = strrchr(word.c_str(), '.');
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001109 if (!dot)
1110 return Error("enum values need to be qualified by an enum type");
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001111 std::string enum_def_str(word.c_str(), dot);
1112 std::string enum_val_str(dot + 1, word.c_str() + word.length());
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -07001113 auto enum_def = LookupEnum(enum_def_str);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001114 if (!enum_def) return Error("unknown enum: " + enum_def_str);
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001115 auto enum_val = enum_def->vals.Lookup(enum_val_str);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001116 if (!enum_val) return Error("unknown enum value: " + enum_val_str);
1117 *result |= enum_val->value;
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001118 }
1119 } while(*next);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001120 return NoError();
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001121}
1122
Alex Amesd5753212015-02-13 15:58:29 -08001123
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001124CheckedError Parser::ParseHash(Value &e, FieldDef* field) {
Alex Amesd5753212015-02-13 15:58:29 -08001125 assert(field);
1126 Value *hash_name = field->attributes.Lookup("hash");
1127 switch (e.type.base_type) {
Wouter van Oortmerssen46497e42017-04-17 17:40:02 -07001128 case BASE_TYPE_INT: {
1129 auto hash = FindHashFunction32(hash_name->constant.c_str());
1130 int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
1131 e.constant = NumToString(hashed_value);
1132 break;
1133 }
Alex Amesd5753212015-02-13 15:58:29 -08001134 case BASE_TYPE_UINT: {
1135 auto hash = FindHashFunction32(hash_name->constant.c_str());
1136 uint32_t hashed_value = hash(attribute_.c_str());
1137 e.constant = NumToString(hashed_value);
1138 break;
1139 }
Wouter van Oortmerssen46497e42017-04-17 17:40:02 -07001140 case BASE_TYPE_LONG: {
1141 auto hash = FindHashFunction64(hash_name->constant.c_str());
1142 int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
1143 e.constant = NumToString(hashed_value);
1144 break;
1145 }
Alex Amesd5753212015-02-13 15:58:29 -08001146 case BASE_TYPE_ULONG: {
1147 auto hash = FindHashFunction64(hash_name->constant.c_str());
1148 uint64_t hashed_value = hash(attribute_.c_str());
1149 e.constant = NumToString(hashed_value);
1150 break;
1151 }
1152 default:
1153 assert(0);
1154 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001155 NEXT();
1156 return NoError();
Alex Amesd5753212015-02-13 15:58:29 -08001157}
1158
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001159CheckedError Parser::ParseSingleValue(Value &e) {
Wouter van Oortmerssend3ac0bc2016-06-15 13:54:17 -07001160 // First see if this could be a conversion function:
1161 if (token_ == kTokenIdentifier && *cursor_ == '(') {
1162 auto functionname = attribute_;
1163 NEXT();
1164 EXPECT('(');
1165 ECHECK(ParseSingleValue(e));
1166 EXPECT(')');
1167 #define FLATBUFFERS_FN_DOUBLE(name, op) \
1168 if (functionname == name) { \
1169 auto x = strtod(e.constant.c_str(), nullptr); \
1170 e.constant = NumToString(op); \
1171 }
1172 FLATBUFFERS_FN_DOUBLE("deg", x / M_PI * 180);
1173 FLATBUFFERS_FN_DOUBLE("rad", x * M_PI / 180);
1174 FLATBUFFERS_FN_DOUBLE("sin", sin(x));
1175 FLATBUFFERS_FN_DOUBLE("cos", cos(x));
1176 FLATBUFFERS_FN_DOUBLE("tan", tan(x));
1177 FLATBUFFERS_FN_DOUBLE("asin", asin(x));
1178 FLATBUFFERS_FN_DOUBLE("acos", acos(x));
1179 FLATBUFFERS_FN_DOUBLE("atan", atan(x));
1180 // TODO(wvo): add more useful conversion functions here.
1181 #undef FLATBUFFERS_FN_DOUBLE
1182 // Then check if this could be a string/identifier enum value:
1183 } else if (e.type.base_type != BASE_TYPE_STRING &&
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001184 e.type.base_type != BASE_TYPE_NONE &&
1185 (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001186 if (IsIdentifierStart(attribute_[0])) { // Enum value.
1187 int64_t val;
1188 ECHECK(ParseEnumFromString(e.type, &val));
1189 e.constant = NumToString(val);
1190 NEXT();
1191 } else { // Numeric constant in string.
1192 if (IsInteger(e.type.base_type)) {
Sahil Jainb6ba3222016-08-25 23:37:30 -04001193 char *end;
1194 e.constant = NumToString(StringToInt(attribute_.c_str(), &end));
1195 if (*end)
1196 return Error("invalid integer: " + attribute_);
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001197 } else if (IsFloat(e.type.base_type)) {
Sahil Jainb6ba3222016-08-25 23:37:30 -04001198 char *end;
1199 e.constant = NumToString(strtod(attribute_.c_str(), &end));
1200 if (*end)
1201 return Error("invalid float: " + attribute_);
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001202 } else {
1203 assert(0); // Shouldn't happen, we covered all types.
1204 e.constant = "0";
1205 }
Wouter van Oortmerssen83dc5ed2016-04-11 11:08:09 -07001206 NEXT();
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001207 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001208 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001209 bool match = false;
1210 ECHECK(TryTypedValue(kTokenIntegerConstant,
1211 IsScalar(e.type.base_type),
1212 e,
1213 BASE_TYPE_INT,
1214 &match));
1215 ECHECK(TryTypedValue(kTokenFloatConstant,
1216 IsFloat(e.type.base_type),
1217 e,
1218 BASE_TYPE_FLOAT,
1219 &match));
1220 ECHECK(TryTypedValue(kTokenStringConstant,
1221 e.type.base_type == BASE_TYPE_STRING,
1222 e,
1223 BASE_TYPE_STRING,
1224 &match));
1225 if (!match)
1226 return Error("cannot parse value starting with: " +
1227 TokenToStringId(token_));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001228 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001229 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001230}
1231
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001232StructDef *Parser::LookupCreateStruct(const std::string &name,
1233 bool create_if_new, bool definition) {
1234 std::string qualified_name = namespaces_.back()->GetFullyQualifiedName(name);
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001235 // See if it exists pre-declared by an unqualified use.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001236 auto struct_def = structs_.Lookup(name);
1237 if (struct_def && struct_def->predecl) {
1238 if (definition) {
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001239 // Make sure it has the current namespace, and is registered under its
1240 // qualified name.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001241 struct_def->defined_namespace = namespaces_.back();
1242 structs_.Move(name, qualified_name);
1243 }
1244 return struct_def;
1245 }
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001246 // See if it exists pre-declared by an qualified use.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001247 struct_def = structs_.Lookup(qualified_name);
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001248 if (struct_def && struct_def->predecl) {
1249 if (definition) {
1250 // Make sure it has the current namespace.
1251 struct_def->defined_namespace = namespaces_.back();
1252 }
1253 return struct_def;
1254 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001255 if (!definition) {
1256 // Search thru parent namespaces.
1257 for (size_t components = namespaces_.back()->components.size();
1258 components && !struct_def; components--) {
1259 struct_def = structs_.Lookup(
1260 namespaces_.back()->GetFullyQualifiedName(name, components - 1));
1261 }
1262 }
1263 if (!struct_def && create_if_new) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001264 struct_def = new StructDef();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001265 if (definition) {
1266 structs_.Add(qualified_name, struct_def);
1267 struct_def->name = name;
1268 struct_def->defined_namespace = namespaces_.back();
1269 } else {
1270 // Not a definition.
1271 // Rather than failing, we create a "pre declared" StructDef, due to
1272 // circular references, and check for errors at the end of parsing.
1273 // It is defined in the root namespace, since we don't know what the
1274 // final namespace will be.
1275 // TODO: maybe safer to use special namespace?
1276 structs_.Add(name, struct_def);
1277 struct_def->name = name;
1278 struct_def->defined_namespace = new Namespace();
1279 namespaces_.insert(namespaces_.begin(), struct_def->defined_namespace);
1280 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001281 }
1282 return struct_def;
1283}
1284
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001285CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
Max Galkinc3807fa2015-03-07 08:49:55 -08001286 std::vector<std::string> enum_comment = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001287 NEXT();
Max Galkinc3807fa2015-03-07 08:49:55 -08001288 std::string enum_name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001289 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001290 auto &enum_def = *new EnumDef();
Max Galkinc3807fa2015-03-07 08:49:55 -08001291 enum_def.name = enum_name;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001292 enum_def.file = file_being_parsed_;
Max Galkinc3807fa2015-03-07 08:49:55 -08001293 enum_def.doc_comment = enum_comment;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001294 enum_def.is_union = is_union;
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -07001295 enum_def.defined_namespace = namespaces_.back();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001296 if (enums_.Add(namespaces_.back()->GetFullyQualifiedName(enum_name),
1297 &enum_def))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001298 return Error("enum already exists: " + enum_name);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001299 if (is_union) {
1300 enum_def.underlying_type.base_type = BASE_TYPE_UTYPE;
1301 enum_def.underlying_type.enum_def = &enum_def;
Wouter van Oortmerssena5f50012014-07-02 12:01:21 -07001302 } else {
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -08001303 if (opts.proto_mode) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001304 enum_def.underlying_type.base_type = BASE_TYPE_INT;
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001305 } else {
1306 // Give specialized error message, since this type spec used to
1307 // be optional in the first FlatBuffers release.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001308 if (!Is(':')) {
1309 return Error("must specify the underlying integer type for this"
1310 " enum (e.g. \': short\', which was the default).");
1311 } else {
1312 NEXT();
1313 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001314 // Specify the integer type underlying this enum.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001315 ECHECK(ParseType(enum_def.underlying_type));
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001316 if (!IsInteger(enum_def.underlying_type.base_type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001317 return Error("underlying enum type must be integral");
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001318 }
Wouter van Oortmerssen3fb6a862014-07-14 17:49:04 -07001319 // Make this type refer back to the enum it was derived from.
1320 enum_def.underlying_type.enum_def = &enum_def;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001321 }
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001322 ECHECK(ParseMetaData(&enum_def.attributes));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001323 EXPECT('{');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001324 if (is_union) enum_def.vals.Add("NONE", new EnumVal("NONE", 0));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001325 for (;;) {
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -08001326 if (opts.proto_mode && attribute_ == "option") {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001327 ECHECK(ParseProtoOption());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001328 } else {
1329 auto value_name = attribute_;
1330 auto full_name = value_name;
1331 std::vector<std::string> value_comment = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001332 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen36390322016-06-17 18:16:11 -07001333 if (is_union) {
1334 ECHECK(ParseNamespacing(&full_name, &value_name));
Wouter van Oortmerssend70f5ac2016-07-29 10:45:32 -07001335 if (opts.union_value_namespacing) {
1336 // Since we can't namespace the actual enum identifiers, turn
1337 // namespace parts into part of the identifier.
1338 value_name = full_name;
1339 std::replace(value_name.begin(), value_name.end(), '.', '_');
1340 }
Wouter van Oortmerssen36390322016-06-17 18:16:11 -07001341 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001342 auto prevsize = enum_def.vals.vec.size();
1343 auto value = enum_def.vals.vec.size()
1344 ? enum_def.vals.vec.back()->value + 1
1345 : 0;
1346 auto &ev = *new EnumVal(value_name, value);
1347 if (enum_def.vals.Add(value_name, &ev))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001348 return Error("enum value already exists: " + value_name);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001349 ev.doc_comment = value_comment;
1350 if (is_union) {
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -07001351 if (Is(':')) {
1352 NEXT();
1353 ECHECK(ParseType(ev.union_type));
1354 if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
1355 ev.union_type.base_type != BASE_TYPE_STRING)
1356 return Error("union value type may only be table/struct/string");
1357 enum_def.uses_type_aliases = true;
1358 } else {
1359 ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
1360 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001361 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001362 if (Is('=')) {
1363 NEXT();
Wouter van Oortmerssend7793082016-02-10 11:25:31 -08001364 ev.value = StringToInt(attribute_.c_str());
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001365 EXPECT(kTokenIntegerConstant);
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -08001366 if (!opts.proto_mode && prevsize &&
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001367 enum_def.vals.vec[prevsize - 1]->value >= ev.value)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001368 return Error("enum values must be specified in ascending order");
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001369 }
Wouter van Oortmerssen9d01bfa2017-05-10 17:21:47 -07001370 if (is_union) {
1371 if (ev.value < 0 || ev.value >= 256)
1372 return Error("union enum value must fit in a ubyte");
1373 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001374 if (opts.proto_mode && Is('[')) {
1375 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001376 // ignore attributes on enums.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001377 while (token_ != ']') NEXT();
1378 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001379 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001380 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001381 if (!Is(opts.proto_mode ? ';' : ',')) break;
1382 NEXT();
1383 if (Is('}')) break;
1384 }
1385 EXPECT('}');
Wouter van Oortmerssen127d3502014-07-17 15:12:37 -07001386 if (enum_def.attributes.Lookup("bit_flags")) {
1387 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
1388 ++it) {
1389 if (static_cast<size_t>((*it)->value) >=
1390 SizeOf(enum_def.underlying_type.base_type) * 8)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001391 return Error("bit flag out of range of underlying integral type");
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001392 (*it)->value = 1LL << (*it)->value;
Wouter van Oortmerssen127d3502014-07-17 15:12:37 -07001393 }
1394 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001395 if (dest) *dest = &enum_def;
Wouter van Oortmerssen9b3d8b32017-01-27 15:28:57 -08001396 types_.Add(namespaces_.back()->GetFullyQualifiedName(enum_def.name),
1397 new Type(BASE_TYPE_UNION, nullptr, &enum_def));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001398 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001399}
1400
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001401CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001402 auto &struct_def = *LookupCreateStruct(name, true, true);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001403 if (!struct_def.predecl) return Error("datatype already exists: " + name);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001404 struct_def.predecl = false;
1405 struct_def.name = name;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001406 struct_def.file = file_being_parsed_;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001407 // Move this struct to the back of the vector just in case it was predeclared,
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001408 // to preserve declaration order.
Dmitry Ermolov370693a2017-04-20 02:55:41 +03001409 *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001410 *dest = &struct_def;
1411 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001412}
1413
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001414CheckedError Parser::CheckClash(std::vector<FieldDef*> &fields,
1415 StructDef *struct_def,
1416 const char *suffix,
1417 BaseType basetype) {
1418 auto len = strlen(suffix);
1419 for (auto it = fields.begin(); it != fields.end(); ++it) {
1420 auto &fname = (*it)->name;
1421 if (fname.length() > len &&
1422 fname.compare(fname.length() - len, len, suffix) == 0 &&
1423 (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
1424 auto field = struct_def->fields.Lookup(
1425 fname.substr(0, fname.length() - len));
1426 if (field && field->value.type.base_type == basetype)
1427 return Error("Field " + fname +
1428 " would clash with generated functions for field " +
1429 field->name);
1430 }
1431 }
1432 return NoError();
1433}
Wouter van Oortmerssend7793082016-02-10 11:25:31 -08001434
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001435static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
1436 auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
1437 auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
1438 return a_id < b_id;
1439}
1440
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001441CheckedError Parser::ParseDecl() {
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001442 std::vector<std::string> dc = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001443 bool fixed = Is(kTokenStruct);
1444 if (fixed) NEXT() else EXPECT(kTokenTable);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001445 std::string name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001446 EXPECT(kTokenIdentifier);
1447 StructDef *struct_def;
1448 ECHECK(StartStruct(name, &struct_def));
1449 struct_def->doc_comment = dc;
1450 struct_def->fixed = fixed;
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001451 ECHECK(ParseMetaData(&struct_def->attributes));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001452 struct_def->sortbysize =
1453 struct_def->attributes.Lookup("original_order") == nullptr && !fixed;
1454 EXPECT('{');
1455 while (token_ != '}') ECHECK(ParseField(*struct_def));
1456 auto force_align = struct_def->attributes.Lookup("force_align");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001457 if (fixed && force_align) {
1458 auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
1459 if (force_align->type.base_type != BASE_TYPE_INT ||
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001460 align < struct_def->minalign ||
Wouter van Oortmerssen6862b2f2016-10-17 18:02:19 -07001461 align > FLATBUFFERS_MAX_ALIGNMENT ||
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001462 align & (align - 1))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001463 return Error("force_align must be a power of two integer ranging from the"
Wouter van Oortmerssen6862b2f2016-10-17 18:02:19 -07001464 "struct\'s natural alignment to " +
1465 NumToString(FLATBUFFERS_MAX_ALIGNMENT));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001466 struct_def->minalign = align;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001467 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001468 struct_def->PadLastField(struct_def->minalign);
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001469 // Check if this is a table that has manual id assignments
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001470 auto &fields = struct_def->fields.vec;
1471 if (!struct_def->fixed && fields.size()) {
Wouter van Oortmerssen7fcbe722014-07-08 16:35:14 -07001472 size_t num_id_fields = 0;
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001473 for (auto it = fields.begin(); it != fields.end(); ++it) {
1474 if ((*it)->attributes.Lookup("id")) num_id_fields++;
1475 }
1476 // If any fields have ids..
1477 if (num_id_fields) {
1478 // Then all fields must have them.
1479 if (num_id_fields != fields.size())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001480 return Error(
1481 "either all fields or no fields must have an 'id' attribute");
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001482 // Simply sort by id, then the fields are the same as if no ids had
1483 // been specified.
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001484 std::sort(fields.begin(), fields.end(), compareFieldDefs);
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001485 // Verify we have a contiguous set, and reassign vtable offsets.
1486 for (int i = 0; i < static_cast<int>(fields.size()); i++) {
1487 if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str()))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001488 return Error("field id\'s must be consecutive from 0, id " +
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001489 NumToString(i) + " missing or set twice");
1490 fields[i]->value.offset = FieldIndexToOffset(static_cast<voffset_t>(i));
1491 }
1492 }
1493 }
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001494
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -07001495 ECHECK(CheckClash(fields, struct_def, UnionTypeFieldSuffix(),
1496 BASE_TYPE_UNION));
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001497 ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION));
1498 ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR));
1499 ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR));
1500 ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
1501 ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001502 EXPECT('}');
Wouter van Oortmerssen9b3d8b32017-01-27 15:28:57 -08001503 types_.Add(namespaces_.back()->GetFullyQualifiedName(struct_def->name),
1504 new Type(BASE_TYPE_STRUCT, struct_def, nullptr));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001505 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001506}
1507
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001508CheckedError Parser::ParseService() {
1509 std::vector<std::string> service_comment = doc_comment_;
1510 NEXT();
1511 auto service_name = attribute_;
1512 EXPECT(kTokenIdentifier);
1513 auto &service_def = *new ServiceDef();
1514 service_def.name = service_name;
1515 service_def.file = file_being_parsed_;
1516 service_def.doc_comment = service_comment;
1517 service_def.defined_namespace = namespaces_.back();
1518 if (services_.Add(namespaces_.back()->GetFullyQualifiedName(service_name),
1519 &service_def))
1520 return Error("service already exists: " + service_name);
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001521 ECHECK(ParseMetaData(&service_def.attributes));
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001522 EXPECT('{');
1523 do {
1524 auto rpc_name = attribute_;
1525 EXPECT(kTokenIdentifier);
1526 EXPECT('(');
1527 Type reqtype, resptype;
1528 ECHECK(ParseTypeIdent(reqtype));
1529 EXPECT(')');
1530 EXPECT(':');
1531 ECHECK(ParseTypeIdent(resptype));
1532 if (reqtype.base_type != BASE_TYPE_STRUCT || reqtype.struct_def->fixed ||
1533 resptype.base_type != BASE_TYPE_STRUCT || resptype.struct_def->fixed)
1534 return Error("rpc request and response types must be tables");
1535 auto &rpc = *new RPCCall();
1536 rpc.name = rpc_name;
1537 rpc.request = reqtype.struct_def;
1538 rpc.response = resptype.struct_def;
1539 if (service_def.calls.Add(rpc_name, &rpc))
1540 return Error("rpc already exists: " + rpc_name);
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001541 ECHECK(ParseMetaData(&rpc.attributes));
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001542 EXPECT(';');
1543 } while (token_ != '}');
1544 NEXT();
1545 return NoError();
1546}
1547
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001548bool Parser::SetRootType(const char *name) {
Wouter van Oortmerssen4dcaec72015-12-09 16:41:12 -08001549 root_struct_def_ = structs_.Lookup(name);
1550 if (!root_struct_def_)
1551 root_struct_def_ = structs_.Lookup(
1552 namespaces_.back()->GetFullyQualifiedName(name));
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07001553 return root_struct_def_ != nullptr;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001554}
1555
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001556void Parser::MarkGenerated() {
Wouter van Oortmerssen3881bbd2015-11-30 16:42:48 -08001557 // This function marks all existing definitions as having already
1558 // been generated, which signals no code for included files should be
1559 // generated.
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001560 for (auto it = enums_.vec.begin();
1561 it != enums_.vec.end(); ++it) {
1562 (*it)->generated = true;
1563 }
1564 for (auto it = structs_.vec.begin();
1565 it != structs_.vec.end(); ++it) {
1566 (*it)->generated = true;
1567 }
Wouter van Oortmerssen48f37f92016-04-13 18:16:05 -07001568 for (auto it = services_.vec.begin();
1569 it != services_.vec.end(); ++it) {
1570 (*it)->generated = true;
1571 }
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001572}
1573
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001574CheckedError Parser::ParseNamespace() {
1575 NEXT();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001576 auto ns = new Namespace();
1577 namespaces_.push_back(ns);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001578 if (token_ != ';') {
1579 for (;;) {
1580 ns->components.push_back(attribute_);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001581 EXPECT(kTokenIdentifier);
1582 if (Is('.')) NEXT() else break;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001583 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001584 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001585 EXPECT(';');
1586 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001587}
1588
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001589static bool compareEnumVals(const EnumVal *a, const EnumVal* b) {
1590 return a->value < b->value;
1591}
1592
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001593// Best effort parsing of .proto declarations, with the aim to turn them
1594// in the closest corresponding FlatBuffer equivalent.
1595// We parse everything as identifiers instead of keywords, since we don't
1596// want protobuf keywords to become invalid identifiers in FlatBuffers.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001597CheckedError Parser::ParseProtoDecl() {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001598 bool isextend = attribute_ == "extend";
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001599 if (attribute_ == "package") {
1600 // These are identical in syntax to FlatBuffer's namespace decl.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001601 ECHECK(ParseNamespace());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001602 } else if (attribute_ == "message" || isextend) {
Advay Mengle3ad85362015-03-31 02:03:11 -07001603 std::vector<std::string> struct_comment = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001604 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001605 StructDef *struct_def = nullptr;
1606 if (isextend) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001607 if (Is('.')) NEXT(); // qualified names may start with a . ?
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001608 auto id = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001609 EXPECT(kTokenIdentifier);
1610 ECHECK(ParseNamespacing(&id, nullptr));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001611 struct_def = LookupCreateStruct(id, false);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001612 if (!struct_def)
1613 return Error("cannot extend unknown message type: " + id);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001614 } else {
1615 std::string name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001616 EXPECT(kTokenIdentifier);
1617 ECHECK(StartStruct(name, &struct_def));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001618 // Since message definitions can be nested, we create a new namespace.
1619 auto ns = new Namespace();
1620 // Copy of current namespace.
1621 *ns = *namespaces_.back();
1622 // But with current message name.
1623 ns->components.push_back(name);
1624 namespaces_.push_back(ns);
1625 }
1626 struct_def->doc_comment = struct_comment;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001627 ECHECK(ParseProtoFields(struct_def, isextend, false));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001628 if (!isextend) {
1629 // We have to remove the nested namespace, but we can't just throw it
1630 // away, so put it at the beginning of the vector.
1631 auto ns = namespaces_.back();
1632 namespaces_.pop_back();
1633 namespaces_.insert(namespaces_.begin(), ns);
1634 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001635 if (Is(';')) NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001636 } else if (attribute_ == "enum") {
1637 // These are almost the same, just with different terminator:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001638 EnumDef *enum_def;
1639 ECHECK(ParseEnum(false, &enum_def));
1640 if (Is(';')) NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001641 // Protobuf allows them to be specified in any order, so sort afterwards.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001642 auto &v = enum_def->vals.vec;
Wouter van Oortmerssend7793082016-02-10 11:25:31 -08001643 std::sort(v.begin(), v.end(), compareEnumVals);
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001644
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001645 // Temp: remove any duplicates, as .fbs files can't handle them.
1646 for (auto it = v.begin(); it != v.end(); ) {
1647 if (it != v.begin() && it[0]->value == it[-1]->value) it = v.erase(it);
1648 else ++it;
1649 }
1650 } else if (attribute_ == "syntax") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001651 NEXT();
1652 EXPECT('=');
1653 EXPECT(kTokenStringConstant);
1654 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001655 } else if (attribute_ == "option") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001656 ECHECK(ParseProtoOption());
1657 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001658 } else if (attribute_ == "service") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001659 NEXT();
1660 EXPECT(kTokenIdentifier);
1661 ECHECK(ParseProtoCurliesOrIdent());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001662 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001663 return Error("don\'t know how to parse .proto declaration starting with " +
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001664 TokenToStringId(token_));
1665 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001666 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001667}
1668
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001669CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend,
1670 bool inside_oneof) {
1671 EXPECT('{');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001672 while (token_ != '}') {
1673 if (attribute_ == "message" || attribute_ == "extend" ||
1674 attribute_ == "enum") {
1675 // Nested declarations.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001676 ECHECK(ParseProtoDecl());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001677 } else if (attribute_ == "extensions") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001678 NEXT();
1679 EXPECT(kTokenIntegerConstant);
1680 if (Is(kTokenIdentifier)) {
1681 NEXT(); // to
1682 NEXT(); // num
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001683 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001684 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001685 } else if (attribute_ == "option") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001686 ECHECK(ParseProtoOption());
1687 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001688 } else if (attribute_ == "reserved") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001689 NEXT();
1690 EXPECT(kTokenIntegerConstant);
1691 while (Is(',')) { NEXT(); EXPECT(kTokenIntegerConstant); }
1692 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001693 } else {
1694 std::vector<std::string> field_comment = doc_comment_;
1695 // Parse the qualifier.
1696 bool required = false;
1697 bool repeated = false;
1698 bool oneof = false;
1699 if (!inside_oneof) {
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001700 if (attribute_ == "optional") {
1701 // This is the default.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001702 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001703 } else if (attribute_ == "required") {
1704 required = true;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001705 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001706 } else if (attribute_ == "repeated") {
1707 repeated = true;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001708 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001709 } else if (attribute_ == "oneof") {
1710 oneof = true;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001711 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001712 } else {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001713 // can't error, proto3 allows decls without any of the above.
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001714 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001715 }
1716 StructDef *anonymous_struct = nullptr;
1717 Type type;
1718 if (attribute_ == "group" || oneof) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001719 if (!oneof) EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001720 auto name = "Anonymous" + NumToString(anonymous_counter++);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001721 ECHECK(StartStruct(name, &anonymous_struct));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001722 type = Type(BASE_TYPE_STRUCT, anonymous_struct);
1723 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001724 ECHECK(ParseTypeFromProtoType(&type));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001725 }
1726 // Repeated elements get mapped to a vector.
1727 if (repeated) {
1728 type.element = type.base_type;
1729 type.base_type = BASE_TYPE_VECTOR;
1730 }
1731 std::string name = attribute_;
1732 // Protos may use our keywords "attribute" & "namespace" as an identifier.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001733 if (Is(kTokenAttribute) || Is(kTokenNameSpace)) {
1734 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001735 // TODO: simpler to just not make these keywords?
1736 name += "_"; // Have to make it not a keyword.
1737 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001738 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001739 }
1740 if (!oneof) {
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001741 // Parse the field id. Since we're just translating schemas, not
1742 // any kind of binary compatibility, we can safely ignore these, and
1743 // assign our own.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001744 EXPECT('=');
1745 EXPECT(kTokenIntegerConstant);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001746 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001747 FieldDef *field = nullptr;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001748 if (isextend) {
1749 // We allow a field to be re-defined when extending.
1750 // TODO: are there situations where that is problematic?
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001751 field = struct_def->fields.Lookup(name);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001752 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001753 if (!field) ECHECK(AddField(*struct_def, name, type, &field));
1754 field->doc_comment = field_comment;
1755 if (!IsScalar(type.base_type)) field->required = required;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001756 // See if there's a default specified.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001757 if (Is('[')) {
1758 NEXT();
1759 for (;;) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001760 auto key = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001761 ECHECK(ParseProtoKey());
1762 EXPECT('=');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001763 auto val = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001764 ECHECK(ParseProtoCurliesOrIdent());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001765 if (key == "default") {
1766 // Temp: skip non-numeric defaults (enums).
1767 auto numeric = strpbrk(val.c_str(), "0123456789-+.");
1768 if (IsScalar(type.base_type) && numeric == val.c_str())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001769 field->value.constant = val;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001770 } else if (key == "deprecated") {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001771 field->deprecated = val == "true";
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001772 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001773 if (!Is(',')) break;
1774 NEXT();
1775 }
1776 EXPECT(']');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001777 }
1778 if (anonymous_struct) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001779 ECHECK(ParseProtoFields(anonymous_struct, false, oneof));
1780 if (Is(';')) NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001781 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001782 EXPECT(';');
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001783 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001784 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001785 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001786 NEXT();
1787 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001788}
1789
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001790CheckedError Parser::ParseProtoKey() {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001791 if (token_ == '(') {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001792 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001793 // Skip "(a.b)" style custom attributes.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001794 while (token_ == '.' || token_ == kTokenIdentifier) NEXT();
1795 EXPECT(')');
1796 while (Is('.')) { NEXT(); EXPECT(kTokenIdentifier); }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001797 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001798 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001799 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001800 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001801}
1802
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001803CheckedError Parser::ParseProtoCurliesOrIdent() {
1804 if (Is('{')) {
1805 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001806 for (int nesting = 1; nesting; ) {
1807 if (token_ == '{') nesting++;
1808 else if (token_ == '}') nesting--;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001809 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001810 }
1811 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001812 NEXT(); // Any single token.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001813 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001814 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001815}
1816
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001817CheckedError Parser::ParseProtoOption() {
1818 NEXT();
1819 ECHECK(ParseProtoKey());
1820 EXPECT('=');
1821 ECHECK(ParseProtoCurliesOrIdent());
1822 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001823}
1824
1825// Parse a protobuf type, and map it to the corresponding FlatBuffer one.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001826CheckedError Parser::ParseTypeFromProtoType(Type *type) {
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001827 struct type_lookup { const char *proto_type; BaseType fb_type; };
1828 static type_lookup lookup[] = {
1829 { "float", BASE_TYPE_FLOAT }, { "double", BASE_TYPE_DOUBLE },
1830 { "int32", BASE_TYPE_INT }, { "int64", BASE_TYPE_LONG },
1831 { "uint32", BASE_TYPE_UINT }, { "uint64", BASE_TYPE_ULONG },
1832 { "sint32", BASE_TYPE_INT }, { "sint64", BASE_TYPE_LONG },
1833 { "fixed32", BASE_TYPE_UINT }, { "fixed64", BASE_TYPE_ULONG },
1834 { "sfixed32", BASE_TYPE_INT }, { "sfixed64", BASE_TYPE_LONG },
1835 { "bool", BASE_TYPE_BOOL },
1836 { "string", BASE_TYPE_STRING },
1837 { "bytes", BASE_TYPE_STRING },
1838 { nullptr, BASE_TYPE_NONE }
1839 };
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001840 for (auto tl = lookup; tl->proto_type; tl++) {
1841 if (attribute_ == tl->proto_type) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001842 type->base_type = tl->fb_type;
1843 NEXT();
1844 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001845 }
1846 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001847 if (Is('.')) NEXT(); // qualified names may start with a . ?
1848 ECHECK(ParseTypeIdent(*type));
1849 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001850}
1851
Nalinichandra Penke13d05942015-12-22 00:02:19 -08001852CheckedError Parser::SkipAnyJsonValue() {
1853 switch (token_) {
1854 case '{':
1855 ECHECK(SkipJsonObject());
1856 break;
1857 case kTokenStringConstant:
1858 ECHECK(SkipJsonString());
1859 break;
1860 case '[':
1861 ECHECK(SkipJsonArray());
1862 break;
1863 case kTokenIntegerConstant:
1864 EXPECT(kTokenIntegerConstant);
1865 break;
1866 case kTokenFloatConstant:
1867 EXPECT(kTokenFloatConstant);
1868 break;
1869 default:
Chris Pickette0b2f812016-01-05 10:58:40 -06001870 return Error(std::string("Unexpected token:") + std::string(1, static_cast<char>(token_)));
Nalinichandra Penke13d05942015-12-22 00:02:19 -08001871 }
1872 return NoError();
1873}
1874
1875CheckedError Parser::SkipJsonObject() {
1876 EXPECT('{');
1877 size_t fieldn = 0;
1878
Chris Pickett0e1601b2016-01-05 10:58:21 -06001879 for (;;) {
Nalinichandra Penke13d05942015-12-22 00:02:19 -08001880 if ((!opts.strict_json || !fieldn) && Is('}')) break;
1881
Nalinichandra Penkecbab2662016-02-22 14:27:08 -06001882 if (!Is(kTokenStringConstant)) {
Nalinichandra Penke13d05942015-12-22 00:02:19 -08001883 EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
Nalinichandra Penkecbab2662016-02-22 14:27:08 -06001884 }
1885 else {
1886 NEXT();
1887 }
Nalinichandra Penke13d05942015-12-22 00:02:19 -08001888
1889 EXPECT(':');
1890 ECHECK(SkipAnyJsonValue());
1891 fieldn++;
1892
1893 if (Is('}')) break;
1894 EXPECT(',');
1895 }
1896
1897 NEXT();
1898 return NoError();
1899}
1900
1901CheckedError Parser::SkipJsonArray() {
1902 EXPECT('[');
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -08001903
Chris Pickett0e1601b2016-01-05 10:58:21 -06001904 for (;;) {
Nalinichandra Penke13d05942015-12-22 00:02:19 -08001905 if (Is(']')) break;
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -08001906
Nalinichandra Penke13d05942015-12-22 00:02:19 -08001907 ECHECK(SkipAnyJsonValue());
1908
1909 if (Is(']')) break;
1910 EXPECT(',');
1911 }
1912
1913 NEXT();
1914 return NoError();
1915}
1916
1917CheckedError Parser::SkipJsonString() {
1918 EXPECT(kTokenStringConstant);
1919 return NoError();
1920}
1921
Wouter van Oortmerssen30642c52014-09-22 15:49:43 -07001922bool Parser::Parse(const char *source, const char **include_paths,
1923 const char *source_filename) {
Pavel Kalinnikov642254b2017-06-02 17:50:18 +02001924 return !DoParse(source, include_paths, source_filename, nullptr).Check();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001925}
1926
1927CheckedError Parser::DoParse(const char *source, const char **include_paths,
Wouter van Oortmerssen22743ca2017-05-24 15:21:26 -07001928 const char *source_filename,
1929 const char *include_filename) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001930 file_being_parsed_ = source_filename ? source_filename : "";
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08001931 if (source_filename &&
Pavel Kalinnikov642254b2017-06-02 17:50:18 +02001932 included_files_.find(source_filename) == included_files_.end()) {
1933 included_files_[source_filename] = include_filename ? include_filename : "";
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08001934 files_included_per_file_[source_filename] = std::set<std::string>();
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08001935 }
1936 if (!include_paths) {
Wouter van Oortmerssen1e6f8f52015-06-22 10:23:42 -07001937 static const char *current_directory[] = { "", nullptr };
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08001938 include_paths = current_directory;
1939 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001940 source_ = cursor_ = source;
1941 line_ = 1;
1942 error_.clear();
Yonggang Lifea6b522017-01-03 13:54:15 -08001943 field_stack_.clear();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001944 builder_.Clear();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001945 // Start with a blank namespace just in case this file doesn't have one.
1946 namespaces_.push_back(new Namespace());
Oli Wilkinsoncbe87472016-01-18 18:58:53 +00001947 ECHECK(SkipByteOrderMark());
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001948 NEXT();
Louis-Paul CORDIERe7e4dc72017-03-10 17:50:44 +01001949
1950 if (Is(kTokenEof))
1951 return Error("input file is empty");
1952
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001953 // Includes must come before type declarations:
1954 for (;;) {
1955 // Parse pre-include proto statements if any:
1956 if (opts.proto_mode &&
1957 (attribute_ == "option" || attribute_ == "syntax" ||
1958 attribute_ == "package")) {
1959 ECHECK(ParseProtoDecl());
Wouter van Oortmerssen3f936c52017-01-18 16:23:35 -08001960 } else if (Is(kTokenNativeInclude)) {
1961 NEXT();
1962 native_included_files_.emplace_back(attribute_);
1963 EXPECT(kTokenStringConstant);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001964 } else if (Is(kTokenInclude) ||
1965 (opts.proto_mode &&
1966 attribute_ == "import" &&
1967 Is(kTokenIdentifier))) {
1968 NEXT();
1969 if (opts.proto_mode && attribute_ == "public") NEXT();
Wouter van Oortmerssenaaf55982017-05-18 17:18:43 -07001970 auto name = flatbuffers::PosixPath(attribute_.c_str());
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001971 EXPECT(kTokenStringConstant);
1972 // Look for the file in include_paths.
1973 std::string filepath;
1974 for (auto paths = include_paths; paths && *paths; paths++) {
1975 filepath = flatbuffers::ConCatPathFileName(*paths, name);
1976 if(FileExists(filepath.c_str())) break;
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001977 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001978 if (filepath.empty())
1979 return Error("unable to locate include file: " + name);
1980 if (source_filename)
1981 files_included_per_file_[source_filename].insert(filepath);
Pavel Kalinnikov642254b2017-06-02 17:50:18 +02001982 if (included_files_.find(filepath) == included_files_.end()) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001983 // We found an include file that we have not parsed yet.
1984 // Load it and parse it.
1985 std::string contents;
1986 if (!LoadFile(filepath.c_str(), true, &contents))
1987 return Error("unable to load include file: " + name);
Wouter van Oortmerssen22743ca2017-05-24 15:21:26 -07001988 ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
1989 name.c_str()));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001990 // We generally do not want to output code for any included files:
1991 if (!opts.generate_all) MarkGenerated();
1992 // This is the easiest way to continue this file after an include:
1993 // instead of saving and restoring all the state, we simply start the
1994 // file anew. This will cause it to encounter the same include
1995 // statement again, but this time it will skip it, because it was
1996 // entered into included_files_.
1997 // This is recursive, but only go as deep as the number of include
1998 // statements.
Wouter van Oortmerssen22743ca2017-05-24 15:21:26 -07001999 return DoParse(source, include_paths, source_filename, include_filename);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002000 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002001 EXPECT(';');
2002 } else {
2003 break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002004 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002005 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002006 // Now parse all other kinds of declarations:
2007 while (token_ != kTokenEof) {
2008 if (opts.proto_mode) {
2009 ECHECK(ParseProtoDecl());
2010 } else if (token_ == kTokenNameSpace) {
2011 ECHECK(ParseNamespace());
2012 } else if (token_ == '{') {
2013 if (!root_struct_def_)
2014 return Error("no root type set to parse json with");
2015 if (builder_.GetSize()) {
2016 return Error("cannot have more than one json object in a file");
2017 }
2018 uoffset_t toff;
2019 ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
2020 builder_.Finish(Offset<Table>(toff),
2021 file_identifier_.length() ? file_identifier_.c_str() : nullptr);
2022 } else if (token_ == kTokenEnum) {
2023 ECHECK(ParseEnum(false, nullptr));
2024 } else if (token_ == kTokenUnion) {
2025 ECHECK(ParseEnum(true, nullptr));
2026 } else if (token_ == kTokenRootType) {
2027 NEXT();
2028 auto root_type = attribute_;
2029 EXPECT(kTokenIdentifier);
2030 ECHECK(ParseNamespacing(&root_type, nullptr));
2031 if (!SetRootType(root_type.c_str()))
2032 return Error("unknown root type: " + root_type);
2033 if (root_struct_def_->fixed)
2034 return Error("root type must be a table");
2035 EXPECT(';');
2036 } else if (token_ == kTokenFileIdentifier) {
2037 NEXT();
2038 file_identifier_ = attribute_;
2039 EXPECT(kTokenStringConstant);
2040 if (file_identifier_.length() !=
2041 FlatBufferBuilder::kFileIdentifierLength)
2042 return Error("file_identifier must be exactly " +
2043 NumToString(FlatBufferBuilder::kFileIdentifierLength) +
2044 " characters");
2045 EXPECT(';');
2046 } else if (token_ == kTokenFileExtension) {
2047 NEXT();
2048 file_extension_ = attribute_;
2049 EXPECT(kTokenStringConstant);
2050 EXPECT(';');
2051 } else if(token_ == kTokenInclude) {
2052 return Error("includes must come before declarations");
2053 } else if(token_ == kTokenAttribute) {
2054 NEXT();
2055 auto name = attribute_;
2056 EXPECT(kTokenStringConstant);
2057 EXPECT(';');
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002058 known_attributes_[name] = false;
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08002059 } else if (token_ == kTokenService) {
2060 ECHECK(ParseService());
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002061 } else {
2062 ECHECK(ParseDecl());
2063 }
2064 }
2065 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
2066 if ((*it)->predecl) {
2067 return Error("type referenced but not defined: " + (*it)->name);
2068 }
2069 }
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -07002070 // This check has to happen here and not earlier, because only now do we
2071 // know for sure what the type of these are.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002072 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
2073 auto &enum_def = **it;
2074 if (enum_def.is_union) {
2075 for (auto val_it = enum_def.vals.vec.begin();
2076 val_it != enum_def.vals.vec.end();
2077 ++val_it) {
2078 auto &val = **val_it;
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -07002079 if (opts.lang_to_generate != IDLOptions::kCpp &&
2080 val.union_type.struct_def && val.union_type.struct_def->fixed)
2081 return Error(
2082 "only tables can be union elements in the generated language: "
2083 + val.name);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002084 }
2085 }
2086 }
2087 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002088}
2089
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002090std::set<std::string> Parser::GetIncludedFilesRecursive(
2091 const std::string &file_name) const {
2092 std::set<std::string> included_files;
2093 std::list<std::string> to_process;
2094
2095 if (file_name.empty()) return included_files;
2096 to_process.push_back(file_name);
2097
2098 while (!to_process.empty()) {
2099 std::string current = to_process.front();
2100 to_process.pop_front();
2101 included_files.insert(current);
2102
2103 auto new_files = files_included_per_file_.at(current);
2104 for (auto it = new_files.begin(); it != new_files.end(); ++it) {
2105 if (included_files.find(*it) == included_files.end())
2106 to_process.push_back(*it);
2107 }
2108 }
2109
2110 return included_files;
2111}
2112
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002113// Schema serialization functionality:
2114
Chandra Penkeb63ebad2016-01-06 08:31:53 -08002115template<typename T> bool compareName(const T* a, const T* b) {
Xun Liudf0991b2016-09-14 10:33:06 -07002116 return a->defined_namespace->GetFullyQualifiedName(a->name)
2117 < b->defined_namespace->GetFullyQualifiedName(b->name);
Chandra Penkeb63ebad2016-01-06 08:31:53 -08002118}
2119
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002120template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
2121 // Pre-sort these vectors, such that we can set the correct indices for them.
2122 auto vec = defvec;
Chandra Penkeb63ebad2016-01-06 08:31:53 -08002123 std::sort(vec.begin(), vec.end(), compareName<T>);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002124 for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
2125}
2126
2127void Parser::Serialize() {
2128 builder_.Clear();
2129 AssignIndices(structs_.vec);
2130 AssignIndices(enums_.vec);
2131 std::vector<Offset<reflection::Object>> object_offsets;
2132 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002133 auto offset = (*it)->Serialize(&builder_, *this);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002134 object_offsets.push_back(offset);
2135 (*it)->serialized_location = offset.o;
2136 }
2137 std::vector<Offset<reflection::Enum>> enum_offsets;
2138 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002139 auto offset = (*it)->Serialize(&builder_, *this);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002140 enum_offsets.push_back(offset);
2141 (*it)->serialized_location = offset.o;
2142 }
2143 auto schema_offset = reflection::CreateSchema(
2144 builder_,
2145 builder_.CreateVectorOfSortedTables(&object_offsets),
2146 builder_.CreateVectorOfSortedTables(&enum_offsets),
2147 builder_.CreateString(file_identifier_),
2148 builder_.CreateString(file_extension_),
Wouter van Oortmerssen36c7e9a2015-06-29 15:21:48 -07002149 root_struct_def_
2150 ? root_struct_def_->serialized_location
2151 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002152 builder_.Finish(schema_offset, reflection::SchemaIdentifier());
2153}
2154
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002155Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
2156 const Parser &parser) const {
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002157 std::vector<Offset<reflection::Field>> field_offsets;
2158 for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
Wouter van Oortmerssen622b8d02015-06-15 15:57:48 -07002159 field_offsets.push_back(
2160 (*it)->Serialize(builder,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002161 static_cast<uint16_t>(it - fields.vec.begin()), parser));
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002162 }
Xun Liudf0991b2016-09-14 10:33:06 -07002163 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002164 return reflection::CreateObject(*builder,
Xun Liudf0991b2016-09-14 10:33:06 -07002165 builder->CreateString(qualified_name),
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002166 builder->CreateVectorOfSortedTables(
2167 &field_offsets),
Wouter van Oortmerssencb2b2be2015-06-23 16:06:35 -07002168 fixed,
2169 static_cast<int>(minalign),
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002170 static_cast<int>(bytesize),
Wouter van Oortmerssen1fb6b9e2017-02-13 16:15:55 -08002171 SerializeAttributes(builder, parser),
2172 parser.opts.binary_schema_comments
2173 ? builder->CreateVectorOfStrings(
2174 doc_comment)
2175 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002176}
2177
2178Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002179 uint16_t id,
2180 const Parser &parser) const {
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002181 return reflection::CreateField(*builder,
2182 builder->CreateString(name),
2183 value.type.Serialize(builder),
2184 id,
2185 value.offset,
2186 IsInteger(value.type.base_type)
2187 ? StringToInt(value.constant.c_str())
2188 : 0,
2189 IsFloat(value.type.base_type)
2190 ? strtod(value.constant.c_str(), nullptr)
2191 : 0.0,
2192 deprecated,
2193 required,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002194 key,
Wouter van Oortmerssen1fb6b9e2017-02-13 16:15:55 -08002195 SerializeAttributes(builder, parser),
2196 parser.opts.binary_schema_comments
2197 ? builder->CreateVectorOfStrings(doc_comment)
2198 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002199 // TODO: value.constant is almost always "0", we could save quite a bit of
2200 // space by sharing it. Same for common values of value.type.
2201}
2202
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002203Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
2204 const Parser &parser) const {
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002205 std::vector<Offset<reflection::EnumVal>> enumval_offsets;
2206 for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
2207 enumval_offsets.push_back((*it)->Serialize(builder));
2208 }
Xun Liudf0991b2016-09-14 10:33:06 -07002209 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002210 return reflection::CreateEnum(*builder,
Xun Liudf0991b2016-09-14 10:33:06 -07002211 builder->CreateString(qualified_name),
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002212 builder->CreateVector(enumval_offsets),
2213 is_union,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002214 underlying_type.Serialize(builder),
Wouter van Oortmerssen1fb6b9e2017-02-13 16:15:55 -08002215 SerializeAttributes(builder, parser),
2216 parser.opts.binary_schema_comments
2217 ? builder->CreateVectorOfStrings(doc_comment)
2218 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002219}
2220
2221Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const
2222 {
2223 return reflection::CreateEnumVal(*builder,
2224 builder->CreateString(name),
2225 value,
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -07002226 union_type.struct_def
2227 ? union_type.struct_def->
2228 serialized_location
2229 : 0,
2230 union_type.Serialize(builder));
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002231}
2232
2233Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
2234 return reflection::CreateType(*builder,
2235 static_cast<reflection::BaseType>(base_type),
2236 static_cast<reflection::BaseType>(element),
2237 struct_def ? struct_def->index :
2238 (enum_def ? enum_def->index : -1));
2239}
2240
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002241flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<
2242 reflection::KeyValue>>>
2243 Definition::SerializeAttributes(FlatBufferBuilder *builder,
2244 const Parser &parser) const {
2245 std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -07002246 for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) {
2247 auto it = parser.known_attributes_.find(kv->first);
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002248 assert(it != parser.known_attributes_.end());
2249 if (!it->second) { // Custom attribute.
2250 attrs.push_back(
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -07002251 reflection::CreateKeyValue(*builder, builder->CreateString(kv->first),
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002252 builder->CreateString(
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -07002253 kv->second->constant)));
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002254 }
2255 }
2256 if (attrs.size()) {
2257 return builder->CreateVectorOfSortedTables(&attrs);
2258 } else {
2259 return 0;
2260 }
2261}
2262
Wouter van Oortmerssen05b00c52016-07-20 17:24:50 -07002263std::string Parser::ConformTo(const Parser &base) {
2264 for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) {
2265 auto &struct_def = **sit;
2266 auto qualified_name =
2267 struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name);
2268 auto struct_def_base = base.structs_.Lookup(qualified_name);
2269 if (!struct_def_base) continue;
2270 for (auto fit = struct_def.fields.vec.begin();
2271 fit != struct_def.fields.vec.end(); ++fit) {
2272 auto &field = **fit;
2273 auto field_base = struct_def_base->fields.Lookup(field.name);
2274 if (field_base) {
2275 if (field.value.offset != field_base->value.offset)
2276 return "offsets differ for field: " + field.name;
2277 if (field.value.constant != field_base->value.constant)
2278 return "defaults differ for field: " + field.name;
2279 if (!EqualByName(field.value.type, field_base->value.type))
2280 return "types differ for field: " + field.name;
2281 } else {
2282 // Doesn't have to exist, deleting fields is fine.
2283 // But we should check if there is a field that has the same offset
2284 // but is incompatible (in the case of field renaming).
2285 for (auto fbit = struct_def_base->fields.vec.begin();
2286 fbit != struct_def_base->fields.vec.end(); ++fbit) {
2287 field_base = *fbit;
2288 if (field.value.offset == field_base->value.offset) {
2289 if (!EqualByName(field.value.type, field_base->value.type))
2290 return "field renamed to different type: " + field.name;
2291 break;
2292 }
2293 }
2294 }
2295 }
2296 }
2297 for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) {
2298 auto &enum_def = **eit;
2299 auto qualified_name =
2300 enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name);
2301 auto enum_def_base = base.enums_.Lookup(qualified_name);
2302 if (!enum_def_base) continue;
2303 for (auto evit = enum_def.vals.vec.begin();
2304 evit != enum_def.vals.vec.end(); ++evit) {
2305 auto &enum_val = **evit;
2306 auto enum_val_base = enum_def_base->vals.Lookup(enum_val.name);
2307 if (enum_val_base) {
2308 if (enum_val.value != enum_val_base->value)
2309 return "values differ for enum: " + enum_val.name;
2310 }
2311 }
2312 }
2313 return "";
2314}
2315
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002316} // namespace flatbuffers