blob: c0a3b8f242512c16a15914e1480731710a5bbc53 [file] [log] [blame]
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001/*
2 * Copyright 2014 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <algorithm>
Gabriel Martinezdf4909e2014-11-04 10:00:56 -080018#include <list>
Christian Helmich89a68942017-07-29 02:27:51 +090019#include <iostream>
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080020
Wouter van Oortmerssend3ac0bc2016-06-15 13:54:17 -070021#include <math.h>
22
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080023#include "flatbuffers/idl.h"
24#include "flatbuffers/util.h"
25
26namespace flatbuffers {
27
Bastien Brunnenstein85b131a2017-12-05 00:06:13 +010028const double kPi = 3.14159265358979323846;
29
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080030const char *const kTypeNames[] = {
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -070031 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
MikkelFJf2b37052017-08-02 17:07:43 +020032 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
rw48dfc692014-12-16 00:32:11 -080033 IDLTYPE,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080034 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
35 #undef FLATBUFFERS_TD
36 nullptr
37};
38
39const char kTypeSizes[] = {
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -070040 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
MikkelFJf2b37052017-08-02 17:07:43 +020041 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen557c88c2014-09-16 17:37:17 -070042 sizeof(CTYPE),
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080043 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
44 #undef FLATBUFFERS_TD
45};
46
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -070047// The enums in the reflection schema should match the ones we use internally.
48// Compare the last element to check if these go out of sync.
49static_assert(BASE_TYPE_UNION ==
Wouter van Oortmerssen622b8d02015-06-15 15:57:48 -070050 static_cast<BaseType>(reflection::Union),
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -070051 "enums don't match");
52
Wouter van Oortmerssen451272b2015-12-29 16:33:00 -080053// Any parsing calls have to be wrapped in this macro, which automates
54// handling of recursive error checking a bit. It will check the received
55// CheckedError object, and return straight away on error.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080056#define ECHECK(call) { auto ce = (call); if (ce.Check()) return ce; }
Wouter van Oortmerssen451272b2015-12-29 16:33:00 -080057
58// These two functions are called hundreds of times below, so define a short
59// form:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080060#define NEXT() ECHECK(Next())
61#define EXPECT(tok) ECHECK(Expect(tok))
62
Ben Hamiltonf6416d82016-08-01 14:04:51 -070063static bool ValidateUTF8(const std::string &str) {
64 const char *s = &str[0];
65 const char * const sEnd = s + str.length();
66 while (s < sEnd) {
67 if (FromUTF8(&s) < 0) {
68 return false;
69 }
70 }
71 return true;
72}
73
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -070074void Parser::Message(const std::string &msg) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080075 error_ = file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : "";
76 #ifdef _WIN32
77 error_ += "(" + NumToString(line_) + ")"; // MSVC alike
78 #else
79 if (file_being_parsed_.length()) error_ += ":";
80 error_ += NumToString(line_) + ":0"; // gcc alike
81 #endif
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -070082 error_ += ": " + msg;
83}
84
85void Parser::Warning(const std::string &msg) {
86 Message("warning: " + msg);
87}
88
89CheckedError Parser::Error(const std::string &msg) {
90 Message("error: " + msg);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080091 return CheckedError(true);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080092}
93
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080094inline CheckedError NoError() { return CheckedError(false); }
95
Jason Stubbsa07f0d42017-04-18 04:19:43 +100096inline std::string OutOfRangeErrorMsg(int64_t val, const std::string &op,
97 int64_t limit) {
98 const std::string cause = NumToString(val) + op + NumToString(limit);
99 return "constant does not fit (" + cause + ")";
100}
101
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800102// Ensure that integer values we parse fit inside the declared integer type.
Jason Stubbsa07f0d42017-04-18 04:19:43 +1000103CheckedError Parser::CheckInRange(int64_t val, int64_t min, int64_t max) {
104 if (val < min)
105 return Error(OutOfRangeErrorMsg(val, " < ", min));
106 else if (val > max)
107 return Error(OutOfRangeErrorMsg(val, " > ", max));
108 else
109 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800110}
111
112// atot: templated version of atoi/atof: convert a string to an instance of T.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800113template<typename T> inline CheckedError atot(const char *s, Parser &parser,
114 T *val) {
115 int64_t i = StringToInt(s);
Stewart Milesa8923222017-07-13 06:27:39 -0700116 const int64_t min = flatbuffers::numeric_limits<T>::min();
117 const int64_t max = flatbuffers::numeric_limits<T>::max();
Jason Stubbsa07f0d42017-04-18 04:19:43 +1000118 ECHECK(parser.CheckInRange(i, min, max));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800119 *val = (T)i;
120 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800121}
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800122template<> inline CheckedError atot<uint64_t>(const char *s, Parser &parser,
123 uint64_t *val) {
124 (void)parser;
125 *val = StringToUInt(s);
126 return NoError();
127}
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800128template<> inline CheckedError atot<bool>(const char *s, Parser &parser,
129 bool *val) {
130 (void)parser;
131 *val = 0 != atoi(s);
132 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800133}
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800134template<> inline CheckedError atot<float>(const char *s, Parser &parser,
135 float *val) {
136 (void)parser;
137 *val = static_cast<float>(strtod(s, nullptr));
138 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800139}
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800140template<> inline CheckedError atot<double>(const char *s, Parser &parser,
141 double *val) {
142 (void)parser;
143 *val = strtod(s, nullptr);
144 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800145}
146
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800147template<> inline CheckedError atot<Offset<void>>(const char *s, Parser &parser,
148 Offset<void> *val) {
149 (void)parser;
150 *val = Offset<void>(atoi(s));
151 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800152}
153
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700154std::string Namespace::GetFullyQualifiedName(const std::string &name,
155 size_t max_components) const {
156 // Early exit if we don't have a defined namespace.
157 if (components.size() == 0 || !max_components) {
158 return name;
159 }
160 std::stringstream stream;
161 for (size_t i = 0; i < std::min(components.size(), max_components);
162 i++) {
163 if (i) {
164 stream << ".";
165 }
166 stream << components[i];
167 }
Wouter van Oortmerssen8c1a7232017-01-09 15:54:31 -0800168 if (name.length()) stream << "." << name;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700169 return stream.str();
170}
171
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800172// Declare tokens we'll use. Single character tokens are represented by their
173// ascii character code (e.g. '{'), others above 256.
174#define FLATBUFFERS_GEN_TOKENS(TD) \
175 TD(Eof, 256, "end of file") \
176 TD(StringConstant, 257, "string constant") \
177 TD(IntegerConstant, 258, "integer constant") \
178 TD(FloatConstant, 259, "float constant") \
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -0700179 TD(Identifier, 260, "identifier")
Wouter van Oortmerssen8f80fec2014-07-29 10:29:38 -0700180#ifdef __GNUC__
181__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
182#endif
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800183enum {
Wouter van Oortmerssen75349ae2014-07-09 11:44:26 -0700184 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800185 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
186 #undef FLATBUFFERS_TOKEN
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800187};
188
189static std::string TokenToString(int t) {
190 static const char *tokens[] = {
191 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
192 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
193 #undef FLATBUFFERS_TOKEN
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -0700194 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
MikkelFJf2b37052017-08-02 17:07:43 +0200195 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
rw48dfc692014-12-16 00:32:11 -0800196 IDLTYPE,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800197 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
198 #undef FLATBUFFERS_TD
199 };
200 if (t < 256) { // A single ascii char token.
201 std::string s;
Wouter van Oortmerssen8e409022014-09-02 17:32:12 -0700202 s.append(1, static_cast<char>(t));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800203 return s;
204 } else { // Other tokens.
205 return tokens[t - 256];
206 }
207}
208
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700209std::string Parser::TokenToStringId(int t) {
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -0700210 return t == kTokenIdentifier ? attribute_ : TokenToString(t);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700211}
212
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700213// Parses exactly nibbles worth of hex digits into a number, or error.
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800214CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) {
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700215 for (int i = 0; i < nibbles; i++)
Chris Pickett30013b42016-01-05 13:38:03 -0600216 if (!isxdigit(static_cast<const unsigned char>(cursor_[i])))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800217 return Error("escape code must be followed by " + NumToString(nibbles) +
218 " hex digits");
Hiroshi Matsunaga7cf74cb2015-01-09 03:38:14 +0900219 std::string target(cursor_, cursor_ + nibbles);
Sahil Jainb6ba3222016-08-25 23:37:30 -0400220 *val = StringToUInt(target.c_str(), nullptr, 16);
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700221 cursor_ += nibbles;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800222 return NoError();
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700223}
224
Oli Wilkinsoncbe87472016-01-18 18:58:53 +0000225CheckedError Parser::SkipByteOrderMark() {
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -0700226 if (static_cast<unsigned char>(*cursor_) != 0xef)
227 return NoError();
Oli Wilkinsoncbe87472016-01-18 18:58:53 +0000228 cursor_++;
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -0700229 if (static_cast<unsigned char>(*cursor_) != 0xbb)
230 return Error("invalid utf-8 byte order mark");
Wouter van Oortmerssenf6330ab2016-04-22 11:26:47 -0700231 cursor_++;
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -0700232 if (static_cast<unsigned char>(*cursor_) != 0xbf)
233 return Error("invalid utf-8 byte order mark");
Wouter van Oortmerssenf6330ab2016-04-22 11:26:47 -0700234 cursor_++;
Oli Wilkinsoncbe87472016-01-18 18:58:53 +0000235 return NoError();
236}
237
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -0800238bool IsIdentifierStart(char c) {
239 return isalpha(static_cast<unsigned char>(c)) || c == '_';
240}
241
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800242CheckedError Parser::Next() {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800243 doc_comment_.clear();
244 bool seen_newline = false;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700245 attribute_.clear();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800246 for (;;) {
247 char c = *cursor_++;
248 token_ = c;
249 switch (c) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800250 case '\0': cursor_--; token_ = kTokenEof; return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800251 case ' ': case '\r': case '\t': break;
252 case '\n': line_++; seen_newline = true; break;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800253 case '{': case '}': case '(': case ')': case '[': case ']':
254 case ',': case ':': case ';': case '=': return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800255 case '.':
Chris Pickett30013b42016-01-05 13:38:03 -0600256 if(!isdigit(static_cast<const unsigned char>(*cursor_))) return NoError();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800257 return Error("floating point constant can\'t start with \".\"");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800258 case '\"':
Ben Gertzfield6704b192016-04-28 12:27:38 -0700259 case '\'': {
260 int unicode_high_surrogate = -1;
261
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700262 while (*cursor_ != c) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800263 if (*cursor_ < ' ' && *cursor_ >= 0)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800264 return Error("illegal character in string constant");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800265 if (*cursor_ == '\\') {
266 cursor_++;
Ben Gertzfield6704b192016-04-28 12:27:38 -0700267 if (unicode_high_surrogate != -1 &&
268 *cursor_ != 'u') {
269 return Error(
270 "illegal Unicode sequence (unpaired high surrogate)");
271 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800272 switch (*cursor_) {
273 case 'n': attribute_ += '\n'; cursor_++; break;
274 case 't': attribute_ += '\t'; cursor_++; break;
275 case 'r': attribute_ += '\r'; cursor_++; break;
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700276 case 'b': attribute_ += '\b'; cursor_++; break;
277 case 'f': attribute_ += '\f'; cursor_++; break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800278 case '\"': attribute_ += '\"'; cursor_++; break;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700279 case '\'': attribute_ += '\''; cursor_++; break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800280 case '\\': attribute_ += '\\'; cursor_++; break;
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700281 case '/': attribute_ += '/'; cursor_++; break;
282 case 'x': { // Not in the JSON standard
283 cursor_++;
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800284 uint64_t val;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800285 ECHECK(ParseHexNum(2, &val));
286 attribute_ += static_cast<char>(val);
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700287 break;
288 }
289 case 'u': {
290 cursor_++;
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800291 uint64_t val;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800292 ECHECK(ParseHexNum(4, &val));
Ben Gertzfield6704b192016-04-28 12:27:38 -0700293 if (val >= 0xD800 && val <= 0xDBFF) {
294 if (unicode_high_surrogate != -1) {
295 return Error(
296 "illegal Unicode sequence (multiple high surrogates)");
297 } else {
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -0700298 unicode_high_surrogate = static_cast<int>(val);
Ben Gertzfield6704b192016-04-28 12:27:38 -0700299 }
300 } else if (val >= 0xDC00 && val <= 0xDFFF) {
301 if (unicode_high_surrogate == -1) {
302 return Error(
303 "illegal Unicode sequence (unpaired low surrogate)");
304 } else {
305 int code_point = 0x10000 +
306 ((unicode_high_surrogate & 0x03FF) << 10) +
307 (val & 0x03FF);
308 ToUTF8(code_point, &attribute_);
309 unicode_high_surrogate = -1;
310 }
311 } else {
312 if (unicode_high_surrogate != -1) {
313 return Error(
314 "illegal Unicode sequence (unpaired high surrogate)");
315 }
316 ToUTF8(static_cast<int>(val), &attribute_);
317 }
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700318 break;
319 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800320 default: return Error("unknown escape code in string constant");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800321 }
322 } else { // printable chars + UTF-8 bytes
Ben Gertzfield6704b192016-04-28 12:27:38 -0700323 if (unicode_high_surrogate != -1) {
324 return Error(
325 "illegal Unicode sequence (unpaired high surrogate)");
326 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800327 attribute_ += *cursor_++;
328 }
329 }
Ben Gertzfield6704b192016-04-28 12:27:38 -0700330 if (unicode_high_surrogate != -1) {
331 return Error(
332 "illegal Unicode sequence (unpaired high surrogate)");
333 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800334 cursor_++;
Ben Hamiltonf6416d82016-08-01 14:04:51 -0700335 if (!opts.allow_non_utf8 && !ValidateUTF8(attribute_)) {
336 return Error("illegal UTF-8 sequence");
337 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800338 token_ = kTokenStringConstant;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800339 return NoError();
Ben Gertzfield6704b192016-04-28 12:27:38 -0700340 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800341 case '/':
342 if (*cursor_ == '/') {
343 const char *start = ++cursor_;
Mormegila8d69622015-04-14 18:09:08 +0200344 while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800345 if (*start == '/') { // documentation comment
Zbigniew Mandziejewicz07d59652014-10-22 22:40:03 +0800346 if (cursor_ != source_ && !seen_newline)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800347 return Error(
348 "a documentation comment should be on a line on its own");
Gabriel Martinez730c0ca2014-09-24 11:46:32 -0700349 doc_comment_.push_back(std::string(start + 1, cursor_));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800350 }
351 break;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700352 } else if (*cursor_ == '*') {
353 cursor_++;
354 // TODO: make nested.
355 while (*cursor_ != '*' || cursor_[1] != '/') {
Wouter van Oortmerssenab51b032016-10-07 17:07:39 -0700356 if (*cursor_ == '\n') line_++;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800357 if (!*cursor_) return Error("end of file in comment");
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700358 cursor_++;
359 }
360 cursor_ += 2;
361 break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800362 }
363 // fall thru
364 default:
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -0800365 if (IsIdentifierStart(c)) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800366 // Collect all chars of an identifier:
367 const char *start = cursor_ - 1;
368 while (isalnum(static_cast<unsigned char>(*cursor_)) ||
369 *cursor_ == '_')
370 cursor_++;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800371 attribute_.append(start, cursor_);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800372 token_ = kTokenIdentifier;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800373 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800374 } else if (isdigit(static_cast<unsigned char>(c)) || c == '-') {
375 const char *start = cursor_ - 1;
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800376 if (c == '-' && *cursor_ == '0' &&
377 (cursor_[1] == 'x' || cursor_[1] == 'X')) {
Ramanf6f88e52016-07-12 19:47:53 +0200378 ++start;
379 ++cursor_;
380 attribute_.append(&c, &c + 1);
381 c = '0';
382 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700383 if (c == '0' && (*cursor_ == 'x' || *cursor_ == 'X')) {
384 cursor_++;
385 while (isxdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
386 attribute_.append(start + 2, cursor_);
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800387 attribute_ = NumToString(static_cast<int64_t>(
388 StringToUInt(attribute_.c_str(), nullptr, 16)));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700389 token_ = kTokenIntegerConstant;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800390 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700391 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800392 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700393 if (*cursor_ == '.' || *cursor_ == 'e' || *cursor_ == 'E') {
394 if (*cursor_ == '.') {
395 cursor_++;
396 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
397 }
Wouter van Oortmerssen93df5692014-07-10 13:40:55 -0700398 // See if this float has a scientific notation suffix. Both JSON
399 // and C++ (through strtod() we use) have the same format:
400 if (*cursor_ == 'e' || *cursor_ == 'E') {
401 cursor_++;
402 if (*cursor_ == '+' || *cursor_ == '-') cursor_++;
403 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
404 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800405 token_ = kTokenFloatConstant;
406 } else {
407 token_ = kTokenIntegerConstant;
408 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800409 attribute_.append(start, cursor_);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800410 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800411 }
412 std::string ch;
413 ch = c;
414 if (c < ' ' || c > '~') ch = "code: " + NumToString(c);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800415 return Error("illegal character: " + ch);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800416 }
417 }
418}
419
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800420// Check if a given token is next.
421bool Parser::Is(int t) {
422 return t == token_;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800423}
424
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -0700425bool Parser::IsIdent(const char *id) {
426 return token_ == kTokenIdentifier && attribute_ == id;
427}
428
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800429// Expect a given token to be next, consume it, or error if not present.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800430CheckedError Parser::Expect(int t) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800431 if (t != token_) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800432 return Error("expecting: " + TokenToString(t) + " instead got: " +
433 TokenToStringId(token_));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800434 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800435 NEXT();
436 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800437}
438
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800439CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) {
440 while (Is('.')) {
441 NEXT();
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700442 *id += ".";
443 *id += attribute_;
444 if (last) *last = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800445 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700446 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800447 return NoError();
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700448}
449
450EnumDef *Parser::LookupEnum(const std::string &id) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700451 // Search thru parent namespaces.
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -0700452 for (int components = static_cast<int>(current_namespace_->components.size());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700453 components >= 0; components--) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800454 auto ed = enums_.Lookup(
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -0700455 current_namespace_->GetFullyQualifiedName(id, components));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700456 if (ed) return ed;
457 }
458 return nullptr;
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700459}
460
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -0700461StructDef *Parser::LookupStruct(const std::string &id) const {
462 auto sd = structs_.Lookup(id);
463 if (sd) sd->refcount++;
464 return sd;
465}
466
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800467CheckedError Parser::ParseTypeIdent(Type &type) {
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700468 std::string id = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800469 EXPECT(kTokenIdentifier);
470 ECHECK(ParseNamespacing(&id, nullptr));
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700471 auto enum_def = LookupEnum(id);
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700472 if (enum_def) {
473 type = enum_def->underlying_type;
474 if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
475 } else {
476 type.base_type = BASE_TYPE_STRUCT;
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700477 type.struct_def = LookupCreateStruct(id);
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700478 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800479 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700480}
481
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800482// Parse any IDL type.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800483CheckedError Parser::ParseType(Type &type) {
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -0700484 if (token_ == kTokenIdentifier) {
485 if (IsIdent("bool")) {
486 type.base_type = BASE_TYPE_BOOL;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800487 NEXT();
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -0700488 } else if (IsIdent("byte") || IsIdent("int8")) {
489 type.base_type = BASE_TYPE_CHAR;
490 NEXT();
491 } else if (IsIdent("ubyte") || IsIdent("uint8")) {
492 type.base_type = BASE_TYPE_UCHAR;
493 NEXT();
494 } else if (IsIdent("short") || IsIdent("int16")) {
495 type.base_type = BASE_TYPE_SHORT;
496 NEXT();
497 } else if (IsIdent("ushort") || IsIdent("uint16")) {
498 type.base_type = BASE_TYPE_USHORT;
499 NEXT();
500 } else if (IsIdent("int") || IsIdent("int32")) {
501 type.base_type = BASE_TYPE_INT;
502 NEXT();
503 } else if (IsIdent("uint") || IsIdent("uint32")) {
504 type.base_type = BASE_TYPE_UINT;
505 NEXT();
506 } else if (IsIdent("long") || IsIdent("int64")) {
507 type.base_type = BASE_TYPE_LONG;
508 NEXT();
509 } else if (IsIdent("ulong") || IsIdent("uint64")) {
510 type.base_type = BASE_TYPE_ULONG;
511 NEXT();
512 } else if (IsIdent("float") || IsIdent("float32")) {
513 type.base_type = BASE_TYPE_FLOAT;
514 NEXT();
515 } else if (IsIdent("double") || IsIdent("float64")) {
516 type.base_type = BASE_TYPE_DOUBLE;
517 NEXT();
518 } else if (IsIdent("string")) {
519 type.base_type = BASE_TYPE_STRING;
520 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800521 } else {
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -0700522 ECHECK(ParseTypeIdent(type));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800523 }
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -0700524 } else if (token_ == '[') {
525 NEXT();
526 Type subtype;
527 ECHECK(ParseType(subtype));
528 if (subtype.base_type == BASE_TYPE_VECTOR) {
529 // We could support this, but it will complicate things, and it's
530 // easier to work around with a struct around the inner vector.
531 return Error(
532 "nested vector types not supported (wrap in table first).");
533 }
534 type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
535 type.element = subtype.base_type;
536 EXPECT(']');
537 } else {
538 return Error("illegal type syntax");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800539 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800540 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800541}
542
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800543CheckedError Parser::AddField(StructDef &struct_def, const std::string &name,
544 const Type &type, FieldDef **dest) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800545 auto &field = *new FieldDef();
546 field.value.offset =
547 FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size()));
548 field.name = name;
Gabriel Martinezdf4909e2014-11-04 10:00:56 -0800549 field.file = struct_def.file;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800550 field.value.type = type;
551 if (struct_def.fixed) { // statically compute the field offset
552 auto size = InlineSize(type);
553 auto alignment = InlineAlignment(type);
554 // structs_ need to have a predictable format, so we need to align to
555 // the largest scalar
556 struct_def.minalign = std::max(struct_def.minalign, alignment);
557 struct_def.PadLastField(alignment);
Wouter van Oortmerssen12563072014-06-30 15:56:31 -0700558 field.value.offset = static_cast<voffset_t>(struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800559 struct_def.bytesize += size;
560 }
561 if (struct_def.fields.Add(name, &field))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800562 return Error("field already exists: " + name);
563 *dest = &field;
564 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800565}
566
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800567CheckedError Parser::ParseField(StructDef &struct_def) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800568 std::string name = attribute_;
Wouter van Oortmerssene9f1f4d2017-06-02 15:55:02 -0700569
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -0700570 if (LookupStruct(name))
Wouter van Oortmerssene9f1f4d2017-06-02 15:55:02 -0700571 return Error("field name can not be the same as table/struct name");
572
Gabriel Martinez730c0ca2014-09-24 11:46:32 -0700573 std::vector<std::string> dc = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800574 EXPECT(kTokenIdentifier);
575 EXPECT(':');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800576 Type type;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800577 ECHECK(ParseType(type));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800578
579 if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800580 return Error("structs_ may contain only scalar or struct fields");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800581
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700582 FieldDef *typefield = nullptr;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800583 if (type.base_type == BASE_TYPE_UNION) {
584 // For union fields, add a second auto-generated field to hold the type,
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700585 // with a special suffix.
586 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
587 type.enum_def->underlying_type, &typefield));
Bei Li68bbe982017-01-24 11:52:36 -0800588 } else if (type.base_type == BASE_TYPE_VECTOR &&
589 type.element == BASE_TYPE_UNION) {
Kamil Rojewski46bb05d2017-08-11 18:24:36 +0200590 // Only cpp, js and ts supports the union vector feature so far.
591 if (!SupportsVectorOfUnions()) {
Bei Li68bbe982017-01-24 11:52:36 -0800592 return Error("Vectors of unions are not yet supported in all "
593 "the specified programming languages.");
594 }
595 // For vector of union fields, add a second auto-generated vector field to
596 // hold the types, with a special suffix.
597 Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def);
598 union_vector.element = BASE_TYPE_UTYPE;
599 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
600 union_vector, &typefield));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800601 }
602
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800603 FieldDef *field;
604 ECHECK(AddField(struct_def, name, type, &field));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800605
606 if (token_ == '=') {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800607 NEXT();
Wouter van Oortmerssen15dc1a82014-09-03 12:23:15 -0700608 if (!IsScalar(type.base_type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800609 return Error("default values currently only supported for scalars");
610 ECHECK(ParseSingleValue(field->value));
Wouter van Oortmerssenfd542c72016-04-20 12:05:21 -0700611 }
612 if (IsFloat(field->value.type.base_type)) {
613 if (!strpbrk(field->value.constant.c_str(), ".eE"))
614 field->value.constant += ".0";
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800615 }
616
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -0700617 if (type.enum_def &&
618 IsScalar(type.base_type) &&
619 !struct_def.fixed &&
620 !type.enum_def->attributes.Lookup("bit_flags") &&
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700621 !type.enum_def->ReverseLookup(static_cast<int>(
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800622 StringToInt(field->value.constant.c_str()))))
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -0700623 Warning("enum " + type.enum_def->name +
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -0700624 " does not have a declaration for this field\'s default of " +
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800625 field->value.constant);
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -0700626
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800627 field->doc_comment = dc;
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -0800628 ECHECK(ParseMetaData(&field->attributes));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800629 field->deprecated = field->attributes.Lookup("deprecated") != nullptr;
630 auto hash_name = field->attributes.Lookup("hash");
Alex Amesd5753212015-02-13 15:58:29 -0800631 if (hash_name) {
632 switch (type.base_type) {
633 case BASE_TYPE_INT:
634 case BASE_TYPE_UINT: {
635 if (FindHashFunction32(hash_name->constant.c_str()) == nullptr)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800636 return Error("Unknown hashing algorithm for 32 bit types: " +
Alex Amesd5753212015-02-13 15:58:29 -0800637 hash_name->constant);
638 break;
639 }
640 case BASE_TYPE_LONG:
641 case BASE_TYPE_ULONG: {
642 if (FindHashFunction64(hash_name->constant.c_str()) == nullptr)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800643 return Error("Unknown hashing algorithm for 64 bit types: " +
Alex Amesd5753212015-02-13 15:58:29 -0800644 hash_name->constant);
645 break;
646 }
647 default:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800648 return Error(
649 "only int, uint, long and ulong data types support hashing.");
Alex Amesd5753212015-02-13 15:58:29 -0800650 }
651 }
Wouter van Oortmerssendc2fa212016-10-05 16:59:15 -0700652 auto cpp_type = field->attributes.Lookup("cpp_type");
653 if (cpp_type) {
654 if (!hash_name)
655 return Error("cpp_type can only be used with a hashed field");
656 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800657 if (field->deprecated && struct_def.fixed)
658 return Error("can't deprecate fields in a struct");
659 field->required = field->attributes.Lookup("required") != nullptr;
660 if (field->required && (struct_def.fixed ||
661 IsScalar(field->value.type.base_type)))
662 return Error("only non-scalar fields in tables may be 'required'");
663 field->key = field->attributes.Lookup("key") != nullptr;
664 if (field->key) {
Wouter van Oortmerssen35508992015-01-07 17:51:31 -0800665 if (struct_def.has_key)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800666 return Error("only one field may be set as 'key'");
Wouter van Oortmerssen35508992015-01-07 17:51:31 -0800667 struct_def.has_key = true;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800668 if (!IsScalar(field->value.type.base_type)) {
669 field->required = true;
670 if (field->value.type.base_type != BASE_TYPE_STRING)
671 return Error("'key' field must be string or scalar type");
Wouter van Oortmerssen35508992015-01-07 17:51:31 -0800672 }
673 }
Wouter van Oortmerssen641b3972016-12-02 14:25:08 -0800674
rmawatson53a89772017-12-01 18:15:41 +0100675 auto field_native_custom_alloc = field->attributes.Lookup("native_custom_alloc");
676 if (field_native_custom_alloc)
677 return Error("native_custom_alloc can only be used with a table or struct definition");
678
Wouter van Oortmerssen641b3972016-12-02 14:25:08 -0800679 field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
680 if (field->native_inline && !IsStruct(field->value.type))
681 return Error("native_inline can only be defined on structs'");
682
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800683 auto nested = field->attributes.Lookup("nested_flatbuffer");
Wouter van Oortmerssen3e201a92014-07-15 17:50:22 -0700684 if (nested) {
685 if (nested->type.base_type != BASE_TYPE_STRING)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800686 return Error(
687 "nested_flatbuffer attribute must be a string (the root type)");
688 if (field->value.type.base_type != BASE_TYPE_VECTOR ||
689 field->value.type.element != BASE_TYPE_UCHAR)
690 return Error(
691 "nested_flatbuffer attribute may only apply to a vector of ubyte");
Wouter van Oortmerssen3e201a92014-07-15 17:50:22 -0700692 // This will cause an error if the root type of the nested flatbuffer
693 // wasn't defined elsewhere.
694 LookupCreateStruct(nested->constant);
Christian Helmich89a68942017-07-29 02:27:51 +0900695
696 // Keep a pointer to StructDef in FieldDef to simplify re-use later
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -0700697 auto nested_qualified_name =
698 current_namespace_->GetFullyQualifiedName(nested->constant);
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -0700699 field->nested_flatbuffer = LookupStruct(nested_qualified_name);
Wouter van Oortmerssen3e201a92014-07-15 17:50:22 -0700700 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800701
Wouter van Oortmerssendddd0862017-06-02 16:41:22 -0700702 if (field->attributes.Lookup("flexbuffer")) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700703 field->flexbuffer = true;
Wouter van Oortmerssendddd0862017-06-02 16:41:22 -0700704 uses_flexbuffers_ = true;
705 if (field->value.type.base_type != BASE_TYPE_VECTOR ||
706 field->value.type.element != BASE_TYPE_UCHAR)
707 return Error(
708 "flexbuffer attribute may only apply to a vector of ubyte");
709 }
710
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700711 if (typefield) {
Kamil Rojewski7cc72e42017-08-11 18:19:28 +0200712 if (!IsScalar(typefield->value.type.base_type)) {
713 // this is a union vector field
714 typefield->required = field->required;
715 }
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700716 // If this field is a union, and it has a manually assigned id,
717 // the automatically added type field should have an id as well (of N - 1).
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800718 auto attr = field->attributes.Lookup("id");
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700719 if (attr) {
720 auto id = atoi(attr->constant.c_str());
721 auto val = new Value();
722 val->type = attr->type;
723 val->constant = NumToString(id - 1);
724 typefield->attributes.Add("id", val);
725 }
726 }
727
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800728 EXPECT(';');
729 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800730}
731
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -0700732CheckedError Parser::ParseString(Value &val) {
733 auto s = attribute_;
734 EXPECT(kTokenStringConstant);
735 val.constant = NumToString(builder_.CreateString(s).o);
736 return NoError();
737}
738
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -0700739CheckedError Parser::ParseComma() {
740 if (!opts.protobuf_ascii_alike) EXPECT(',');
741 return NoError();
742}
743
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800744CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700745 size_t parent_fieldn,
746 const StructDef *parent_struct_def) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800747 switch (val.type.base_type) {
748 case BASE_TYPE_UNION: {
749 assert(field);
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700750 std::string constant;
Wouter van Oortmersseneac29052017-01-18 12:02:31 -0800751 // Find corresponding type field we may have already parsed.
752 for (auto elem = field_stack_.rbegin();
753 elem != field_stack_.rbegin() + parent_fieldn; ++elem) {
754 auto &type = elem->second->value.type;
755 if (type.base_type == BASE_TYPE_UTYPE &&
756 type.enum_def == val.type.enum_def) {
757 constant = elem->first.constant;
758 break;
759 }
760 }
761 if (constant.empty()) {
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700762 // We haven't seen the type field yet. Sadly a lot of JSON writers
763 // output these in alphabetical order, meaning it comes after this
764 // value. So we scan past the value to find it, then come back here.
765 auto type_name = field->name + UnionTypeFieldSuffix();
766 assert(parent_struct_def);
767 auto type_field = parent_struct_def->fields.Lookup(type_name);
768 assert(type_field); // Guaranteed by ParseField().
769 // Remember where we are in the source file, so we can come back here.
770 auto backup = *static_cast<ParserState *>(this);
771 ECHECK(SkipAnyJsonValue()); // The table.
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -0700772 ECHECK(ParseComma());
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700773 auto next_name = attribute_;
774 if (Is(kTokenStringConstant)) {
775 NEXT();
776 } else {
777 EXPECT(kTokenIdentifier);
778 }
779 if (next_name != type_name)
780 return Error("missing type field after this union value: " +
781 type_name);
782 EXPECT(':');
783 Value type_val = type_field->value;
784 ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr));
785 constant = type_val.constant;
786 // Got the information we needed, now rewind:
787 *static_cast<ParserState *>(this) = backup;
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700788 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800789 uint8_t enum_idx;
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700790 ECHECK(atot(constant.c_str(), *this, &enum_idx));
Wouter van Oortmerssen3fb6a862014-07-14 17:49:04 -0700791 auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800792 if (!enum_val) return Error("illegal type id for: " + field->name);
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -0700793 if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
794 ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
795 nullptr));
796 if (enum_val->union_type.struct_def->fixed) {
797 // All BASE_TYPE_UNION values are offsets, so turn this into one.
798 SerializeStruct(*enum_val->union_type.struct_def, val);
799 builder_.ClearOffsets();
800 val.constant = NumToString(builder_.GetSize());
801 }
802 } else if (enum_val->union_type.base_type == BASE_TYPE_STRING) {
803 ECHECK(ParseString(val));
804 } else {
805 assert(false);
806 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800807 break;
808 }
809 case BASE_TYPE_STRUCT:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800810 ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800811 break;
812 case BASE_TYPE_STRING: {
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -0700813 ECHECK(ParseString(val));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800814 break;
815 }
816 case BASE_TYPE_VECTOR: {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800817 uoffset_t off;
818 ECHECK(ParseVector(val.type.VectorType(), &off));
819 val.constant = NumToString(off);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800820 break;
821 }
Alex Amesd5753212015-02-13 15:58:29 -0800822 case BASE_TYPE_INT:
823 case BASE_TYPE_UINT:
824 case BASE_TYPE_LONG:
825 case BASE_TYPE_ULONG: {
826 if (field && field->attributes.Lookup("hash") &&
827 (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800828 ECHECK(ParseHash(val, field));
Alex Amesd5753212015-02-13 15:58:29 -0800829 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800830 ECHECK(ParseSingleValue(val));
Alex Amesd5753212015-02-13 15:58:29 -0800831 }
832 break;
833 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800834 default:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800835 ECHECK(ParseSingleValue(val));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800836 break;
837 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800838 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800839}
840
841void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700842 assert(val.constant.length() == struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800843 builder_.Align(struct_def.minalign);
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700844 builder_.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()),
845 struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800846 builder_.AddStructOffset(val.offset, builder_.GetSize());
847}
848
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700849CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
850 const StructDef *struct_def,
Stewart Milesa8923222017-07-13 06:27:39 -0700851 ParseTableDelimitersBody body,
852 void *state) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700853 // We allow tables both as JSON object{ .. } with field names
Guillaume Giraudb1740682017-06-08 01:58:19 +0200854 // or vector[..] with all fields in order
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700855 char terminator = '}';
856 bool is_nested_vector = struct_def && Is('[');
857 if (is_nested_vector) {
Guillaume Giraudb1740682017-06-08 01:58:19 +0200858 NEXT();
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700859 terminator = ']';
Guillaume Giraudb1740682017-06-08 01:58:19 +0200860 } else {
861 EXPECT('{');
862 }
Wouter van Oortmerssen6c2dc412015-01-16 16:57:04 -0800863 for (;;) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700864 if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
Guillaume Giraudb1740682017-06-08 01:58:19 +0200865 std::string name;
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700866 if (is_nested_vector) {
867 if (fieldn > struct_def->fields.vec.size()) {
Guillaume Giraudb1740682017-06-08 01:58:19 +0200868 return Error("too many unnamed fields in nested array");
869 }
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700870 name = struct_def->fields.vec[fieldn]->name;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800871 } else {
Guillaume Giraudb1740682017-06-08 01:58:19 +0200872 name = attribute_;
873 if (Is(kTokenStringConstant)) {
874 NEXT();
875 } else {
876 EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
877 }
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -0700878 if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800879 }
Stewart Milesa8923222017-07-13 06:27:39 -0700880 ECHECK(body(name, fieldn, struct_def, state));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700881 if (Is(terminator)) break;
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -0700882 ECHECK(ParseComma());
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700883 }
884 NEXT();
885 if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
886 return Error("wrong number of unnamed fields in table vector");
887 }
888 return NoError();
889}
890
891CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
892 uoffset_t *ovalue) {
Stewart Milesa8923222017-07-13 06:27:39 -0700893 size_t fieldn_outer = 0;
894 auto err = ParseTableDelimiters(fieldn_outer, &struct_def,
895 [](const std::string &name, size_t &fieldn,
896 const StructDef *struct_def_inner,
897 void *state) -> CheckedError {
898 Parser *parser = static_cast<Parser *>(state);
schoetbi2e2063c2017-07-19 17:58:48 +0200899 if (name == "$schema") {
Stewart Milesa8923222017-07-13 06:27:39 -0700900 ECHECK(parser->Expect(kTokenStringConstant));
schoetbi2e2063c2017-07-19 17:58:48 +0200901 return NoError();
902 }
Stewart Milesa8923222017-07-13 06:27:39 -0700903 auto field = struct_def_inner->fields.Lookup(name);
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800904 if (!field) {
Stewart Milesa8923222017-07-13 06:27:39 -0700905 if (!parser->opts.skip_unexpected_fields_in_json) {
906 return parser->Error("unknown field: " + name);
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800907 } else {
Stewart Milesa8923222017-07-13 06:27:39 -0700908 ECHECK(parser->SkipAnyJsonValue());
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800909 }
910 } else {
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -0700911 if (parser->IsIdent("null")) {
Stewart Milesa8923222017-07-13 06:27:39 -0700912 ECHECK(parser->Next()); // Ignore this field.
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800913 } else {
914 Value val = field->value;
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700915 if (field->flexbuffer) {
916 flexbuffers::Builder builder(1024,
917 flexbuffers::BUILDER_FLAG_SHARE_ALL);
Stewart Milesa8923222017-07-13 06:27:39 -0700918 ECHECK(parser->ParseFlexBufferValue(&builder));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700919 builder.Finish();
Stewart Milesa8923222017-07-13 06:27:39 -0700920 auto off = parser->builder_.CreateVector(builder.GetBuffer());
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700921 val.constant = NumToString(off.o);
Christian Helmich89a68942017-07-29 02:27:51 +0900922 } else if (field->nested_flatbuffer) {
923 ECHECK(parser->ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700924 } else {
Stewart Milesa8923222017-07-13 06:27:39 -0700925 ECHECK(parser->ParseAnyValue(val, field, fieldn, struct_def_inner));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700926 }
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800927 // Hardcoded insertion-sort with error-check.
928 // If fields are specified in order, then this loop exits immediately.
Stewart Milesa8923222017-07-13 06:27:39 -0700929 auto elem = parser->field_stack_.rbegin();
930 for (; elem != parser->field_stack_.rbegin() + fieldn; ++elem) {
Wouter van Oortmersseneac29052017-01-18 12:02:31 -0800931 auto existing_field = elem->second;
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800932 if (existing_field == field)
Stewart Milesa8923222017-07-13 06:27:39 -0700933 return parser->Error("field set more than once: " + field->name);
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800934 if (existing_field->value.offset < field->value.offset) break;
935 }
Wouter van Oortmersseneac29052017-01-18 12:02:31 -0800936 // Note: elem points to before the insertion point, thus .base() points
937 // to the correct spot.
Stewart Milesa8923222017-07-13 06:27:39 -0700938 parser->field_stack_.insert(elem.base(),
939 std::make_pair(val, field));
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800940 fieldn++;
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800941 }
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700942 }
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700943 return NoError();
Stewart Milesa8923222017-07-13 06:27:39 -0700944 }, this);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700945 ECHECK(err);
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800946
sfariv55dec4d2017-05-18 09:32:04 -0700947 // Check if all required fields are parsed.
948 for (auto field_it = struct_def.fields.vec.begin();
949 field_it != struct_def.fields.vec.end();
950 ++field_it) {
951 auto required_field = *field_it;
952 if (!required_field->required) {
953 continue;
954 }
955 bool found = false;
Stewart Milesa8923222017-07-13 06:27:39 -0700956 for (auto pf_it = field_stack_.end() - fieldn_outer;
sfariv55dec4d2017-05-18 09:32:04 -0700957 pf_it != field_stack_.end();
958 ++pf_it) {
959 auto parsed_field = pf_it->second;
960 if (parsed_field == required_field) {
961 found = true;
962 break;
963 }
964 }
965 if (!found) {
966 return Error("required field is missing: " + required_field->name + " in " + struct_def.name);
967 }
968 }
969
Stewart Milesa8923222017-07-13 06:27:39 -0700970 if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800971 return Error("struct: wrong number of initializers: " + struct_def.name);
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700972
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800973 auto start = struct_def.fixed
974 ? builder_.StartStruct(struct_def.minalign)
975 : builder_.StartTable();
976
977 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
978 size;
979 size /= 2) {
980 // Go through elements in reverse, since we're building the data backwards.
Stewart Milesa8923222017-07-13 06:27:39 -0700981 for (auto it = field_stack_.rbegin(); it != field_stack_.rbegin() +
982 fieldn_outer;
983 ++it) {
Shuhei Tanuma721d2192015-11-06 07:14:21 +0900984 auto &field_value = it->first;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800985 auto field = it->second;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800986 if (!struct_def.sortbysize ||
987 size == SizeOf(field_value.type.base_type)) {
Shuhei Tanuma721d2192015-11-06 07:14:21 +0900988 switch (field_value.type.base_type) {
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -0700989 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
MikkelFJf2b37052017-08-02 17:07:43 +0200990 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800991 case BASE_TYPE_ ## ENUM: \
992 builder_.Pad(field->padding); \
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -0700993 if (struct_def.fixed) { \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800994 CTYPE val; \
995 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
996 builder_.PushElement(val); \
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -0700997 } else { \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800998 CTYPE val, valdef; \
999 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1000 ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \
1001 builder_.AddElement(field_value.offset, val, valdef); \
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -07001002 } \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001003 break;
1004 FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
1005 #undef FLATBUFFERS_TD
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001006 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
MikkelFJf2b37052017-08-02 17:07:43 +02001007 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001008 case BASE_TYPE_ ## ENUM: \
1009 builder_.Pad(field->padding); \
1010 if (IsStruct(field->value.type)) { \
Shuhei Tanuma721d2192015-11-06 07:14:21 +09001011 SerializeStruct(*field->value.type.struct_def, field_value); \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001012 } else { \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001013 CTYPE val; \
1014 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1015 builder_.AddOffset(field_value.offset, val); \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001016 } \
1017 break;
1018 FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD);
1019 #undef FLATBUFFERS_TD
1020 }
1021 }
1022 }
1023 }
Stewart Milesa8923222017-07-13 06:27:39 -07001024 for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001025
1026 if (struct_def.fixed) {
1027 builder_.ClearOffsets();
1028 builder_.EndStruct();
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -07001029 assert(value);
1030 // Temporarily store this struct in the value string, since it is to
1031 // be serialized in-place elsewhere.
1032 value->assign(
1033 reinterpret_cast<const char *>(builder_.GetCurrentBufferPointer()),
1034 struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001035 builder_.PopBytes(struct_def.bytesize);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001036 assert(!ovalue);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001037 } else {
Wouter van Oortmerssenac1015e2017-08-21 13:44:23 -07001038 auto val = builder_.EndTable(start);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001039 if (ovalue) *ovalue = val;
1040 if (value) *value = NumToString(val);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001041 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001042 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001043}
1044
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001045CheckedError Parser::ParseVectorDelimiters(size_t &count,
Stewart Milesa8923222017-07-13 06:27:39 -07001046 ParseVectorDelimitersBody body,
1047 void *state) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001048 EXPECT('[');
Wouter van Oortmerssen6c2dc412015-01-16 16:57:04 -08001049 for (;;) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001050 if ((!opts.strict_json || !count) && Is(']')) break;
Stewart Milesa8923222017-07-13 06:27:39 -07001051 ECHECK(body(count, state));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001052 count++;
1053 if (Is(']')) break;
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -07001054 ECHECK(ParseComma());
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001055 }
1056 NEXT();
1057 return NoError();
1058}
1059
1060CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
1061 size_t count = 0;
Stewart Milesa8923222017-07-13 06:27:39 -07001062 std::pair<Parser *, const Type &> parser_and_type_state(this, type);
1063 auto err = ParseVectorDelimiters(count,
1064 [](size_t &, void *state) -> CheckedError {
1065 auto *parser_and_type =
1066 static_cast<std::pair<Parser *, const Type &> *>(state);
1067 auto *parser = parser_and_type->first;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001068 Value val;
Stewart Milesa8923222017-07-13 06:27:39 -07001069 val.type = parser_and_type->second;
1070 ECHECK(parser->ParseAnyValue(val, nullptr, 0, nullptr));
1071 parser->field_stack_.push_back(std::make_pair(val, nullptr));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001072 return NoError();
Stewart Milesa8923222017-07-13 06:27:39 -07001073 }, &parser_and_type_state);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001074 ECHECK(err);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001075
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -07001076 builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
1077 InlineAlignment(type));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001078 for (size_t i = 0; i < count; i++) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001079 // start at the back, since we're building the data backwards.
1080 auto &val = field_stack_.back().first;
1081 switch (val.type.base_type) {
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001082 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
MikkelFJf2b37052017-08-02 17:07:43 +02001083 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001084 case BASE_TYPE_ ## ENUM: \
1085 if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001086 else { \
1087 CTYPE elem; \
1088 ECHECK(atot(val.constant.c_str(), *this, &elem)); \
1089 builder_.PushElement(elem); \
1090 } \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001091 break;
1092 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1093 #undef FLATBUFFERS_TD
1094 }
1095 field_stack_.pop_back();
1096 }
1097
1098 builder_.ClearOffsets();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001099 *ovalue = builder_.EndVector(count);
1100 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001101}
1102
Christian Helmich89a68942017-07-29 02:27:51 +09001103CheckedError Parser::ParseNestedFlatbuffer(Value &val, FieldDef *field,
1104 size_t fieldn,
1105 const StructDef *parent_struct_def) {
1106 if (token_ == '[') {// backwards compat for 'legacy' ubyte buffers
1107 ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def));
1108 } else {
1109 auto cursor_at_value_begin = cursor_;
1110 ECHECK(SkipAnyJsonValue());
1111 std::string substring(cursor_at_value_begin -1 , cursor_ -1);
1112
1113 // Create and initialize new parser
1114 Parser nested_parser;
1115 assert(field->nested_flatbuffer);
1116 nested_parser.root_struct_def_ = field->nested_flatbuffer;
1117 nested_parser.enums_ = enums_;
1118 nested_parser.opts = opts;
1119 nested_parser.uses_flexbuffers_ = uses_flexbuffers_;
1120
1121 // Parse JSON substring into new flatbuffer builder using nested_parser
1122 if (!nested_parser.Parse(substring.c_str(), nullptr, nullptr)) {
1123 ECHECK(Error(nested_parser.error_));
1124 }
1125 auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(), nested_parser.builder_.GetSize());
1126 val.constant = NumToString(off.o);
1127
1128 // Clean nested_parser before destruction to avoid deleting the elements in the SymbolTables
1129 nested_parser.enums_.dict.clear();
1130 nested_parser.enums_.vec.clear();
1131 }
1132 return NoError();
1133}
1134
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001135CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001136 if (Is('(')) {
1137 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001138 for (;;) {
1139 auto name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001140 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen09521432014-11-17 17:27:26 -08001141 if (known_attributes_.find(name) == known_attributes_.end())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001142 return Error("user define attributes must be declared before use: " +
1143 name);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001144 auto e = new Value();
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001145 attributes->Add(name, e);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001146 if (Is(':')) {
1147 NEXT();
1148 ECHECK(ParseSingleValue(*e));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001149 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001150 if (Is(')')) { NEXT(); break; }
1151 EXPECT(',');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001152 }
1153 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001154 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001155}
1156
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001157CheckedError Parser::TryTypedValue(int dtoken, bool check, Value &e,
1158 BaseType req, bool *destmatch) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001159 bool match = dtoken == token_;
1160 if (match) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001161 *destmatch = true;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001162 e.constant = attribute_;
1163 if (!check) {
1164 if (e.type.base_type == BASE_TYPE_NONE) {
1165 e.type.base_type = req;
1166 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001167 return Error(std::string("type mismatch: expecting: ") +
1168 kTypeNames[e.type.base_type] +
1169 ", found: " +
1170 kTypeNames[req]);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001171 }
1172 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001173 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001174 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001175 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001176}
1177
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001178CheckedError Parser::ParseEnumFromString(Type &type, int64_t *result) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001179 *result = 0;
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001180 // Parse one or more enum identifiers, separated by spaces.
1181 const char *next = attribute_.c_str();
1182 do {
1183 const char *divider = strchr(next, ' ');
1184 std::string word;
1185 if (divider) {
1186 word = std::string(next, divider);
1187 next = divider + strspn(divider, " ");
1188 } else {
1189 word = next;
1190 next += word.length();
1191 }
1192 if (type.enum_def) { // The field has an enum type
1193 auto enum_val = type.enum_def->vals.Lookup(word);
1194 if (!enum_val)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001195 return Error("unknown enum value: " + word +
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001196 ", for enum: " + type.enum_def->name);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001197 *result |= enum_val->value;
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001198 } else { // No enum type, probably integral field.
1199 if (!IsInteger(type.base_type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001200 return Error("not a valid value for this field: " + word);
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001201 // TODO: could check if its a valid number constant here.
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -07001202 const char *dot = strrchr(word.c_str(), '.');
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001203 if (!dot)
1204 return Error("enum values need to be qualified by an enum type");
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001205 std::string enum_def_str(word.c_str(), dot);
1206 std::string enum_val_str(dot + 1, word.c_str() + word.length());
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -07001207 auto enum_def = LookupEnum(enum_def_str);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001208 if (!enum_def) return Error("unknown enum: " + enum_def_str);
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001209 auto enum_val = enum_def->vals.Lookup(enum_val_str);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001210 if (!enum_val) return Error("unknown enum value: " + enum_val_str);
1211 *result |= enum_val->value;
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001212 }
1213 } while(*next);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001214 return NoError();
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001215}
1216
Alex Amesd5753212015-02-13 15:58:29 -08001217
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001218CheckedError Parser::ParseHash(Value &e, FieldDef* field) {
Alex Amesd5753212015-02-13 15:58:29 -08001219 assert(field);
1220 Value *hash_name = field->attributes.Lookup("hash");
1221 switch (e.type.base_type) {
Wouter van Oortmerssen46497e42017-04-17 17:40:02 -07001222 case BASE_TYPE_INT: {
1223 auto hash = FindHashFunction32(hash_name->constant.c_str());
1224 int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
1225 e.constant = NumToString(hashed_value);
1226 break;
1227 }
Alex Amesd5753212015-02-13 15:58:29 -08001228 case BASE_TYPE_UINT: {
1229 auto hash = FindHashFunction32(hash_name->constant.c_str());
1230 uint32_t hashed_value = hash(attribute_.c_str());
1231 e.constant = NumToString(hashed_value);
1232 break;
1233 }
Wouter van Oortmerssen46497e42017-04-17 17:40:02 -07001234 case BASE_TYPE_LONG: {
1235 auto hash = FindHashFunction64(hash_name->constant.c_str());
1236 int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
1237 e.constant = NumToString(hashed_value);
1238 break;
1239 }
Alex Amesd5753212015-02-13 15:58:29 -08001240 case BASE_TYPE_ULONG: {
1241 auto hash = FindHashFunction64(hash_name->constant.c_str());
1242 uint64_t hashed_value = hash(attribute_.c_str());
1243 e.constant = NumToString(hashed_value);
1244 break;
1245 }
1246 default:
1247 assert(0);
1248 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001249 NEXT();
1250 return NoError();
Alex Amesd5753212015-02-13 15:58:29 -08001251}
1252
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001253CheckedError Parser::TokenError() {
1254 return Error("cannot parse value starting with: " +
1255 TokenToStringId(token_));
1256}
1257
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001258CheckedError Parser::ParseSingleValue(Value &e) {
Wouter van Oortmerssend3ac0bc2016-06-15 13:54:17 -07001259 // First see if this could be a conversion function:
1260 if (token_ == kTokenIdentifier && *cursor_ == '(') {
1261 auto functionname = attribute_;
1262 NEXT();
1263 EXPECT('(');
1264 ECHECK(ParseSingleValue(e));
1265 EXPECT(')');
1266 #define FLATBUFFERS_FN_DOUBLE(name, op) \
1267 if (functionname == name) { \
1268 auto x = strtod(e.constant.c_str(), nullptr); \
1269 e.constant = NumToString(op); \
1270 }
Bastien Brunnenstein85b131a2017-12-05 00:06:13 +01001271 FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180);
1272 FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180);
Wouter van Oortmerssend3ac0bc2016-06-15 13:54:17 -07001273 FLATBUFFERS_FN_DOUBLE("sin", sin(x));
1274 FLATBUFFERS_FN_DOUBLE("cos", cos(x));
1275 FLATBUFFERS_FN_DOUBLE("tan", tan(x));
1276 FLATBUFFERS_FN_DOUBLE("asin", asin(x));
1277 FLATBUFFERS_FN_DOUBLE("acos", acos(x));
1278 FLATBUFFERS_FN_DOUBLE("atan", atan(x));
1279 // TODO(wvo): add more useful conversion functions here.
1280 #undef FLATBUFFERS_FN_DOUBLE
1281 // Then check if this could be a string/identifier enum value:
1282 } else if (e.type.base_type != BASE_TYPE_STRING &&
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001283 e.type.base_type != BASE_TYPE_BOOL &&
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001284 e.type.base_type != BASE_TYPE_NONE &&
1285 (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001286 if (IsIdentifierStart(attribute_[0])) { // Enum value.
1287 int64_t val;
1288 ECHECK(ParseEnumFromString(e.type, &val));
1289 e.constant = NumToString(val);
1290 NEXT();
1291 } else { // Numeric constant in string.
1292 if (IsInteger(e.type.base_type)) {
Sahil Jainb6ba3222016-08-25 23:37:30 -04001293 char *end;
1294 e.constant = NumToString(StringToInt(attribute_.c_str(), &end));
1295 if (*end)
1296 return Error("invalid integer: " + attribute_);
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001297 } else if (IsFloat(e.type.base_type)) {
Sahil Jainb6ba3222016-08-25 23:37:30 -04001298 char *end;
1299 e.constant = NumToString(strtod(attribute_.c_str(), &end));
1300 if (*end)
1301 return Error("invalid float: " + attribute_);
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001302 } else {
1303 assert(0); // Shouldn't happen, we covered all types.
1304 e.constant = "0";
1305 }
Wouter van Oortmerssen83dc5ed2016-04-11 11:08:09 -07001306 NEXT();
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001307 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001308 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001309 bool match = false;
1310 ECHECK(TryTypedValue(kTokenIntegerConstant,
1311 IsScalar(e.type.base_type),
1312 e,
1313 BASE_TYPE_INT,
1314 &match));
1315 ECHECK(TryTypedValue(kTokenFloatConstant,
1316 IsFloat(e.type.base_type),
1317 e,
1318 BASE_TYPE_FLOAT,
1319 &match));
1320 ECHECK(TryTypedValue(kTokenStringConstant,
1321 e.type.base_type == BASE_TYPE_STRING,
1322 e,
1323 BASE_TYPE_STRING,
1324 &match));
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001325 auto istrue = IsIdent("true");
1326 if (istrue || IsIdent("false")) {
1327 attribute_ = NumToString(istrue);
1328 ECHECK(TryTypedValue(kTokenIdentifier,
1329 IsBool(e.type.base_type),
1330 e,
1331 BASE_TYPE_BOOL,
1332 &match));
1333 }
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001334 if (!match) return TokenError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001335 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001336 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001337}
1338
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001339StructDef *Parser::LookupCreateStruct(const std::string &name,
1340 bool create_if_new, bool definition) {
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001341 std::string qualified_name = current_namespace_->GetFullyQualifiedName(name);
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001342 // See if it exists pre-declared by an unqualified use.
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -07001343 auto struct_def = LookupStruct(name);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001344 if (struct_def && struct_def->predecl) {
1345 if (definition) {
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001346 // Make sure it has the current namespace, and is registered under its
1347 // qualified name.
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001348 struct_def->defined_namespace = current_namespace_;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001349 structs_.Move(name, qualified_name);
1350 }
1351 return struct_def;
1352 }
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001353 // See if it exists pre-declared by an qualified use.
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -07001354 struct_def = LookupStruct(qualified_name);
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001355 if (struct_def && struct_def->predecl) {
1356 if (definition) {
1357 // Make sure it has the current namespace.
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001358 struct_def->defined_namespace = current_namespace_;
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001359 }
1360 return struct_def;
1361 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001362 if (!definition) {
1363 // Search thru parent namespaces.
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001364 for (size_t components = current_namespace_->components.size();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001365 components && !struct_def; components--) {
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -07001366 struct_def = LookupStruct(
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001367 current_namespace_->GetFullyQualifiedName(name, components - 1));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001368 }
1369 }
1370 if (!struct_def && create_if_new) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001371 struct_def = new StructDef();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001372 if (definition) {
1373 structs_.Add(qualified_name, struct_def);
1374 struct_def->name = name;
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001375 struct_def->defined_namespace = current_namespace_;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001376 } else {
1377 // Not a definition.
1378 // Rather than failing, we create a "pre declared" StructDef, due to
1379 // circular references, and check for errors at the end of parsing.
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -07001380 // It is defined in the current namespace, as the best guess what the
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001381 // final namespace will be.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001382 structs_.Add(name, struct_def);
1383 struct_def->name = name;
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -07001384 struct_def->defined_namespace = current_namespace_;
1385 struct_def->original_location.reset(new std::string(file_being_parsed_ +
1386 ":" + NumToString(line_)));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001387 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001388 }
1389 return struct_def;
1390}
1391
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001392CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
Max Galkinc3807fa2015-03-07 08:49:55 -08001393 std::vector<std::string> enum_comment = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001394 NEXT();
Max Galkinc3807fa2015-03-07 08:49:55 -08001395 std::string enum_name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001396 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001397 auto &enum_def = *new EnumDef();
Max Galkinc3807fa2015-03-07 08:49:55 -08001398 enum_def.name = enum_name;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001399 enum_def.file = file_being_parsed_;
Max Galkinc3807fa2015-03-07 08:49:55 -08001400 enum_def.doc_comment = enum_comment;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001401 enum_def.is_union = is_union;
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001402 enum_def.defined_namespace = current_namespace_;
1403 if (enums_.Add(current_namespace_->GetFullyQualifiedName(enum_name),
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001404 &enum_def))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001405 return Error("enum already exists: " + enum_name);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001406 if (is_union) {
1407 enum_def.underlying_type.base_type = BASE_TYPE_UTYPE;
1408 enum_def.underlying_type.enum_def = &enum_def;
Wouter van Oortmerssena5f50012014-07-02 12:01:21 -07001409 } else {
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -08001410 if (opts.proto_mode) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001411 enum_def.underlying_type.base_type = BASE_TYPE_INT;
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001412 } else {
1413 // Give specialized error message, since this type spec used to
1414 // be optional in the first FlatBuffers release.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001415 if (!Is(':')) {
1416 return Error("must specify the underlying integer type for this"
1417 " enum (e.g. \': short\', which was the default).");
1418 } else {
1419 NEXT();
1420 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001421 // Specify the integer type underlying this enum.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001422 ECHECK(ParseType(enum_def.underlying_type));
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001423 if (!IsInteger(enum_def.underlying_type.base_type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001424 return Error("underlying enum type must be integral");
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001425 }
Wouter van Oortmerssen3fb6a862014-07-14 17:49:04 -07001426 // Make this type refer back to the enum it was derived from.
1427 enum_def.underlying_type.enum_def = &enum_def;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001428 }
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001429 ECHECK(ParseMetaData(&enum_def.attributes));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001430 EXPECT('{');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001431 if (is_union) enum_def.vals.Add("NONE", new EnumVal("NONE", 0));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001432 for (;;) {
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -08001433 if (opts.proto_mode && attribute_ == "option") {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001434 ECHECK(ParseProtoOption());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001435 } else {
1436 auto value_name = attribute_;
1437 auto full_name = value_name;
1438 std::vector<std::string> value_comment = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001439 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen36390322016-06-17 18:16:11 -07001440 if (is_union) {
1441 ECHECK(ParseNamespacing(&full_name, &value_name));
Wouter van Oortmerssend70f5ac2016-07-29 10:45:32 -07001442 if (opts.union_value_namespacing) {
1443 // Since we can't namespace the actual enum identifiers, turn
1444 // namespace parts into part of the identifier.
1445 value_name = full_name;
1446 std::replace(value_name.begin(), value_name.end(), '.', '_');
1447 }
Wouter van Oortmerssen36390322016-06-17 18:16:11 -07001448 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001449 auto prevsize = enum_def.vals.vec.size();
1450 auto value = enum_def.vals.vec.size()
1451 ? enum_def.vals.vec.back()->value + 1
1452 : 0;
1453 auto &ev = *new EnumVal(value_name, value);
1454 if (enum_def.vals.Add(value_name, &ev))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001455 return Error("enum value already exists: " + value_name);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001456 ev.doc_comment = value_comment;
1457 if (is_union) {
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -07001458 if (Is(':')) {
1459 NEXT();
1460 ECHECK(ParseType(ev.union_type));
1461 if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
1462 ev.union_type.base_type != BASE_TYPE_STRING)
1463 return Error("union value type may only be table/struct/string");
1464 enum_def.uses_type_aliases = true;
1465 } else {
1466 ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
1467 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001468 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001469 if (Is('=')) {
1470 NEXT();
Wouter van Oortmerssend7793082016-02-10 11:25:31 -08001471 ev.value = StringToInt(attribute_.c_str());
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001472 EXPECT(kTokenIntegerConstant);
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -08001473 if (!opts.proto_mode && prevsize &&
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001474 enum_def.vals.vec[prevsize - 1]->value >= ev.value)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001475 return Error("enum values must be specified in ascending order");
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001476 }
Wouter van Oortmerssen9d01bfa2017-05-10 17:21:47 -07001477 if (is_union) {
1478 if (ev.value < 0 || ev.value >= 256)
1479 return Error("union enum value must fit in a ubyte");
1480 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001481 if (opts.proto_mode && Is('[')) {
1482 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001483 // ignore attributes on enums.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001484 while (token_ != ']') NEXT();
1485 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001486 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001487 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001488 if (!Is(opts.proto_mode ? ';' : ',')) break;
1489 NEXT();
1490 if (Is('}')) break;
1491 }
1492 EXPECT('}');
Wouter van Oortmerssen127d3502014-07-17 15:12:37 -07001493 if (enum_def.attributes.Lookup("bit_flags")) {
1494 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
1495 ++it) {
1496 if (static_cast<size_t>((*it)->value) >=
1497 SizeOf(enum_def.underlying_type.base_type) * 8)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001498 return Error("bit flag out of range of underlying integral type");
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001499 (*it)->value = 1LL << (*it)->value;
Wouter van Oortmerssen127d3502014-07-17 15:12:37 -07001500 }
1501 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001502 if (dest) *dest = &enum_def;
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001503 types_.Add(current_namespace_->GetFullyQualifiedName(enum_def.name),
Wouter van Oortmerssen9b3d8b32017-01-27 15:28:57 -08001504 new Type(BASE_TYPE_UNION, nullptr, &enum_def));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001505 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001506}
1507
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001508CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001509 auto &struct_def = *LookupCreateStruct(name, true, true);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001510 if (!struct_def.predecl) return Error("datatype already exists: " + name);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001511 struct_def.predecl = false;
1512 struct_def.name = name;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001513 struct_def.file = file_being_parsed_;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001514 // Move this struct to the back of the vector just in case it was predeclared,
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001515 // to preserve declaration order.
Dmitry Ermolov370693a2017-04-20 02:55:41 +03001516 *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001517 *dest = &struct_def;
1518 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001519}
1520
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001521CheckedError Parser::CheckClash(std::vector<FieldDef*> &fields,
1522 StructDef *struct_def,
1523 const char *suffix,
1524 BaseType basetype) {
1525 auto len = strlen(suffix);
1526 for (auto it = fields.begin(); it != fields.end(); ++it) {
1527 auto &fname = (*it)->name;
1528 if (fname.length() > len &&
1529 fname.compare(fname.length() - len, len, suffix) == 0 &&
1530 (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
1531 auto field = struct_def->fields.Lookup(
1532 fname.substr(0, fname.length() - len));
1533 if (field && field->value.type.base_type == basetype)
1534 return Error("Field " + fname +
1535 " would clash with generated functions for field " +
1536 field->name);
1537 }
1538 }
1539 return NoError();
1540}
Wouter van Oortmerssend7793082016-02-10 11:25:31 -08001541
Kamil Rojewski46bb05d2017-08-11 18:24:36 +02001542bool Parser::SupportsVectorOfUnions() const {
1543 return opts.lang_to_generate != 0 && (opts.lang_to_generate &
1544 ~(IDLOptions::kCpp | IDLOptions::kJs | IDLOptions::kTs | IDLOptions::kPhp)) == 0;
1545}
1546
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001547Namespace *Parser::UniqueNamespace(Namespace *ns) {
1548 for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) {
1549 if (ns->components == (*it)->components) {
1550 delete ns;
1551 return *it;
1552 }
1553 }
1554 namespaces_.push_back(ns);
1555 return ns;
1556}
1557
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001558static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
1559 auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
1560 auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
1561 return a_id < b_id;
1562}
1563
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001564CheckedError Parser::ParseDecl() {
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001565 std::vector<std::string> dc = doc_comment_;
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001566 bool fixed = IsIdent("struct");
1567 if (!fixed && !IsIdent("table")) return Error("declaration expected");
1568 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001569 std::string name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001570 EXPECT(kTokenIdentifier);
1571 StructDef *struct_def;
1572 ECHECK(StartStruct(name, &struct_def));
1573 struct_def->doc_comment = dc;
1574 struct_def->fixed = fixed;
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001575 ECHECK(ParseMetaData(&struct_def->attributes));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001576 struct_def->sortbysize =
1577 struct_def->attributes.Lookup("original_order") == nullptr && !fixed;
1578 EXPECT('{');
1579 while (token_ != '}') ECHECK(ParseField(*struct_def));
1580 auto force_align = struct_def->attributes.Lookup("force_align");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001581 if (fixed && force_align) {
1582 auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
1583 if (force_align->type.base_type != BASE_TYPE_INT ||
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001584 align < struct_def->minalign ||
Wouter van Oortmerssen6862b2f2016-10-17 18:02:19 -07001585 align > FLATBUFFERS_MAX_ALIGNMENT ||
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001586 align & (align - 1))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001587 return Error("force_align must be a power of two integer ranging from the"
Wouter van Oortmerssen6862b2f2016-10-17 18:02:19 -07001588 "struct\'s natural alignment to " +
1589 NumToString(FLATBUFFERS_MAX_ALIGNMENT));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001590 struct_def->minalign = align;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001591 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001592 struct_def->PadLastField(struct_def->minalign);
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001593 // Check if this is a table that has manual id assignments
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001594 auto &fields = struct_def->fields.vec;
1595 if (!struct_def->fixed && fields.size()) {
Wouter van Oortmerssen7fcbe722014-07-08 16:35:14 -07001596 size_t num_id_fields = 0;
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001597 for (auto it = fields.begin(); it != fields.end(); ++it) {
1598 if ((*it)->attributes.Lookup("id")) num_id_fields++;
1599 }
1600 // If any fields have ids..
1601 if (num_id_fields) {
1602 // Then all fields must have them.
1603 if (num_id_fields != fields.size())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001604 return Error(
1605 "either all fields or no fields must have an 'id' attribute");
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001606 // Simply sort by id, then the fields are the same as if no ids had
1607 // been specified.
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001608 std::sort(fields.begin(), fields.end(), compareFieldDefs);
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001609 // Verify we have a contiguous set, and reassign vtable offsets.
1610 for (int i = 0; i < static_cast<int>(fields.size()); i++) {
1611 if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str()))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001612 return Error("field id\'s must be consecutive from 0, id " +
Wouter van Oortmerssen91401442014-07-07 17:34:23 -07001613 NumToString(i) + " missing or set twice");
1614 fields[i]->value.offset = FieldIndexToOffset(static_cast<voffset_t>(i));
1615 }
1616 }
1617 }
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001618
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -07001619 ECHECK(CheckClash(fields, struct_def, UnionTypeFieldSuffix(),
1620 BASE_TYPE_UNION));
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001621 ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION));
1622 ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR));
1623 ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR));
1624 ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
1625 ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001626 EXPECT('}');
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001627 types_.Add(current_namespace_->GetFullyQualifiedName(struct_def->name),
Wouter van Oortmerssen9b3d8b32017-01-27 15:28:57 -08001628 new Type(BASE_TYPE_STRUCT, struct_def, nullptr));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001629 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001630}
1631
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001632CheckedError Parser::ParseService() {
1633 std::vector<std::string> service_comment = doc_comment_;
1634 NEXT();
1635 auto service_name = attribute_;
1636 EXPECT(kTokenIdentifier);
1637 auto &service_def = *new ServiceDef();
1638 service_def.name = service_name;
1639 service_def.file = file_being_parsed_;
1640 service_def.doc_comment = service_comment;
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001641 service_def.defined_namespace = current_namespace_;
1642 if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name),
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001643 &service_def))
1644 return Error("service already exists: " + service_name);
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001645 ECHECK(ParseMetaData(&service_def.attributes));
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001646 EXPECT('{');
1647 do {
Yuri Finkelstein8518b3f2017-12-21 07:55:57 -10001648 std::vector<std::string> rpc_comment = doc_comment_;
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001649 auto rpc_name = attribute_;
1650 EXPECT(kTokenIdentifier);
1651 EXPECT('(');
1652 Type reqtype, resptype;
1653 ECHECK(ParseTypeIdent(reqtype));
1654 EXPECT(')');
1655 EXPECT(':');
1656 ECHECK(ParseTypeIdent(resptype));
1657 if (reqtype.base_type != BASE_TYPE_STRUCT || reqtype.struct_def->fixed ||
1658 resptype.base_type != BASE_TYPE_STRUCT || resptype.struct_def->fixed)
1659 return Error("rpc request and response types must be tables");
1660 auto &rpc = *new RPCCall();
1661 rpc.name = rpc_name;
1662 rpc.request = reqtype.struct_def;
1663 rpc.response = resptype.struct_def;
Yuri Finkelstein8518b3f2017-12-21 07:55:57 -10001664 rpc.rpc_comment = rpc_comment;
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001665 if (service_def.calls.Add(rpc_name, &rpc))
1666 return Error("rpc already exists: " + rpc_name);
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001667 ECHECK(ParseMetaData(&rpc.attributes));
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001668 EXPECT(';');
1669 } while (token_ != '}');
1670 NEXT();
1671 return NoError();
1672}
1673
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001674bool Parser::SetRootType(const char *name) {
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -07001675 root_struct_def_ = LookupStruct(name);
Wouter van Oortmerssen4dcaec72015-12-09 16:41:12 -08001676 if (!root_struct_def_)
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -07001677 root_struct_def_ = LookupStruct(
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001678 current_namespace_->GetFullyQualifiedName(name));
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07001679 return root_struct_def_ != nullptr;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001680}
1681
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001682void Parser::MarkGenerated() {
Wouter van Oortmerssen3881bbd2015-11-30 16:42:48 -08001683 // This function marks all existing definitions as having already
1684 // been generated, which signals no code for included files should be
1685 // generated.
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001686 for (auto it = enums_.vec.begin();
1687 it != enums_.vec.end(); ++it) {
1688 (*it)->generated = true;
1689 }
1690 for (auto it = structs_.vec.begin();
1691 it != structs_.vec.end(); ++it) {
Robbie McElrath0e85eee2017-06-26 09:07:02 -07001692 if (!(*it)->predecl) {
1693 (*it)->generated = true;
1694 }
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001695 }
Wouter van Oortmerssen48f37f92016-04-13 18:16:05 -07001696 for (auto it = services_.vec.begin();
1697 it != services_.vec.end(); ++it) {
1698 (*it)->generated = true;
1699 }
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001700}
1701
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001702CheckedError Parser::ParseNamespace() {
1703 NEXT();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001704 auto ns = new Namespace();
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001705 namespaces_.push_back(ns); // Store it here to not leak upon error.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001706 if (token_ != ';') {
1707 for (;;) {
1708 ns->components.push_back(attribute_);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001709 EXPECT(kTokenIdentifier);
1710 if (Is('.')) NEXT() else break;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001711 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001712 }
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001713 namespaces_.pop_back();
1714 current_namespace_ = UniqueNamespace(ns);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001715 EXPECT(';');
1716 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001717}
1718
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001719static bool compareEnumVals(const EnumVal *a, const EnumVal* b) {
1720 return a->value < b->value;
1721}
1722
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001723// Best effort parsing of .proto declarations, with the aim to turn them
1724// in the closest corresponding FlatBuffer equivalent.
1725// We parse everything as identifiers instead of keywords, since we don't
1726// want protobuf keywords to become invalid identifiers in FlatBuffers.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001727CheckedError Parser::ParseProtoDecl() {
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001728 bool isextend = IsIdent("extend");
1729 if (IsIdent("package")) {
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001730 // These are identical in syntax to FlatBuffer's namespace decl.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001731 ECHECK(ParseNamespace());
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001732 } else if (IsIdent("message") || isextend) {
Advay Mengle3ad85362015-03-31 02:03:11 -07001733 std::vector<std::string> struct_comment = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001734 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001735 StructDef *struct_def = nullptr;
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001736 Namespace *parent_namespace = nullptr;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001737 if (isextend) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001738 if (Is('.')) NEXT(); // qualified names may start with a . ?
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001739 auto id = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001740 EXPECT(kTokenIdentifier);
1741 ECHECK(ParseNamespacing(&id, nullptr));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001742 struct_def = LookupCreateStruct(id, false);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001743 if (!struct_def)
1744 return Error("cannot extend unknown message type: " + id);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001745 } else {
1746 std::string name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001747 EXPECT(kTokenIdentifier);
1748 ECHECK(StartStruct(name, &struct_def));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001749 // Since message definitions can be nested, we create a new namespace.
1750 auto ns = new Namespace();
1751 // Copy of current namespace.
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001752 *ns = *current_namespace_;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001753 // But with current message name.
1754 ns->components.push_back(name);
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -07001755 ns->from_table++;
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001756 parent_namespace = current_namespace_;
1757 current_namespace_ = UniqueNamespace(ns);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001758 }
1759 struct_def->doc_comment = struct_comment;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001760 ECHECK(ParseProtoFields(struct_def, isextend, false));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001761 if (!isextend) {
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07001762 current_namespace_ = parent_namespace;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001763 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001764 if (Is(';')) NEXT();
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001765 } else if (IsIdent("enum")) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001766 // These are almost the same, just with different terminator:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001767 EnumDef *enum_def;
1768 ECHECK(ParseEnum(false, &enum_def));
1769 if (Is(';')) NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001770 // Protobuf allows them to be specified in any order, so sort afterwards.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001771 auto &v = enum_def->vals.vec;
Wouter van Oortmerssend7793082016-02-10 11:25:31 -08001772 std::sort(v.begin(), v.end(), compareEnumVals);
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001773
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001774 // Temp: remove any duplicates, as .fbs files can't handle them.
1775 for (auto it = v.begin(); it != v.end(); ) {
1776 if (it != v.begin() && it[0]->value == it[-1]->value) it = v.erase(it);
1777 else ++it;
1778 }
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001779 } else if (IsIdent("syntax")) { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001780 NEXT();
1781 EXPECT('=');
1782 EXPECT(kTokenStringConstant);
1783 EXPECT(';');
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001784 } else if (IsIdent("option")) { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001785 ECHECK(ParseProtoOption());
1786 EXPECT(';');
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001787 } else if (IsIdent("service")) { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001788 NEXT();
1789 EXPECT(kTokenIdentifier);
1790 ECHECK(ParseProtoCurliesOrIdent());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001791 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001792 return Error("don\'t know how to parse .proto declaration starting with " +
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001793 TokenToStringId(token_));
1794 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001795 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001796}
1797
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001798CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend,
1799 bool inside_oneof) {
1800 EXPECT('{');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001801 while (token_ != '}') {
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001802 if (IsIdent("message") || IsIdent("extend") || IsIdent("enum")) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001803 // Nested declarations.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001804 ECHECK(ParseProtoDecl());
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001805 } else if (IsIdent("extensions")) { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001806 NEXT();
1807 EXPECT(kTokenIntegerConstant);
1808 if (Is(kTokenIdentifier)) {
1809 NEXT(); // to
1810 NEXT(); // num
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001811 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001812 EXPECT(';');
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001813 } else if (IsIdent("option")) { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001814 ECHECK(ParseProtoOption());
1815 EXPECT(';');
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001816 } else if (IsIdent("reserved")) { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001817 NEXT();
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -07001818 while (!Is(';')) { NEXT(); } // A variety of formats, just skip.
1819 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001820 } else {
1821 std::vector<std::string> field_comment = doc_comment_;
1822 // Parse the qualifier.
1823 bool required = false;
1824 bool repeated = false;
1825 bool oneof = false;
1826 if (!inside_oneof) {
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001827 if (IsIdent("optional")) {
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001828 // This is the default.
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001829 NEXT();
1830 } else if (IsIdent("required")) {
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001831 required = true;
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001832 NEXT();
1833 } else if (IsIdent("repeated")) {
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001834 repeated = true;
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001835 NEXT();
1836 } else if (IsIdent("oneof")) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001837 oneof = true;
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001838 NEXT();
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001839 } else {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001840 // can't error, proto3 allows decls without any of the above.
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001841 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001842 }
1843 StructDef *anonymous_struct = nullptr;
1844 Type type;
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001845 if (IsIdent("group") || oneof) {
1846 if (!oneof) NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001847 auto name = "Anonymous" + NumToString(anonymous_counter++);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001848 ECHECK(StartStruct(name, &anonymous_struct));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001849 type = Type(BASE_TYPE_STRUCT, anonymous_struct);
1850 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001851 ECHECK(ParseTypeFromProtoType(&type));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001852 }
1853 // Repeated elements get mapped to a vector.
1854 if (repeated) {
1855 type.element = type.base_type;
1856 type.base_type = BASE_TYPE_VECTOR;
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -07001857 if (type.element == BASE_TYPE_VECTOR) {
1858 // We have a vector or vectors, which FlatBuffers doesn't support.
1859 // For now make it a vector of string (since the source is likely
1860 // "repeated bytes").
1861 // TODO(wvo): A better solution would be to wrap this in a table.
1862 type.element = BASE_TYPE_STRING;
1863 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001864 }
1865 std::string name = attribute_;
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07001866 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001867 if (!oneof) {
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001868 // Parse the field id. Since we're just translating schemas, not
1869 // any kind of binary compatibility, we can safely ignore these, and
1870 // assign our own.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001871 EXPECT('=');
1872 EXPECT(kTokenIntegerConstant);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001873 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001874 FieldDef *field = nullptr;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001875 if (isextend) {
1876 // We allow a field to be re-defined when extending.
1877 // TODO: are there situations where that is problematic?
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001878 field = struct_def->fields.Lookup(name);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001879 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001880 if (!field) ECHECK(AddField(*struct_def, name, type, &field));
1881 field->doc_comment = field_comment;
1882 if (!IsScalar(type.base_type)) field->required = required;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001883 // See if there's a default specified.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001884 if (Is('[')) {
1885 NEXT();
1886 for (;;) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001887 auto key = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001888 ECHECK(ParseProtoKey());
1889 EXPECT('=');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001890 auto val = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001891 ECHECK(ParseProtoCurliesOrIdent());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001892 if (key == "default") {
1893 // Temp: skip non-numeric defaults (enums).
1894 auto numeric = strpbrk(val.c_str(), "0123456789-+.");
1895 if (IsScalar(type.base_type) && numeric == val.c_str())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001896 field->value.constant = val;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001897 } else if (key == "deprecated") {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001898 field->deprecated = val == "true";
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001899 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001900 if (!Is(',')) break;
1901 NEXT();
1902 }
1903 EXPECT(']');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001904 }
1905 if (anonymous_struct) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001906 ECHECK(ParseProtoFields(anonymous_struct, false, oneof));
1907 if (Is(';')) NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001908 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001909 EXPECT(';');
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001910 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001911 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001912 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001913 NEXT();
1914 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001915}
1916
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001917CheckedError Parser::ParseProtoKey() {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001918 if (token_ == '(') {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001919 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001920 // Skip "(a.b)" style custom attributes.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001921 while (token_ == '.' || token_ == kTokenIdentifier) NEXT();
1922 EXPECT(')');
1923 while (Is('.')) { NEXT(); EXPECT(kTokenIdentifier); }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001924 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001925 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001926 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001927 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001928}
1929
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001930CheckedError Parser::ParseProtoCurliesOrIdent() {
1931 if (Is('{')) {
1932 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001933 for (int nesting = 1; nesting; ) {
1934 if (token_ == '{') nesting++;
1935 else if (token_ == '}') nesting--;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001936 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001937 }
1938 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001939 NEXT(); // Any single token.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001940 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001941 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001942}
1943
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001944CheckedError Parser::ParseProtoOption() {
1945 NEXT();
1946 ECHECK(ParseProtoKey());
1947 EXPECT('=');
1948 ECHECK(ParseProtoCurliesOrIdent());
1949 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001950}
1951
1952// Parse a protobuf type, and map it to the corresponding FlatBuffer one.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001953CheckedError Parser::ParseTypeFromProtoType(Type *type) {
Wouter van Oortmerssen69776b92017-08-14 14:45:29 -07001954 struct type_lookup { const char *proto_type; BaseType fb_type, element; };
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001955 static type_lookup lookup[] = {
Wouter van Oortmerssen69776b92017-08-14 14:45:29 -07001956 { "float", BASE_TYPE_FLOAT, BASE_TYPE_NONE },
1957 { "double", BASE_TYPE_DOUBLE, BASE_TYPE_NONE },
1958 { "int32", BASE_TYPE_INT, BASE_TYPE_NONE },
1959 { "int64", BASE_TYPE_LONG, BASE_TYPE_NONE },
1960 { "uint32", BASE_TYPE_UINT, BASE_TYPE_NONE },
1961 { "uint64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
1962 { "sint32", BASE_TYPE_INT, BASE_TYPE_NONE },
1963 { "sint64", BASE_TYPE_LONG, BASE_TYPE_NONE },
1964 { "fixed32", BASE_TYPE_UINT, BASE_TYPE_NONE },
1965 { "fixed64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
1966 { "sfixed32", BASE_TYPE_INT, BASE_TYPE_NONE },
1967 { "sfixed64", BASE_TYPE_LONG, BASE_TYPE_NONE },
1968 { "bool", BASE_TYPE_BOOL, BASE_TYPE_NONE },
1969 { "string", BASE_TYPE_STRING, BASE_TYPE_NONE },
1970 { "bytes", BASE_TYPE_VECTOR, BASE_TYPE_UCHAR },
1971 { nullptr, BASE_TYPE_NONE, BASE_TYPE_NONE }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001972 };
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001973 for (auto tl = lookup; tl->proto_type; tl++) {
1974 if (attribute_ == tl->proto_type) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001975 type->base_type = tl->fb_type;
Wouter van Oortmerssen69776b92017-08-14 14:45:29 -07001976 type->element = tl->element;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001977 NEXT();
1978 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001979 }
1980 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001981 if (Is('.')) NEXT(); // qualified names may start with a . ?
1982 ECHECK(ParseTypeIdent(*type));
1983 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001984}
1985
Nalinichandra Penke13d05942015-12-22 00:02:19 -08001986CheckedError Parser::SkipAnyJsonValue() {
1987 switch (token_) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001988 case '{': {
Stewart Milesa8923222017-07-13 06:27:39 -07001989 size_t fieldn_outer = 0;
1990 return ParseTableDelimiters(fieldn_outer, nullptr,
1991 [](const std::string &,
1992 size_t &fieldn, const StructDef *,
1993 void *state) -> CheckedError {
1994 auto *parser = static_cast<Parser *>(state);
1995 ECHECK(parser->SkipAnyJsonValue());
1996 fieldn++;
1997 return NoError();
1998 },
1999 this);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002000 }
2001 case '[': {
2002 size_t count = 0;
Stewart Milesa8923222017-07-13 06:27:39 -07002003 return ParseVectorDelimiters(count, [](size_t &,
2004 void *state) -> CheckedError {
2005 return static_cast<Parser *>(state)->SkipAnyJsonValue();
2006 },
2007 this);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002008 }
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002009 case kTokenStringConstant:
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002010 case kTokenIntegerConstant:
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002011 case kTokenFloatConstant:
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002012 NEXT();
rouziera2b1bfc2017-08-04 11:04:28 -04002013 break;
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002014 default:
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002015 if (IsIdent("true") || IsIdent("false") || IsIdent("null")) { NEXT(); }
2016 else return TokenError();
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002017 }
2018 return NoError();
2019}
2020
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002021CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
2022 switch (token_) {
2023 case '{': {
Stewart Milesa8923222017-07-13 06:27:39 -07002024 std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state(
2025 this, builder);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002026 auto start = builder->StartMap();
Stewart Milesa8923222017-07-13 06:27:39 -07002027 size_t fieldn_outer = 0;
2028 auto err = ParseTableDelimiters(fieldn_outer, nullptr,
2029 [](const std::string &name,
2030 size_t &fieldn, const StructDef *,
2031 void *state) -> CheckedError {
2032 auto *parser_and_builder =
2033 static_cast<std::pair<Parser *, flexbuffers::Builder *> *>(
2034 state);
2035 auto *parser = parser_and_builder->first;
2036 auto *current_builder = parser_and_builder->second;
2037 current_builder->Key(name);
2038 ECHECK(parser->ParseFlexBufferValue(current_builder));
2039 fieldn++;
2040 return NoError();
2041 },
2042 &parser_and_builder_state);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002043 ECHECK(err);
2044 builder->EndMap(start);
2045 break;
Nalinichandra Penkecbab2662016-02-22 14:27:08 -06002046 }
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002047 case '[':{
2048 auto start = builder->StartVector();
2049 size_t count = 0;
Stewart Milesa8923222017-07-13 06:27:39 -07002050 std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state(
2051 this, builder);
2052 ECHECK(ParseVectorDelimiters(count, [](size_t &,
2053 void *state) -> CheckedError {
2054 auto *parser_and_builder =
2055 static_cast<std::pair<Parser *, flexbuffers::Builder *> *>(
2056 state);
2057 return parser_and_builder->first->ParseFlexBufferValue(
2058 parser_and_builder->second);
2059 },
2060 &parser_and_builder_state));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002061 builder->EndVector(start, false, false);
2062 break;
Nalinichandra Penkecbab2662016-02-22 14:27:08 -06002063 }
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002064 case kTokenStringConstant:
2065 builder->String(attribute_);
2066 EXPECT(kTokenStringConstant);
2067 break;
2068 case kTokenIntegerConstant:
2069 builder->Int(StringToInt(attribute_.c_str()));
2070 EXPECT(kTokenIntegerConstant);
2071 break;
2072 case kTokenFloatConstant:
2073 builder->Double(strtod(attribute_.c_str(), nullptr));
2074 EXPECT(kTokenFloatConstant);
2075 break;
2076 default:
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002077 if (IsIdent("true")) { builder->Bool(true); NEXT(); }
2078 else if (IsIdent("false")) { builder->Bool(false); NEXT(); }
2079 else if (IsIdent("null")) { builder->Null(); NEXT(); }
2080 else return TokenError();
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002081 }
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002082 return NoError();
2083}
2084
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002085bool Parser::ParseFlexBuffer(const char *source, const char *source_filename,
2086 flexbuffers::Builder *builder) {
2087 auto ok = !StartParseFile(source, source_filename).Check() &&
2088 !ParseFlexBufferValue(builder).Check();
2089 if (ok) builder->Finish();
2090 return ok;
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002091}
2092
Wouter van Oortmerssen30642c52014-09-22 15:49:43 -07002093bool Parser::Parse(const char *source, const char **include_paths,
2094 const char *source_filename) {
Robbie McElrath0e85eee2017-06-26 09:07:02 -07002095 return !ParseRoot(source, include_paths, source_filename).Check();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002096}
2097
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002098CheckedError Parser::StartParseFile(const char *source, const char *source_filename) {
2099 file_being_parsed_ = source_filename ? source_filename : "";
2100 source_ = cursor_ = source;
2101 line_ = 1;
2102 error_.clear();
2103 ECHECK(SkipByteOrderMark());
2104 NEXT();
2105 if (Is(kTokenEof))
2106 return Error("input file is empty");
2107 return NoError();
2108}
2109
Robbie McElrath0e85eee2017-06-26 09:07:02 -07002110CheckedError Parser::ParseRoot(const char *source, const char **include_paths,
2111 const char *source_filename) {
2112 ECHECK(DoParse(source, include_paths, source_filename, nullptr));
2113
2114 // Check that all types were defined.
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -07002115 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ) {
2116 auto &struct_def = **it;
2117 if (struct_def.predecl) {
2118 if (opts.proto_mode) {
2119 // Protos allow enums to be used before declaration, so check if that
2120 // is the case here.
2121 EnumDef *enum_def = nullptr;
2122 for (size_t components = struct_def.defined_namespace->
2123 components.size() + 1;
2124 components && !enum_def; components--) {
2125 auto qualified_name = struct_def.defined_namespace->
2126 GetFullyQualifiedName(struct_def.name,
2127 components - 1);
2128 enum_def = LookupEnum(qualified_name);
2129 }
2130 if (enum_def) {
2131 // This is pretty slow, but a simple solution for now.
2132 auto initial_count = struct_def.refcount;
2133 for (auto struct_it = structs_.vec.begin();
2134 struct_it != structs_.vec.end();
2135 ++struct_it) {
2136 auto &sd = **struct_it;
2137 for (auto field_it = sd.fields.vec.begin();
2138 field_it != sd.fields.vec.end();
2139 ++field_it) {
2140 auto &field = **field_it;
2141 if (field.value.type.struct_def == &struct_def) {
2142 field.value.type.struct_def = nullptr;
2143 field.value.type.enum_def = enum_def;
2144 auto &bt = field.value.type.base_type == BASE_TYPE_VECTOR
2145 ? field.value.type.element
2146 : field.value.type.base_type;
2147 assert(bt == BASE_TYPE_STRUCT);
2148 bt = enum_def->underlying_type.base_type;
2149 struct_def.refcount--;
2150 enum_def->refcount++;
2151 }
2152 }
2153 }
2154 if (struct_def.refcount)
2155 return Error("internal: " + NumToString(struct_def.refcount) + "/" +
2156 NumToString(initial_count) +
2157 " use(s) of pre-declaration enum not accounted for: "
2158 + enum_def->name);
2159 structs_.dict.erase(structs_.dict.find(struct_def.name));
2160 it = structs_.vec.erase(it);
2161 delete &struct_def;
2162 continue; // Skip error.
2163 }
2164 }
2165 auto err = "type referenced but not defined (check namespace): " +
2166 struct_def.name;
2167 if (struct_def.original_location)
2168 err += ", originally at: " + *struct_def.original_location;
2169 return Error(err);
Robbie McElrath0e85eee2017-06-26 09:07:02 -07002170 }
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -07002171 ++it;
Robbie McElrath0e85eee2017-06-26 09:07:02 -07002172 }
2173
2174 // This check has to happen here and not earlier, because only now do we
2175 // know for sure what the type of these are.
2176 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
2177 auto &enum_def = **it;
2178 if (enum_def.is_union) {
2179 for (auto val_it = enum_def.vals.vec.begin();
2180 val_it != enum_def.vals.vec.end();
2181 ++val_it) {
2182 auto &val = **val_it;
Kamil Rojewski46bb05d2017-08-11 18:24:36 +02002183 if (!SupportsVectorOfUnions() &&
Robbie McElrath0e85eee2017-06-26 09:07:02 -07002184 val.union_type.struct_def && val.union_type.struct_def->fixed)
2185 return Error(
2186 "only tables can be union elements in the generated language: "
2187 + val.name);
2188 }
2189 }
2190 }
2191 return NoError();
2192}
2193
2194CheckedError Parser::DoParse(const char *source,
2195 const char **include_paths,
2196 const char *source_filename,
2197 const char *include_filename) {
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002198 if (source_filename &&
Pavel Kalinnikov642254b2017-06-02 17:50:18 +02002199 included_files_.find(source_filename) == included_files_.end()) {
2200 included_files_[source_filename] = include_filename ? include_filename : "";
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002201 files_included_per_file_[source_filename] = std::set<std::string>();
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002202 }
2203 if (!include_paths) {
Wouter van Oortmerssen1e6f8f52015-06-22 10:23:42 -07002204 static const char *current_directory[] = { "", nullptr };
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002205 include_paths = current_directory;
2206 }
Yonggang Lifea6b522017-01-03 13:54:15 -08002207 field_stack_.clear();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002208 builder_.Clear();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07002209 // Start with a blank namespace just in case this file doesn't have one.
Wouter van Oortmerssen321a1c92017-08-24 12:55:35 -07002210 current_namespace_ = empty_namespace_;
Louis-Paul CORDIERe7e4dc72017-03-10 17:50:44 +01002211
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002212 ECHECK(StartParseFile(source, source_filename));
Louis-Paul CORDIERe7e4dc72017-03-10 17:50:44 +01002213
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002214 // Includes must come before type declarations:
2215 for (;;) {
2216 // Parse pre-include proto statements if any:
2217 if (opts.proto_mode &&
2218 (attribute_ == "option" || attribute_ == "syntax" ||
2219 attribute_ == "package")) {
2220 ECHECK(ParseProtoDecl());
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002221 } else if (IsIdent("native_include")) {
Wouter van Oortmerssen3f936c52017-01-18 16:23:35 -08002222 NEXT();
Stewart Milesa8923222017-07-13 06:27:39 -07002223 vector_emplace_back(&native_included_files_, attribute_);
Wouter van Oortmerssen3f936c52017-01-18 16:23:35 -08002224 EXPECT(kTokenStringConstant);
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002225 } else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002226 NEXT();
2227 if (opts.proto_mode && attribute_ == "public") NEXT();
Wouter van Oortmerssenaaf55982017-05-18 17:18:43 -07002228 auto name = flatbuffers::PosixPath(attribute_.c_str());
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002229 EXPECT(kTokenStringConstant);
2230 // Look for the file in include_paths.
2231 std::string filepath;
2232 for (auto paths = include_paths; paths && *paths; paths++) {
2233 filepath = flatbuffers::ConCatPathFileName(*paths, name);
2234 if(FileExists(filepath.c_str())) break;
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07002235 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002236 if (filepath.empty())
2237 return Error("unable to locate include file: " + name);
2238 if (source_filename)
2239 files_included_per_file_[source_filename].insert(filepath);
Pavel Kalinnikov642254b2017-06-02 17:50:18 +02002240 if (included_files_.find(filepath) == included_files_.end()) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002241 // We found an include file that we have not parsed yet.
2242 // Load it and parse it.
2243 std::string contents;
2244 if (!LoadFile(filepath.c_str(), true, &contents))
2245 return Error("unable to load include file: " + name);
Wouter van Oortmerssen22743ca2017-05-24 15:21:26 -07002246 ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
2247 name.c_str()));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002248 // We generally do not want to output code for any included files:
2249 if (!opts.generate_all) MarkGenerated();
Wouter van Oortmerssen432e7582017-08-14 10:41:39 -07002250 // Reset these just in case the included file had them, and the
Wouter van Oortmerssendca33dd2017-08-14 09:22:12 -07002251 // parent doesn't.
2252 root_struct_def_ = nullptr;
Wouter van Oortmerssen432e7582017-08-14 10:41:39 -07002253 file_identifier_.clear();
2254 file_extension_.clear();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002255 // This is the easiest way to continue this file after an include:
2256 // instead of saving and restoring all the state, we simply start the
2257 // file anew. This will cause it to encounter the same include
2258 // statement again, but this time it will skip it, because it was
2259 // entered into included_files_.
2260 // This is recursive, but only go as deep as the number of include
2261 // statements.
Wouter van Oortmerssen22743ca2017-05-24 15:21:26 -07002262 return DoParse(source, include_paths, source_filename, include_filename);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002263 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002264 EXPECT(';');
2265 } else {
2266 break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002267 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002268 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002269 // Now parse all other kinds of declarations:
2270 while (token_ != kTokenEof) {
2271 if (opts.proto_mode) {
2272 ECHECK(ParseProtoDecl());
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002273 } else if (IsIdent("namespace")) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002274 ECHECK(ParseNamespace());
2275 } else if (token_ == '{') {
2276 if (!root_struct_def_)
2277 return Error("no root type set to parse json with");
2278 if (builder_.GetSize()) {
2279 return Error("cannot have more than one json object in a file");
2280 }
2281 uoffset_t toff;
2282 ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
2283 builder_.Finish(Offset<Table>(toff),
2284 file_identifier_.length() ? file_identifier_.c_str() : nullptr);
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002285 } else if (IsIdent("enum")) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002286 ECHECK(ParseEnum(false, nullptr));
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002287 } else if (IsIdent("union")) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002288 ECHECK(ParseEnum(true, nullptr));
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002289 } else if (IsIdent("root_type")) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002290 NEXT();
2291 auto root_type = attribute_;
2292 EXPECT(kTokenIdentifier);
2293 ECHECK(ParseNamespacing(&root_type, nullptr));
2294 if (!SetRootType(root_type.c_str()))
2295 return Error("unknown root type: " + root_type);
2296 if (root_struct_def_->fixed)
2297 return Error("root type must be a table");
2298 EXPECT(';');
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002299 } else if (IsIdent("file_identifier")) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002300 NEXT();
2301 file_identifier_ = attribute_;
2302 EXPECT(kTokenStringConstant);
2303 if (file_identifier_.length() !=
2304 FlatBufferBuilder::kFileIdentifierLength)
2305 return Error("file_identifier must be exactly " +
2306 NumToString(FlatBufferBuilder::kFileIdentifierLength) +
2307 " characters");
2308 EXPECT(';');
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002309 } else if (IsIdent("file_extension")) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002310 NEXT();
2311 file_extension_ = attribute_;
2312 EXPECT(kTokenStringConstant);
2313 EXPECT(';');
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002314 } else if(IsIdent("include")) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002315 return Error("includes must come before declarations");
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002316 } else if(IsIdent("attribute")) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002317 NEXT();
2318 auto name = attribute_;
2319 EXPECT(kTokenStringConstant);
2320 EXPECT(';');
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002321 known_attributes_[name] = false;
Wouter van Oortmerssen03e28992017-09-22 14:32:07 -07002322 } else if (IsIdent("rpc_service")) {
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08002323 ECHECK(ParseService());
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002324 } else {
2325 ECHECK(ParseDecl());
2326 }
2327 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002328 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002329}
2330
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002331std::set<std::string> Parser::GetIncludedFilesRecursive(
2332 const std::string &file_name) const {
2333 std::set<std::string> included_files;
2334 std::list<std::string> to_process;
2335
2336 if (file_name.empty()) return included_files;
2337 to_process.push_back(file_name);
2338
2339 while (!to_process.empty()) {
2340 std::string current = to_process.front();
2341 to_process.pop_front();
2342 included_files.insert(current);
2343
Stewart Milesa8923222017-07-13 06:27:39 -07002344 // Workaround the lack of const accessor in C++98 maps.
2345 auto &new_files =
2346 (*const_cast<std::map<std::string, std::set<std::string>> *>(
2347 &files_included_per_file_))[current];
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002348 for (auto it = new_files.begin(); it != new_files.end(); ++it) {
2349 if (included_files.find(*it) == included_files.end())
2350 to_process.push_back(*it);
2351 }
2352 }
2353
2354 return included_files;
2355}
2356
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002357// Schema serialization functionality:
2358
Chandra Penkeb63ebad2016-01-06 08:31:53 -08002359template<typename T> bool compareName(const T* a, const T* b) {
Xun Liudf0991b2016-09-14 10:33:06 -07002360 return a->defined_namespace->GetFullyQualifiedName(a->name)
2361 < b->defined_namespace->GetFullyQualifiedName(b->name);
Chandra Penkeb63ebad2016-01-06 08:31:53 -08002362}
2363
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002364template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
2365 // Pre-sort these vectors, such that we can set the correct indices for them.
2366 auto vec = defvec;
Chandra Penkeb63ebad2016-01-06 08:31:53 -08002367 std::sort(vec.begin(), vec.end(), compareName<T>);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002368 for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
2369}
2370
2371void Parser::Serialize() {
2372 builder_.Clear();
2373 AssignIndices(structs_.vec);
2374 AssignIndices(enums_.vec);
2375 std::vector<Offset<reflection::Object>> object_offsets;
2376 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002377 auto offset = (*it)->Serialize(&builder_, *this);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002378 object_offsets.push_back(offset);
2379 (*it)->serialized_location = offset.o;
2380 }
2381 std::vector<Offset<reflection::Enum>> enum_offsets;
2382 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002383 auto offset = (*it)->Serialize(&builder_, *this);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002384 enum_offsets.push_back(offset);
2385 (*it)->serialized_location = offset.o;
2386 }
2387 auto schema_offset = reflection::CreateSchema(
2388 builder_,
2389 builder_.CreateVectorOfSortedTables(&object_offsets),
2390 builder_.CreateVectorOfSortedTables(&enum_offsets),
2391 builder_.CreateString(file_identifier_),
2392 builder_.CreateString(file_extension_),
Wouter van Oortmerssen36c7e9a2015-06-29 15:21:48 -07002393 root_struct_def_
2394 ? root_struct_def_->serialized_location
2395 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002396 builder_.Finish(schema_offset, reflection::SchemaIdentifier());
2397}
2398
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002399Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
2400 const Parser &parser) const {
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002401 std::vector<Offset<reflection::Field>> field_offsets;
2402 for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
Wouter van Oortmerssen622b8d02015-06-15 15:57:48 -07002403 field_offsets.push_back(
2404 (*it)->Serialize(builder,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002405 static_cast<uint16_t>(it - fields.vec.begin()), parser));
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002406 }
Xun Liudf0991b2016-09-14 10:33:06 -07002407 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002408 return reflection::CreateObject(*builder,
Xun Liudf0991b2016-09-14 10:33:06 -07002409 builder->CreateString(qualified_name),
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002410 builder->CreateVectorOfSortedTables(
2411 &field_offsets),
Wouter van Oortmerssencb2b2be2015-06-23 16:06:35 -07002412 fixed,
2413 static_cast<int>(minalign),
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002414 static_cast<int>(bytesize),
Wouter van Oortmerssen1fb6b9e2017-02-13 16:15:55 -08002415 SerializeAttributes(builder, parser),
2416 parser.opts.binary_schema_comments
2417 ? builder->CreateVectorOfStrings(
2418 doc_comment)
2419 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002420}
2421
2422Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002423 uint16_t id,
2424 const Parser &parser) const {
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002425 return reflection::CreateField(*builder,
2426 builder->CreateString(name),
2427 value.type.Serialize(builder),
2428 id,
2429 value.offset,
2430 IsInteger(value.type.base_type)
2431 ? StringToInt(value.constant.c_str())
2432 : 0,
2433 IsFloat(value.type.base_type)
2434 ? strtod(value.constant.c_str(), nullptr)
2435 : 0.0,
2436 deprecated,
2437 required,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002438 key,
Wouter van Oortmerssen1fb6b9e2017-02-13 16:15:55 -08002439 SerializeAttributes(builder, parser),
2440 parser.opts.binary_schema_comments
2441 ? builder->CreateVectorOfStrings(doc_comment)
2442 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002443 // TODO: value.constant is almost always "0", we could save quite a bit of
2444 // space by sharing it. Same for common values of value.type.
2445}
2446
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002447Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
2448 const Parser &parser) const {
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002449 std::vector<Offset<reflection::EnumVal>> enumval_offsets;
2450 for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
2451 enumval_offsets.push_back((*it)->Serialize(builder));
2452 }
Xun Liudf0991b2016-09-14 10:33:06 -07002453 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002454 return reflection::CreateEnum(*builder,
Xun Liudf0991b2016-09-14 10:33:06 -07002455 builder->CreateString(qualified_name),
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002456 builder->CreateVector(enumval_offsets),
2457 is_union,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002458 underlying_type.Serialize(builder),
Wouter van Oortmerssen1fb6b9e2017-02-13 16:15:55 -08002459 SerializeAttributes(builder, parser),
2460 parser.opts.binary_schema_comments
2461 ? builder->CreateVectorOfStrings(doc_comment)
2462 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002463}
2464
2465Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const
2466 {
2467 return reflection::CreateEnumVal(*builder,
2468 builder->CreateString(name),
2469 value,
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -07002470 union_type.struct_def
2471 ? union_type.struct_def->
2472 serialized_location
2473 : 0,
2474 union_type.Serialize(builder));
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002475}
2476
2477Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
2478 return reflection::CreateType(*builder,
2479 static_cast<reflection::BaseType>(base_type),
2480 static_cast<reflection::BaseType>(element),
2481 struct_def ? struct_def->index :
2482 (enum_def ? enum_def->index : -1));
2483}
2484
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002485flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<
2486 reflection::KeyValue>>>
2487 Definition::SerializeAttributes(FlatBufferBuilder *builder,
2488 const Parser &parser) const {
2489 std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -07002490 for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) {
2491 auto it = parser.known_attributes_.find(kv->first);
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002492 assert(it != parser.known_attributes_.end());
2493 if (!it->second) { // Custom attribute.
2494 attrs.push_back(
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -07002495 reflection::CreateKeyValue(*builder, builder->CreateString(kv->first),
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002496 builder->CreateString(
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -07002497 kv->second->constant)));
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002498 }
2499 }
2500 if (attrs.size()) {
2501 return builder->CreateVectorOfSortedTables(&attrs);
2502 } else {
2503 return 0;
2504 }
2505}
2506
Wouter van Oortmerssen05b00c52016-07-20 17:24:50 -07002507std::string Parser::ConformTo(const Parser &base) {
2508 for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) {
2509 auto &struct_def = **sit;
2510 auto qualified_name =
2511 struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name);
Wouter van Oortmerssen9c3920d2017-10-02 15:41:34 -07002512 auto struct_def_base = base.LookupStruct(qualified_name);
Wouter van Oortmerssen05b00c52016-07-20 17:24:50 -07002513 if (!struct_def_base) continue;
2514 for (auto fit = struct_def.fields.vec.begin();
2515 fit != struct_def.fields.vec.end(); ++fit) {
2516 auto &field = **fit;
2517 auto field_base = struct_def_base->fields.Lookup(field.name);
2518 if (field_base) {
2519 if (field.value.offset != field_base->value.offset)
2520 return "offsets differ for field: " + field.name;
2521 if (field.value.constant != field_base->value.constant)
2522 return "defaults differ for field: " + field.name;
2523 if (!EqualByName(field.value.type, field_base->value.type))
2524 return "types differ for field: " + field.name;
2525 } else {
2526 // Doesn't have to exist, deleting fields is fine.
2527 // But we should check if there is a field that has the same offset
2528 // but is incompatible (in the case of field renaming).
2529 for (auto fbit = struct_def_base->fields.vec.begin();
2530 fbit != struct_def_base->fields.vec.end(); ++fbit) {
2531 field_base = *fbit;
2532 if (field.value.offset == field_base->value.offset) {
2533 if (!EqualByName(field.value.type, field_base->value.type))
2534 return "field renamed to different type: " + field.name;
2535 break;
2536 }
2537 }
2538 }
2539 }
2540 }
2541 for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) {
2542 auto &enum_def = **eit;
2543 auto qualified_name =
2544 enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name);
2545 auto enum_def_base = base.enums_.Lookup(qualified_name);
2546 if (!enum_def_base) continue;
2547 for (auto evit = enum_def.vals.vec.begin();
2548 evit != enum_def.vals.vec.end(); ++evit) {
2549 auto &enum_val = **evit;
2550 auto enum_val_base = enum_def_base->vals.Lookup(enum_val.name);
2551 if (enum_val_base) {
2552 if (enum_val.value != enum_val_base->value)
2553 return "values differ for enum: " + enum_val.name;
2554 }
2555 }
2556 }
2557 return "";
2558}
2559
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002560} // namespace flatbuffers