blob: fff35aabedbb5ffdfb775b2252513d902e38c019 [file] [log] [blame]
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001/*
2 * Copyright 2014 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <algorithm>
Gabriel Martinezdf4909e2014-11-04 10:00:56 -080018#include <list>
Christian Helmich89a68942017-07-29 02:27:51 +090019#include <iostream>
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080020
Wouter van Oortmerssend3ac0bc2016-06-15 13:54:17 -070021#ifdef _WIN32
22#if !defined(_USE_MATH_DEFINES)
23#define _USE_MATH_DEFINES // For M_PI.
24#endif // !defined(_USE_MATH_DEFINES)
25#endif // _WIN32
26
27#include <math.h>
28
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080029#include "flatbuffers/idl.h"
30#include "flatbuffers/util.h"
31
32namespace flatbuffers {
33
34const char *const kTypeNames[] = {
rw48dfc692014-12-16 00:32:11 -080035 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
36 IDLTYPE,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080037 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
38 #undef FLATBUFFERS_TD
39 nullptr
40};
41
42const char kTypeSizes[] = {
rw48dfc692014-12-16 00:32:11 -080043 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen557c88c2014-09-16 17:37:17 -070044 sizeof(CTYPE),
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080045 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
46 #undef FLATBUFFERS_TD
47};
48
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -070049// The enums in the reflection schema should match the ones we use internally.
50// Compare the last element to check if these go out of sync.
51static_assert(BASE_TYPE_UNION ==
Wouter van Oortmerssen622b8d02015-06-15 15:57:48 -070052 static_cast<BaseType>(reflection::Union),
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -070053 "enums don't match");
54
Wouter van Oortmerssen451272b2015-12-29 16:33:00 -080055// Any parsing calls have to be wrapped in this macro, which automates
56// handling of recursive error checking a bit. It will check the received
57// CheckedError object, and return straight away on error.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080058#define ECHECK(call) { auto ce = (call); if (ce.Check()) return ce; }
Wouter van Oortmerssen451272b2015-12-29 16:33:00 -080059
60// These two functions are called hundreds of times below, so define a short
61// form:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080062#define NEXT() ECHECK(Next())
63#define EXPECT(tok) ECHECK(Expect(tok))
64
Ben Hamiltonf6416d82016-08-01 14:04:51 -070065static bool ValidateUTF8(const std::string &str) {
66 const char *s = &str[0];
67 const char * const sEnd = s + str.length();
68 while (s < sEnd) {
69 if (FromUTF8(&s) < 0) {
70 return false;
71 }
72 }
73 return true;
74}
75
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080076CheckedError Parser::Error(const std::string &msg) {
77 error_ = file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : "";
78 #ifdef _WIN32
79 error_ += "(" + NumToString(line_) + ")"; // MSVC alike
80 #else
81 if (file_being_parsed_.length()) error_ += ":";
82 error_ += NumToString(line_) + ":0"; // gcc alike
83 #endif
84 error_ += ": error: " + msg;
85 return CheckedError(true);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080086}
87
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -080088inline CheckedError NoError() { return CheckedError(false); }
89
Jason Stubbsa07f0d42017-04-18 04:19:43 +100090inline std::string OutOfRangeErrorMsg(int64_t val, const std::string &op,
91 int64_t limit) {
92 const std::string cause = NumToString(val) + op + NumToString(limit);
93 return "constant does not fit (" + cause + ")";
94}
95
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -080096// Ensure that integer values we parse fit inside the declared integer type.
Jason Stubbsa07f0d42017-04-18 04:19:43 +100097CheckedError Parser::CheckInRange(int64_t val, int64_t min, int64_t max) {
98 if (val < min)
99 return Error(OutOfRangeErrorMsg(val, " < ", min));
100 else if (val > max)
101 return Error(OutOfRangeErrorMsg(val, " > ", max));
102 else
103 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800104}
105
106// atot: templated version of atoi/atof: convert a string to an instance of T.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800107template<typename T> inline CheckedError atot(const char *s, Parser &parser,
108 T *val) {
109 int64_t i = StringToInt(s);
Stewart Milesa8923222017-07-13 06:27:39 -0700110 const int64_t min = flatbuffers::numeric_limits<T>::min();
111 const int64_t max = flatbuffers::numeric_limits<T>::max();
Jason Stubbsa07f0d42017-04-18 04:19:43 +1000112 ECHECK(parser.CheckInRange(i, min, max));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800113 *val = (T)i;
114 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800115}
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800116template<> inline CheckedError atot<uint64_t>(const char *s, Parser &parser,
117 uint64_t *val) {
118 (void)parser;
119 *val = StringToUInt(s);
120 return NoError();
121}
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800122template<> inline CheckedError atot<bool>(const char *s, Parser &parser,
123 bool *val) {
124 (void)parser;
125 *val = 0 != atoi(s);
126 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800127}
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800128template<> inline CheckedError atot<float>(const char *s, Parser &parser,
129 float *val) {
130 (void)parser;
131 *val = static_cast<float>(strtod(s, nullptr));
132 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800133}
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800134template<> inline CheckedError atot<double>(const char *s, Parser &parser,
135 double *val) {
136 (void)parser;
137 *val = strtod(s, nullptr);
138 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800139}
140
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800141template<> inline CheckedError atot<Offset<void>>(const char *s, Parser &parser,
142 Offset<void> *val) {
143 (void)parser;
144 *val = Offset<void>(atoi(s));
145 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800146}
147
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700148std::string Namespace::GetFullyQualifiedName(const std::string &name,
149 size_t max_components) const {
150 // Early exit if we don't have a defined namespace.
151 if (components.size() == 0 || !max_components) {
152 return name;
153 }
154 std::stringstream stream;
155 for (size_t i = 0; i < std::min(components.size(), max_components);
156 i++) {
157 if (i) {
158 stream << ".";
159 }
160 stream << components[i];
161 }
Wouter van Oortmerssen8c1a7232017-01-09 15:54:31 -0800162 if (name.length()) stream << "." << name;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700163 return stream.str();
164}
165
166
167
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800168// Declare tokens we'll use. Single character tokens are represented by their
169// ascii character code (e.g. '{'), others above 256.
170#define FLATBUFFERS_GEN_TOKENS(TD) \
171 TD(Eof, 256, "end of file") \
172 TD(StringConstant, 257, "string constant") \
173 TD(IntegerConstant, 258, "integer constant") \
174 TD(FloatConstant, 259, "float constant") \
175 TD(Identifier, 260, "identifier") \
176 TD(Table, 261, "table") \
177 TD(Struct, 262, "struct") \
178 TD(Enum, 263, "enum") \
179 TD(Union, 264, "union") \
180 TD(NameSpace, 265, "namespace") \
Wouter van Oortmerssen5da7bda2014-07-31 15:11:03 -0700181 TD(RootType, 266, "root_type") \
182 TD(FileIdentifier, 267, "file_identifier") \
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -0700183 TD(FileExtension, 268, "file_extension") \
Wouter van Oortmerssen09521432014-11-17 17:27:26 -0800184 TD(Include, 269, "include") \
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800185 TD(Attribute, 270, "attribute") \
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -0800186 TD(Null, 271, "null") \
Wouter van Oortmerssen3f936c52017-01-18 16:23:35 -0800187 TD(Service, 272, "rpc_service") \
188 TD(NativeInclude, 273, "native_include")
Wouter van Oortmerssen8f80fec2014-07-29 10:29:38 -0700189#ifdef __GNUC__
190__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
191#endif
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800192enum {
Wouter van Oortmerssen75349ae2014-07-09 11:44:26 -0700193 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800194 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
195 #undef FLATBUFFERS_TOKEN
rw48dfc692014-12-16 00:32:11 -0800196 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen557c88c2014-09-16 17:37:17 -0700197 kToken ## ENUM,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800198 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
199 #undef FLATBUFFERS_TD
200};
201
202static std::string TokenToString(int t) {
203 static const char *tokens[] = {
204 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
205 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
206 #undef FLATBUFFERS_TOKEN
rw48dfc692014-12-16 00:32:11 -0800207 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
208 IDLTYPE,
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800209 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
210 #undef FLATBUFFERS_TD
211 };
212 if (t < 256) { // A single ascii char token.
213 std::string s;
Wouter van Oortmerssen8e409022014-09-02 17:32:12 -0700214 s.append(1, static_cast<char>(t));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800215 return s;
216 } else { // Other tokens.
217 return tokens[t - 256];
218 }
219}
220
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700221std::string Parser::TokenToStringId(int t) {
222 return TokenToString(t) + (t == kTokenIdentifier ? ": " + attribute_ : "");
223}
224
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700225// Parses exactly nibbles worth of hex digits into a number, or error.
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800226CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) {
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700227 for (int i = 0; i < nibbles; i++)
Chris Pickett30013b42016-01-05 13:38:03 -0600228 if (!isxdigit(static_cast<const unsigned char>(cursor_[i])))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800229 return Error("escape code must be followed by " + NumToString(nibbles) +
230 " hex digits");
Hiroshi Matsunaga7cf74cb2015-01-09 03:38:14 +0900231 std::string target(cursor_, cursor_ + nibbles);
Sahil Jainb6ba3222016-08-25 23:37:30 -0400232 *val = StringToUInt(target.c_str(), nullptr, 16);
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700233 cursor_ += nibbles;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800234 return NoError();
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700235}
236
Oli Wilkinsoncbe87472016-01-18 18:58:53 +0000237CheckedError Parser::SkipByteOrderMark() {
238 if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError();
239 cursor_++;
Wouter van Oortmerssenf6330ab2016-04-22 11:26:47 -0700240 if (static_cast<unsigned char>(*cursor_) != 0xbb) return Error("invalid utf-8 byte order mark");
241 cursor_++;
242 if (static_cast<unsigned char>(*cursor_) != 0xbf) return Error("invalid utf-8 byte order mark");
243 cursor_++;
Oli Wilkinsoncbe87472016-01-18 18:58:53 +0000244 return NoError();
245}
246
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -0800247bool IsIdentifierStart(char c) {
248 return isalpha(static_cast<unsigned char>(c)) || c == '_';
249}
250
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800251CheckedError Parser::Next() {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800252 doc_comment_.clear();
253 bool seen_newline = false;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700254 attribute_.clear();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800255 for (;;) {
256 char c = *cursor_++;
257 token_ = c;
258 switch (c) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800259 case '\0': cursor_--; token_ = kTokenEof; return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800260 case ' ': case '\r': case '\t': break;
261 case '\n': line_++; seen_newline = true; break;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800262 case '{': case '}': case '(': case ')': case '[': case ']':
263 case ',': case ':': case ';': case '=': return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800264 case '.':
Chris Pickett30013b42016-01-05 13:38:03 -0600265 if(!isdigit(static_cast<const unsigned char>(*cursor_))) return NoError();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800266 return Error("floating point constant can\'t start with \".\"");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800267 case '\"':
Ben Gertzfield6704b192016-04-28 12:27:38 -0700268 case '\'': {
269 int unicode_high_surrogate = -1;
270
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700271 while (*cursor_ != c) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800272 if (*cursor_ < ' ' && *cursor_ >= 0)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800273 return Error("illegal character in string constant");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800274 if (*cursor_ == '\\') {
275 cursor_++;
Ben Gertzfield6704b192016-04-28 12:27:38 -0700276 if (unicode_high_surrogate != -1 &&
277 *cursor_ != 'u') {
278 return Error(
279 "illegal Unicode sequence (unpaired high surrogate)");
280 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800281 switch (*cursor_) {
282 case 'n': attribute_ += '\n'; cursor_++; break;
283 case 't': attribute_ += '\t'; cursor_++; break;
284 case 'r': attribute_ += '\r'; cursor_++; break;
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700285 case 'b': attribute_ += '\b'; cursor_++; break;
286 case 'f': attribute_ += '\f'; cursor_++; break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800287 case '\"': attribute_ += '\"'; cursor_++; break;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700288 case '\'': attribute_ += '\''; cursor_++; break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800289 case '\\': attribute_ += '\\'; cursor_++; break;
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700290 case '/': attribute_ += '/'; cursor_++; break;
291 case 'x': { // Not in the JSON standard
292 cursor_++;
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800293 uint64_t val;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800294 ECHECK(ParseHexNum(2, &val));
295 attribute_ += static_cast<char>(val);
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700296 break;
297 }
298 case 'u': {
299 cursor_++;
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800300 uint64_t val;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800301 ECHECK(ParseHexNum(4, &val));
Ben Gertzfield6704b192016-04-28 12:27:38 -0700302 if (val >= 0xD800 && val <= 0xDBFF) {
303 if (unicode_high_surrogate != -1) {
304 return Error(
305 "illegal Unicode sequence (multiple high surrogates)");
306 } else {
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -0700307 unicode_high_surrogate = static_cast<int>(val);
Ben Gertzfield6704b192016-04-28 12:27:38 -0700308 }
309 } else if (val >= 0xDC00 && val <= 0xDFFF) {
310 if (unicode_high_surrogate == -1) {
311 return Error(
312 "illegal Unicode sequence (unpaired low surrogate)");
313 } else {
314 int code_point = 0x10000 +
315 ((unicode_high_surrogate & 0x03FF) << 10) +
316 (val & 0x03FF);
317 ToUTF8(code_point, &attribute_);
318 unicode_high_surrogate = -1;
319 }
320 } else {
321 if (unicode_high_surrogate != -1) {
322 return Error(
323 "illegal Unicode sequence (unpaired high surrogate)");
324 }
325 ToUTF8(static_cast<int>(val), &attribute_);
326 }
Wouter van Oortmerssenebac1e12014-08-20 13:22:16 -0700327 break;
328 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800329 default: return Error("unknown escape code in string constant");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800330 }
331 } else { // printable chars + UTF-8 bytes
Ben Gertzfield6704b192016-04-28 12:27:38 -0700332 if (unicode_high_surrogate != -1) {
333 return Error(
334 "illegal Unicode sequence (unpaired high surrogate)");
335 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800336 attribute_ += *cursor_++;
337 }
338 }
Ben Gertzfield6704b192016-04-28 12:27:38 -0700339 if (unicode_high_surrogate != -1) {
340 return Error(
341 "illegal Unicode sequence (unpaired high surrogate)");
342 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800343 cursor_++;
Ben Hamiltonf6416d82016-08-01 14:04:51 -0700344 if (!opts.allow_non_utf8 && !ValidateUTF8(attribute_)) {
345 return Error("illegal UTF-8 sequence");
346 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800347 token_ = kTokenStringConstant;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800348 return NoError();
Ben Gertzfield6704b192016-04-28 12:27:38 -0700349 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800350 case '/':
351 if (*cursor_ == '/') {
352 const char *start = ++cursor_;
Mormegila8d69622015-04-14 18:09:08 +0200353 while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800354 if (*start == '/') { // documentation comment
Zbigniew Mandziejewicz07d59652014-10-22 22:40:03 +0800355 if (cursor_ != source_ && !seen_newline)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800356 return Error(
357 "a documentation comment should be on a line on its own");
Gabriel Martinez730c0ca2014-09-24 11:46:32 -0700358 doc_comment_.push_back(std::string(start + 1, cursor_));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800359 }
360 break;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700361 } else if (*cursor_ == '*') {
362 cursor_++;
363 // TODO: make nested.
364 while (*cursor_ != '*' || cursor_[1] != '/') {
Wouter van Oortmerssenab51b032016-10-07 17:07:39 -0700365 if (*cursor_ == '\n') line_++;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800366 if (!*cursor_) return Error("end of file in comment");
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700367 cursor_++;
368 }
369 cursor_ += 2;
370 break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800371 }
372 // fall thru
373 default:
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -0800374 if (IsIdentifierStart(c)) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800375 // Collect all chars of an identifier:
376 const char *start = cursor_ - 1;
377 while (isalnum(static_cast<unsigned char>(*cursor_)) ||
378 *cursor_ == '_')
379 cursor_++;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800380 attribute_.append(start, cursor_);
381 // First, see if it is a type keyword from the table of types:
rw48dfc692014-12-16 00:32:11 -0800382 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
383 PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800384 if (attribute_ == IDLTYPE) { \
385 token_ = kToken ## ENUM; \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800386 return NoError(); \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800387 }
388 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
389 #undef FLATBUFFERS_TD
390 // If it's a boolean constant keyword, turn those into integers,
391 // which simplifies our logic downstream.
392 if (attribute_ == "true" || attribute_ == "false") {
393 attribute_ = NumToString(attribute_ == "true");
394 token_ = kTokenIntegerConstant;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800395 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800396 }
397 // Check for declaration keywords:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800398 if (attribute_ == "table") {
399 token_ = kTokenTable;
400 return NoError();
401 }
402 if (attribute_ == "struct") {
403 token_ = kTokenStruct;
404 return NoError();
405 }
406 if (attribute_ == "enum") {
407 token_ = kTokenEnum;
408 return NoError();
409 }
410 if (attribute_ == "union") {
411 token_ = kTokenUnion;
412 return NoError();
413 }
414 if (attribute_ == "namespace") {
415 token_ = kTokenNameSpace;
416 return NoError();
417 }
418 if (attribute_ == "root_type") {
419 token_ = kTokenRootType;
420 return NoError();
421 }
422 if (attribute_ == "include") {
423 token_ = kTokenInclude;
424 return NoError();
425 }
426 if (attribute_ == "attribute") {
427 token_ = kTokenAttribute;
428 return NoError();
429 }
Wouter van Oortmerssen5da7bda2014-07-31 15:11:03 -0700430 if (attribute_ == "file_identifier") {
431 token_ = kTokenFileIdentifier;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800432 return NoError();
Wouter van Oortmerssen5da7bda2014-07-31 15:11:03 -0700433 }
434 if (attribute_ == "file_extension") {
435 token_ = kTokenFileExtension;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800436 return NoError();
Wouter van Oortmerssen5da7bda2014-07-31 15:11:03 -0700437 }
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800438 if (attribute_ == "null") {
439 token_ = kTokenNull;
440 return NoError();
441 }
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -0800442 if (attribute_ == "rpc_service") {
443 token_ = kTokenService;
444 return NoError();
445 }
Wouter van Oortmerssen3f936c52017-01-18 16:23:35 -0800446 if (attribute_ == "native_include") {
447 token_ = kTokenNativeInclude;
448 return NoError();
449 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800450 // If not, it is a user-defined identifier:
451 token_ = kTokenIdentifier;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800452 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800453 } else if (isdigit(static_cast<unsigned char>(c)) || c == '-') {
454 const char *start = cursor_ - 1;
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800455 if (c == '-' && *cursor_ == '0' &&
456 (cursor_[1] == 'x' || cursor_[1] == 'X')) {
Ramanf6f88e52016-07-12 19:47:53 +0200457 ++start;
458 ++cursor_;
459 attribute_.append(&c, &c + 1);
460 c = '0';
461 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700462 if (c == '0' && (*cursor_ == 'x' || *cursor_ == 'X')) {
463 cursor_++;
464 while (isxdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
465 attribute_.append(start + 2, cursor_);
Wouter van Oortmerssen29574282017-01-30 17:07:55 -0800466 attribute_ = NumToString(static_cast<int64_t>(
467 StringToUInt(attribute_.c_str(), nullptr, 16)));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700468 token_ = kTokenIntegerConstant;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800469 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700470 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800471 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700472 if (*cursor_ == '.' || *cursor_ == 'e' || *cursor_ == 'E') {
473 if (*cursor_ == '.') {
474 cursor_++;
475 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
476 }
Wouter van Oortmerssen93df5692014-07-10 13:40:55 -0700477 // See if this float has a scientific notation suffix. Both JSON
478 // and C++ (through strtod() we use) have the same format:
479 if (*cursor_ == 'e' || *cursor_ == 'E') {
480 cursor_++;
481 if (*cursor_ == '+' || *cursor_ == '-') cursor_++;
482 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
483 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800484 token_ = kTokenFloatConstant;
485 } else {
486 token_ = kTokenIntegerConstant;
487 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800488 attribute_.append(start, cursor_);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800489 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800490 }
491 std::string ch;
492 ch = c;
493 if (c < ' ' || c > '~') ch = "code: " + NumToString(c);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800494 return Error("illegal character: " + ch);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800495 }
496 }
497}
498
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800499// Check if a given token is next.
500bool Parser::Is(int t) {
501 return t == token_;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800502}
503
504// Expect a given token to be next, consume it, or error if not present.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800505CheckedError Parser::Expect(int t) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800506 if (t != token_) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800507 return Error("expecting: " + TokenToString(t) + " instead got: " +
508 TokenToStringId(token_));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800509 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800510 NEXT();
511 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800512}
513
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800514CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) {
515 while (Is('.')) {
516 NEXT();
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700517 *id += ".";
518 *id += attribute_;
519 if (last) *last = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800520 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700521 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800522 return NoError();
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700523}
524
525EnumDef *Parser::LookupEnum(const std::string &id) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700526 // Search thru parent namespaces.
527 for (int components = static_cast<int>(namespaces_.back()->components.size());
528 components >= 0; components--) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800529 auto ed = enums_.Lookup(
530 namespaces_.back()->GetFullyQualifiedName(id, components));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -0700531 if (ed) return ed;
532 }
533 return nullptr;
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700534}
535
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800536CheckedError Parser::ParseTypeIdent(Type &type) {
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700537 std::string id = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800538 EXPECT(kTokenIdentifier);
539 ECHECK(ParseNamespacing(&id, nullptr));
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700540 auto enum_def = LookupEnum(id);
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700541 if (enum_def) {
542 type = enum_def->underlying_type;
543 if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
544 } else {
545 type.base_type = BASE_TYPE_STRUCT;
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -0700546 type.struct_def = LookupCreateStruct(id);
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700547 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800548 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700549}
550
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800551// Parse any IDL type.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800552CheckedError Parser::ParseType(Type &type) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800553 if (token_ >= kTokenBOOL && token_ <= kTokenSTRING) {
554 type.base_type = static_cast<BaseType>(token_ - kTokenNONE);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800555 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800556 } else {
557 if (token_ == kTokenIdentifier) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800558 ECHECK(ParseTypeIdent(type));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800559 } else if (token_ == '[') {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800560 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800561 Type subtype;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800562 ECHECK(ParseType(subtype));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800563 if (subtype.base_type == BASE_TYPE_VECTOR) {
564 // We could support this, but it will complicate things, and it's
565 // easier to work around with a struct around the inner vector.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800566 return Error(
567 "nested vector types not supported (wrap in table first).");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800568 }
Wouter van Oortmerssen3fb6a862014-07-14 17:49:04 -0700569 type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800570 type.element = subtype.base_type;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800571 EXPECT(']');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800572 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800573 return Error("illegal type syntax");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800574 }
575 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800576 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800577}
578
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800579CheckedError Parser::AddField(StructDef &struct_def, const std::string &name,
580 const Type &type, FieldDef **dest) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800581 auto &field = *new FieldDef();
582 field.value.offset =
583 FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size()));
584 field.name = name;
Gabriel Martinezdf4909e2014-11-04 10:00:56 -0800585 field.file = struct_def.file;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800586 field.value.type = type;
587 if (struct_def.fixed) { // statically compute the field offset
588 auto size = InlineSize(type);
589 auto alignment = InlineAlignment(type);
590 // structs_ need to have a predictable format, so we need to align to
591 // the largest scalar
592 struct_def.minalign = std::max(struct_def.minalign, alignment);
593 struct_def.PadLastField(alignment);
Wouter van Oortmerssen12563072014-06-30 15:56:31 -0700594 field.value.offset = static_cast<voffset_t>(struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800595 struct_def.bytesize += size;
596 }
597 if (struct_def.fields.Add(name, &field))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800598 return Error("field already exists: " + name);
599 *dest = &field;
600 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800601}
602
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800603CheckedError Parser::ParseField(StructDef &struct_def) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800604 std::string name = attribute_;
Wouter van Oortmerssene9f1f4d2017-06-02 15:55:02 -0700605
606 if (name == struct_def.name)
607 return Error("field name can not be the same as table/struct name");
608
Gabriel Martinez730c0ca2014-09-24 11:46:32 -0700609 std::vector<std::string> dc = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800610 EXPECT(kTokenIdentifier);
611 EXPECT(':');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800612 Type type;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800613 ECHECK(ParseType(type));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800614
615 if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800616 return Error("structs_ may contain only scalar or struct fields");
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800617
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700618 FieldDef *typefield = nullptr;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800619 if (type.base_type == BASE_TYPE_UNION) {
620 // For union fields, add a second auto-generated field to hold the type,
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700621 // with a special suffix.
622 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
623 type.enum_def->underlying_type, &typefield));
Bei Li68bbe982017-01-24 11:52:36 -0800624 } else if (type.base_type == BASE_TYPE_VECTOR &&
625 type.element == BASE_TYPE_UNION) {
626 // Only cpp supports the union vector feature so far.
627 if (opts.lang_to_generate != IDLOptions::kCpp) {
628 return Error("Vectors of unions are not yet supported in all "
629 "the specified programming languages.");
630 }
631 // For vector of union fields, add a second auto-generated vector field to
632 // hold the types, with a special suffix.
633 Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def);
634 union_vector.element = BASE_TYPE_UTYPE;
635 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
636 union_vector, &typefield));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800637 }
638
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800639 FieldDef *field;
640 ECHECK(AddField(struct_def, name, type, &field));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800641
642 if (token_ == '=') {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800643 NEXT();
Wouter van Oortmerssen15dc1a82014-09-03 12:23:15 -0700644 if (!IsScalar(type.base_type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800645 return Error("default values currently only supported for scalars");
646 ECHECK(ParseSingleValue(field->value));
Wouter van Oortmerssenfd542c72016-04-20 12:05:21 -0700647 }
648 if (IsFloat(field->value.type.base_type)) {
649 if (!strpbrk(field->value.constant.c_str(), ".eE"))
650 field->value.constant += ".0";
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800651 }
652
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -0700653 if (type.enum_def &&
654 IsScalar(type.base_type) &&
655 !struct_def.fixed &&
656 !type.enum_def->attributes.Lookup("bit_flags") &&
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -0700657 !type.enum_def->ReverseLookup(static_cast<int>(
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800658 StringToInt(field->value.constant.c_str()))))
659 return Error("enum " + type.enum_def->name +
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -0700660 " does not have a declaration for this field\'s default of " +
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800661 field->value.constant);
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -0700662
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800663 field->doc_comment = dc;
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -0800664 ECHECK(ParseMetaData(&field->attributes));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800665 field->deprecated = field->attributes.Lookup("deprecated") != nullptr;
666 auto hash_name = field->attributes.Lookup("hash");
Alex Amesd5753212015-02-13 15:58:29 -0800667 if (hash_name) {
668 switch (type.base_type) {
669 case BASE_TYPE_INT:
670 case BASE_TYPE_UINT: {
671 if (FindHashFunction32(hash_name->constant.c_str()) == nullptr)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800672 return Error("Unknown hashing algorithm for 32 bit types: " +
Alex Amesd5753212015-02-13 15:58:29 -0800673 hash_name->constant);
674 break;
675 }
676 case BASE_TYPE_LONG:
677 case BASE_TYPE_ULONG: {
678 if (FindHashFunction64(hash_name->constant.c_str()) == nullptr)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800679 return Error("Unknown hashing algorithm for 64 bit types: " +
Alex Amesd5753212015-02-13 15:58:29 -0800680 hash_name->constant);
681 break;
682 }
683 default:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800684 return Error(
685 "only int, uint, long and ulong data types support hashing.");
Alex Amesd5753212015-02-13 15:58:29 -0800686 }
687 }
Wouter van Oortmerssendc2fa212016-10-05 16:59:15 -0700688 auto cpp_type = field->attributes.Lookup("cpp_type");
689 if (cpp_type) {
690 if (!hash_name)
691 return Error("cpp_type can only be used with a hashed field");
692 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800693 if (field->deprecated && struct_def.fixed)
694 return Error("can't deprecate fields in a struct");
695 field->required = field->attributes.Lookup("required") != nullptr;
696 if (field->required && (struct_def.fixed ||
697 IsScalar(field->value.type.base_type)))
698 return Error("only non-scalar fields in tables may be 'required'");
699 field->key = field->attributes.Lookup("key") != nullptr;
700 if (field->key) {
Wouter van Oortmerssen35508992015-01-07 17:51:31 -0800701 if (struct_def.has_key)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800702 return Error("only one field may be set as 'key'");
Wouter van Oortmerssen35508992015-01-07 17:51:31 -0800703 struct_def.has_key = true;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800704 if (!IsScalar(field->value.type.base_type)) {
705 field->required = true;
706 if (field->value.type.base_type != BASE_TYPE_STRING)
707 return Error("'key' field must be string or scalar type");
Wouter van Oortmerssen35508992015-01-07 17:51:31 -0800708 }
709 }
Wouter van Oortmerssen641b3972016-12-02 14:25:08 -0800710
711 field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
712 if (field->native_inline && !IsStruct(field->value.type))
713 return Error("native_inline can only be defined on structs'");
714
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800715 auto nested = field->attributes.Lookup("nested_flatbuffer");
Wouter van Oortmerssen3e201a92014-07-15 17:50:22 -0700716 if (nested) {
717 if (nested->type.base_type != BASE_TYPE_STRING)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800718 return Error(
719 "nested_flatbuffer attribute must be a string (the root type)");
720 if (field->value.type.base_type != BASE_TYPE_VECTOR ||
721 field->value.type.element != BASE_TYPE_UCHAR)
722 return Error(
723 "nested_flatbuffer attribute may only apply to a vector of ubyte");
Wouter van Oortmerssen3e201a92014-07-15 17:50:22 -0700724 // This will cause an error if the root type of the nested flatbuffer
725 // wasn't defined elsewhere.
726 LookupCreateStruct(nested->constant);
Christian Helmich89a68942017-07-29 02:27:51 +0900727
728 // Keep a pointer to StructDef in FieldDef to simplify re-use later
729 auto nested_qualified_name = namespaces_.back()->GetFullyQualifiedName(nested->constant);
730 field->nested_flatbuffer = structs_.Lookup(nested_qualified_name);
Wouter van Oortmerssen3e201a92014-07-15 17:50:22 -0700731 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800732
Wouter van Oortmerssendddd0862017-06-02 16:41:22 -0700733 if (field->attributes.Lookup("flexbuffer")) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700734 field->flexbuffer = true;
Wouter van Oortmerssendddd0862017-06-02 16:41:22 -0700735 uses_flexbuffers_ = true;
736 if (field->value.type.base_type != BASE_TYPE_VECTOR ||
737 field->value.type.element != BASE_TYPE_UCHAR)
738 return Error(
739 "flexbuffer attribute may only apply to a vector of ubyte");
740 }
741
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700742 if (typefield) {
743 // If this field is a union, and it has a manually assigned id,
744 // the automatically added type field should have an id as well (of N - 1).
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800745 auto attr = field->attributes.Lookup("id");
Wouter van Oortmerssen91401442014-07-07 17:34:23 -0700746 if (attr) {
747 auto id = atoi(attr->constant.c_str());
748 auto val = new Value();
749 val->type = attr->type;
750 val->constant = NumToString(id - 1);
751 typefield->attributes.Add("id", val);
752 }
753 }
754
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800755 EXPECT(';');
756 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800757}
758
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -0700759CheckedError Parser::ParseString(Value &val) {
760 auto s = attribute_;
761 EXPECT(kTokenStringConstant);
762 val.constant = NumToString(builder_.CreateString(s).o);
763 return NoError();
764}
765
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -0700766CheckedError Parser::ParseComma() {
767 if (!opts.protobuf_ascii_alike) EXPECT(',');
768 return NoError();
769}
770
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800771CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700772 size_t parent_fieldn,
773 const StructDef *parent_struct_def) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800774 switch (val.type.base_type) {
775 case BASE_TYPE_UNION: {
776 assert(field);
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700777 std::string constant;
Wouter van Oortmersseneac29052017-01-18 12:02:31 -0800778 // Find corresponding type field we may have already parsed.
779 for (auto elem = field_stack_.rbegin();
780 elem != field_stack_.rbegin() + parent_fieldn; ++elem) {
781 auto &type = elem->second->value.type;
782 if (type.base_type == BASE_TYPE_UTYPE &&
783 type.enum_def == val.type.enum_def) {
784 constant = elem->first.constant;
785 break;
786 }
787 }
788 if (constant.empty()) {
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700789 // We haven't seen the type field yet. Sadly a lot of JSON writers
790 // output these in alphabetical order, meaning it comes after this
791 // value. So we scan past the value to find it, then come back here.
792 auto type_name = field->name + UnionTypeFieldSuffix();
793 assert(parent_struct_def);
794 auto type_field = parent_struct_def->fields.Lookup(type_name);
795 assert(type_field); // Guaranteed by ParseField().
796 // Remember where we are in the source file, so we can come back here.
797 auto backup = *static_cast<ParserState *>(this);
798 ECHECK(SkipAnyJsonValue()); // The table.
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -0700799 ECHECK(ParseComma());
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700800 auto next_name = attribute_;
801 if (Is(kTokenStringConstant)) {
802 NEXT();
803 } else {
804 EXPECT(kTokenIdentifier);
805 }
806 if (next_name != type_name)
807 return Error("missing type field after this union value: " +
808 type_name);
809 EXPECT(':');
810 Value type_val = type_field->value;
811 ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr));
812 constant = type_val.constant;
813 // Got the information we needed, now rewind:
814 *static_cast<ParserState *>(this) = backup;
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700815 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800816 uint8_t enum_idx;
Wouter van Oortmerssen9e6c5f92016-06-20 16:06:30 -0700817 ECHECK(atot(constant.c_str(), *this, &enum_idx));
Wouter van Oortmerssen3fb6a862014-07-14 17:49:04 -0700818 auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800819 if (!enum_val) return Error("illegal type id for: " + field->name);
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -0700820 if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
821 ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
822 nullptr));
823 if (enum_val->union_type.struct_def->fixed) {
824 // All BASE_TYPE_UNION values are offsets, so turn this into one.
825 SerializeStruct(*enum_val->union_type.struct_def, val);
826 builder_.ClearOffsets();
827 val.constant = NumToString(builder_.GetSize());
828 }
829 } else if (enum_val->union_type.base_type == BASE_TYPE_STRING) {
830 ECHECK(ParseString(val));
831 } else {
832 assert(false);
833 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800834 break;
835 }
836 case BASE_TYPE_STRUCT:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800837 ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800838 break;
839 case BASE_TYPE_STRING: {
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -0700840 ECHECK(ParseString(val));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800841 break;
842 }
843 case BASE_TYPE_VECTOR: {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800844 uoffset_t off;
845 ECHECK(ParseVector(val.type.VectorType(), &off));
846 val.constant = NumToString(off);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800847 break;
848 }
Alex Amesd5753212015-02-13 15:58:29 -0800849 case BASE_TYPE_INT:
850 case BASE_TYPE_UINT:
851 case BASE_TYPE_LONG:
852 case BASE_TYPE_ULONG: {
853 if (field && field->attributes.Lookup("hash") &&
854 (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800855 ECHECK(ParseHash(val, field));
Alex Amesd5753212015-02-13 15:58:29 -0800856 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800857 ECHECK(ParseSingleValue(val));
Alex Amesd5753212015-02-13 15:58:29 -0800858 }
859 break;
860 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800861 default:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800862 ECHECK(ParseSingleValue(val));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800863 break;
864 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800865 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800866}
867
868void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700869 assert(val.constant.length() == struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800870 builder_.Align(struct_def.minalign);
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700871 builder_.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()),
872 struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -0800873 builder_.AddStructOffset(val.offset, builder_.GetSize());
874}
875
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700876CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
877 const StructDef *struct_def,
Stewart Milesa8923222017-07-13 06:27:39 -0700878 ParseTableDelimitersBody body,
879 void *state) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700880 // We allow tables both as JSON object{ .. } with field names
Guillaume Giraudb1740682017-06-08 01:58:19 +0200881 // or vector[..] with all fields in order
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700882 char terminator = '}';
883 bool is_nested_vector = struct_def && Is('[');
884 if (is_nested_vector) {
Guillaume Giraudb1740682017-06-08 01:58:19 +0200885 NEXT();
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700886 terminator = ']';
Guillaume Giraudb1740682017-06-08 01:58:19 +0200887 } else {
888 EXPECT('{');
889 }
Wouter van Oortmerssen6c2dc412015-01-16 16:57:04 -0800890 for (;;) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700891 if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
Guillaume Giraudb1740682017-06-08 01:58:19 +0200892 std::string name;
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700893 if (is_nested_vector) {
894 if (fieldn > struct_def->fields.vec.size()) {
Guillaume Giraudb1740682017-06-08 01:58:19 +0200895 return Error("too many unnamed fields in nested array");
896 }
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700897 name = struct_def->fields.vec[fieldn]->name;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800898 } else {
Guillaume Giraudb1740682017-06-08 01:58:19 +0200899 name = attribute_;
900 if (Is(kTokenStringConstant)) {
901 NEXT();
902 } else {
903 EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
904 }
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -0700905 if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800906 }
Stewart Milesa8923222017-07-13 06:27:39 -0700907 ECHECK(body(name, fieldn, struct_def, state));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700908 if (Is(terminator)) break;
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -0700909 ECHECK(ParseComma());
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700910 }
911 NEXT();
912 if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
913 return Error("wrong number of unnamed fields in table vector");
914 }
915 return NoError();
916}
917
918CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
919 uoffset_t *ovalue) {
Stewart Milesa8923222017-07-13 06:27:39 -0700920 size_t fieldn_outer = 0;
921 auto err = ParseTableDelimiters(fieldn_outer, &struct_def,
922 [](const std::string &name, size_t &fieldn,
923 const StructDef *struct_def_inner,
924 void *state) -> CheckedError {
925 Parser *parser = static_cast<Parser *>(state);
schoetbi2e2063c2017-07-19 17:58:48 +0200926 if (name == "$schema") {
Stewart Milesa8923222017-07-13 06:27:39 -0700927 ECHECK(parser->Expect(kTokenStringConstant));
schoetbi2e2063c2017-07-19 17:58:48 +0200928 return NoError();
929 }
Stewart Milesa8923222017-07-13 06:27:39 -0700930 auto field = struct_def_inner->fields.Lookup(name);
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800931 if (!field) {
Stewart Milesa8923222017-07-13 06:27:39 -0700932 if (!parser->opts.skip_unexpected_fields_in_json) {
933 return parser->Error("unknown field: " + name);
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800934 } else {
Stewart Milesa8923222017-07-13 06:27:39 -0700935 ECHECK(parser->SkipAnyJsonValue());
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800936 }
937 } else {
Stewart Milesa8923222017-07-13 06:27:39 -0700938 if (parser->Is(kTokenNull)) {
939 ECHECK(parser->Next()); // Ignore this field.
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800940 } else {
941 Value val = field->value;
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700942 if (field->flexbuffer) {
943 flexbuffers::Builder builder(1024,
944 flexbuffers::BUILDER_FLAG_SHARE_ALL);
Stewart Milesa8923222017-07-13 06:27:39 -0700945 ECHECK(parser->ParseFlexBufferValue(&builder));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700946 builder.Finish();
Stewart Milesa8923222017-07-13 06:27:39 -0700947 auto off = parser->builder_.CreateVector(builder.GetBuffer());
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700948 val.constant = NumToString(off.o);
Christian Helmich89a68942017-07-29 02:27:51 +0900949 } else if (field->nested_flatbuffer) {
950 ECHECK(parser->ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700951 } else {
Stewart Milesa8923222017-07-13 06:27:39 -0700952 ECHECK(parser->ParseAnyValue(val, field, fieldn, struct_def_inner));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700953 }
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800954 // Hardcoded insertion-sort with error-check.
955 // If fields are specified in order, then this loop exits immediately.
Stewart Milesa8923222017-07-13 06:27:39 -0700956 auto elem = parser->field_stack_.rbegin();
957 for (; elem != parser->field_stack_.rbegin() + fieldn; ++elem) {
Wouter van Oortmersseneac29052017-01-18 12:02:31 -0800958 auto existing_field = elem->second;
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800959 if (existing_field == field)
Stewart Milesa8923222017-07-13 06:27:39 -0700960 return parser->Error("field set more than once: " + field->name);
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800961 if (existing_field->value.offset < field->value.offset) break;
962 }
Wouter van Oortmersseneac29052017-01-18 12:02:31 -0800963 // Note: elem points to before the insertion point, thus .base() points
964 // to the correct spot.
Stewart Milesa8923222017-07-13 06:27:39 -0700965 parser->field_stack_.insert(elem.base(),
966 std::make_pair(val, field));
Wouter van Oortmerssen049f3f72016-01-08 15:18:51 -0800967 fieldn++;
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800968 }
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700969 }
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700970 return NoError();
Stewart Milesa8923222017-07-13 06:27:39 -0700971 }, this);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -0700972 ECHECK(err);
Nalinichandra Penke13d05942015-12-22 00:02:19 -0800973
sfariv55dec4d2017-05-18 09:32:04 -0700974 // Check if all required fields are parsed.
975 for (auto field_it = struct_def.fields.vec.begin();
976 field_it != struct_def.fields.vec.end();
977 ++field_it) {
978 auto required_field = *field_it;
979 if (!required_field->required) {
980 continue;
981 }
982 bool found = false;
Stewart Milesa8923222017-07-13 06:27:39 -0700983 for (auto pf_it = field_stack_.end() - fieldn_outer;
sfariv55dec4d2017-05-18 09:32:04 -0700984 pf_it != field_stack_.end();
985 ++pf_it) {
986 auto parsed_field = pf_it->second;
987 if (parsed_field == required_field) {
988 found = true;
989 break;
990 }
991 }
992 if (!found) {
993 return Error("required field is missing: " + required_field->name + " in " + struct_def.name);
994 }
995 }
996
Stewart Milesa8923222017-07-13 06:27:39 -0700997 if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -0800998 return Error("struct: wrong number of initializers: " + struct_def.name);
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -0700999
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001000 auto start = struct_def.fixed
1001 ? builder_.StartStruct(struct_def.minalign)
1002 : builder_.StartTable();
1003
1004 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1005 size;
1006 size /= 2) {
1007 // Go through elements in reverse, since we're building the data backwards.
Stewart Milesa8923222017-07-13 06:27:39 -07001008 for (auto it = field_stack_.rbegin(); it != field_stack_.rbegin() +
1009 fieldn_outer;
1010 ++it) {
Shuhei Tanuma721d2192015-11-06 07:14:21 +09001011 auto &field_value = it->first;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001012 auto field = it->second;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001013 if (!struct_def.sortbysize ||
1014 size == SizeOf(field_value.type.base_type)) {
Shuhei Tanuma721d2192015-11-06 07:14:21 +09001015 switch (field_value.type.base_type) {
rw48dfc692014-12-16 00:32:11 -08001016 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
1017 PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001018 case BASE_TYPE_ ## ENUM: \
1019 builder_.Pad(field->padding); \
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -07001020 if (struct_def.fixed) { \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001021 CTYPE val; \
1022 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1023 builder_.PushElement(val); \
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -07001024 } else { \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001025 CTYPE val, valdef; \
1026 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1027 ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \
1028 builder_.AddElement(field_value.offset, val, valdef); \
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -07001029 } \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001030 break;
1031 FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
1032 #undef FLATBUFFERS_TD
rw48dfc692014-12-16 00:32:11 -08001033 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
1034 PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001035 case BASE_TYPE_ ## ENUM: \
1036 builder_.Pad(field->padding); \
1037 if (IsStruct(field->value.type)) { \
Shuhei Tanuma721d2192015-11-06 07:14:21 +09001038 SerializeStruct(*field->value.type.struct_def, field_value); \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001039 } else { \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001040 CTYPE val; \
1041 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1042 builder_.AddOffset(field_value.offset, val); \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001043 } \
1044 break;
1045 FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD);
1046 #undef FLATBUFFERS_TD
1047 }
1048 }
1049 }
1050 }
Stewart Milesa8923222017-07-13 06:27:39 -07001051 for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001052
1053 if (struct_def.fixed) {
1054 builder_.ClearOffsets();
1055 builder_.EndStruct();
Wouter van Oortmerssen4d781042015-09-28 15:02:41 -07001056 assert(value);
1057 // Temporarily store this struct in the value string, since it is to
1058 // be serialized in-place elsewhere.
1059 value->assign(
1060 reinterpret_cast<const char *>(builder_.GetCurrentBufferPointer()),
1061 struct_def.bytesize);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001062 builder_.PopBytes(struct_def.bytesize);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001063 assert(!ovalue);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001064 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001065 auto val = builder_.EndTable(start,
1066 static_cast<voffset_t>(struct_def.fields.vec.size()));
1067 if (ovalue) *ovalue = val;
1068 if (value) *value = NumToString(val);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001069 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001070 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001071}
1072
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001073CheckedError Parser::ParseVectorDelimiters(size_t &count,
Stewart Milesa8923222017-07-13 06:27:39 -07001074 ParseVectorDelimitersBody body,
1075 void *state) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001076 EXPECT('[');
Wouter van Oortmerssen6c2dc412015-01-16 16:57:04 -08001077 for (;;) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001078 if ((!opts.strict_json || !count) && Is(']')) break;
Stewart Milesa8923222017-07-13 06:27:39 -07001079 ECHECK(body(count, state));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001080 count++;
1081 if (Is(']')) break;
Wouter van Oortmerssenf325cce2017-06-16 11:57:58 -07001082 ECHECK(ParseComma());
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001083 }
1084 NEXT();
1085 return NoError();
1086}
1087
1088CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
1089 size_t count = 0;
Stewart Milesa8923222017-07-13 06:27:39 -07001090 std::pair<Parser *, const Type &> parser_and_type_state(this, type);
1091 auto err = ParseVectorDelimiters(count,
1092 [](size_t &, void *state) -> CheckedError {
1093 auto *parser_and_type =
1094 static_cast<std::pair<Parser *, const Type &> *>(state);
1095 auto *parser = parser_and_type->first;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001096 Value val;
Stewart Milesa8923222017-07-13 06:27:39 -07001097 val.type = parser_and_type->second;
1098 ECHECK(parser->ParseAnyValue(val, nullptr, 0, nullptr));
1099 parser->field_stack_.push_back(std::make_pair(val, nullptr));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001100 return NoError();
Stewart Milesa8923222017-07-13 06:27:39 -07001101 }, &parser_and_type_state);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001102 ECHECK(err);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001103
Wouter van Oortmerssenbe3c8742014-08-11 17:38:54 -07001104 builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
1105 InlineAlignment(type));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001106 for (size_t i = 0; i < count; i++) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001107 // start at the back, since we're building the data backwards.
1108 auto &val = field_stack_.back().first;
1109 switch (val.type.base_type) {
rw48dfc692014-12-16 00:32:11 -08001110 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001111 case BASE_TYPE_ ## ENUM: \
1112 if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001113 else { \
1114 CTYPE elem; \
1115 ECHECK(atot(val.constant.c_str(), *this, &elem)); \
1116 builder_.PushElement(elem); \
1117 } \
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001118 break;
1119 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1120 #undef FLATBUFFERS_TD
1121 }
1122 field_stack_.pop_back();
1123 }
1124
1125 builder_.ClearOffsets();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001126 *ovalue = builder_.EndVector(count);
1127 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001128}
1129
Christian Helmich89a68942017-07-29 02:27:51 +09001130CheckedError Parser::ParseNestedFlatbuffer(Value &val, FieldDef *field,
1131 size_t fieldn,
1132 const StructDef *parent_struct_def) {
1133 if (token_ == '[') {// backwards compat for 'legacy' ubyte buffers
1134 ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def));
1135 } else {
1136 auto cursor_at_value_begin = cursor_;
1137 ECHECK(SkipAnyJsonValue());
1138 std::string substring(cursor_at_value_begin -1 , cursor_ -1);
1139
1140 // Create and initialize new parser
1141 Parser nested_parser;
1142 assert(field->nested_flatbuffer);
1143 nested_parser.root_struct_def_ = field->nested_flatbuffer;
1144 nested_parser.enums_ = enums_;
1145 nested_parser.opts = opts;
1146 nested_parser.uses_flexbuffers_ = uses_flexbuffers_;
1147
1148 // Parse JSON substring into new flatbuffer builder using nested_parser
1149 if (!nested_parser.Parse(substring.c_str(), nullptr, nullptr)) {
1150 ECHECK(Error(nested_parser.error_));
1151 }
1152 auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(), nested_parser.builder_.GetSize());
1153 val.constant = NumToString(off.o);
1154
1155 // Clean nested_parser before destruction to avoid deleting the elements in the SymbolTables
1156 nested_parser.enums_.dict.clear();
1157 nested_parser.enums_.vec.clear();
1158 }
1159 return NoError();
1160}
1161
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001162CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001163 if (Is('(')) {
1164 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001165 for (;;) {
1166 auto name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001167 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen09521432014-11-17 17:27:26 -08001168 if (known_attributes_.find(name) == known_attributes_.end())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001169 return Error("user define attributes must be declared before use: " +
1170 name);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001171 auto e = new Value();
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001172 attributes->Add(name, e);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001173 if (Is(':')) {
1174 NEXT();
1175 ECHECK(ParseSingleValue(*e));
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001176 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001177 if (Is(')')) { NEXT(); break; }
1178 EXPECT(',');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001179 }
1180 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001181 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001182}
1183
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001184CheckedError Parser::TryTypedValue(int dtoken, bool check, Value &e,
1185 BaseType req, bool *destmatch) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001186 bool match = dtoken == token_;
1187 if (match) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001188 *destmatch = true;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001189 e.constant = attribute_;
1190 if (!check) {
1191 if (e.type.base_type == BASE_TYPE_NONE) {
1192 e.type.base_type = req;
1193 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001194 return Error(std::string("type mismatch: expecting: ") +
1195 kTypeNames[e.type.base_type] +
1196 ", found: " +
1197 kTypeNames[req]);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001198 }
1199 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001200 NEXT();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001201 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001202 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001203}
1204
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001205CheckedError Parser::ParseEnumFromString(Type &type, int64_t *result) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001206 *result = 0;
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001207 // Parse one or more enum identifiers, separated by spaces.
1208 const char *next = attribute_.c_str();
1209 do {
1210 const char *divider = strchr(next, ' ');
1211 std::string word;
1212 if (divider) {
1213 word = std::string(next, divider);
1214 next = divider + strspn(divider, " ");
1215 } else {
1216 word = next;
1217 next += word.length();
1218 }
1219 if (type.enum_def) { // The field has an enum type
1220 auto enum_val = type.enum_def->vals.Lookup(word);
1221 if (!enum_val)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001222 return Error("unknown enum value: " + word +
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001223 ", for enum: " + type.enum_def->name);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001224 *result |= enum_val->value;
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001225 } else { // No enum type, probably integral field.
1226 if (!IsInteger(type.base_type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001227 return Error("not a valid value for this field: " + word);
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001228 // TODO: could check if its a valid number constant here.
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -07001229 const char *dot = strrchr(word.c_str(), '.');
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001230 if (!dot)
1231 return Error("enum values need to be qualified by an enum type");
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001232 std::string enum_def_str(word.c_str(), dot);
1233 std::string enum_val_str(dot + 1, word.c_str() + word.length());
Wouter van Oortmerssen39833d72015-05-08 15:04:53 -07001234 auto enum_def = LookupEnum(enum_def_str);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001235 if (!enum_def) return Error("unknown enum: " + enum_def_str);
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001236 auto enum_val = enum_def->vals.Lookup(enum_val_str);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001237 if (!enum_val) return Error("unknown enum value: " + enum_val_str);
1238 *result |= enum_val->value;
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001239 }
1240 } while(*next);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001241 return NoError();
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001242}
1243
Alex Amesd5753212015-02-13 15:58:29 -08001244
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001245CheckedError Parser::ParseHash(Value &e, FieldDef* field) {
Alex Amesd5753212015-02-13 15:58:29 -08001246 assert(field);
1247 Value *hash_name = field->attributes.Lookup("hash");
1248 switch (e.type.base_type) {
Wouter van Oortmerssen46497e42017-04-17 17:40:02 -07001249 case BASE_TYPE_INT: {
1250 auto hash = FindHashFunction32(hash_name->constant.c_str());
1251 int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
1252 e.constant = NumToString(hashed_value);
1253 break;
1254 }
Alex Amesd5753212015-02-13 15:58:29 -08001255 case BASE_TYPE_UINT: {
1256 auto hash = FindHashFunction32(hash_name->constant.c_str());
1257 uint32_t hashed_value = hash(attribute_.c_str());
1258 e.constant = NumToString(hashed_value);
1259 break;
1260 }
Wouter van Oortmerssen46497e42017-04-17 17:40:02 -07001261 case BASE_TYPE_LONG: {
1262 auto hash = FindHashFunction64(hash_name->constant.c_str());
1263 int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
1264 e.constant = NumToString(hashed_value);
1265 break;
1266 }
Alex Amesd5753212015-02-13 15:58:29 -08001267 case BASE_TYPE_ULONG: {
1268 auto hash = FindHashFunction64(hash_name->constant.c_str());
1269 uint64_t hashed_value = hash(attribute_.c_str());
1270 e.constant = NumToString(hashed_value);
1271 break;
1272 }
1273 default:
1274 assert(0);
1275 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001276 NEXT();
1277 return NoError();
Alex Amesd5753212015-02-13 15:58:29 -08001278}
1279
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001280CheckedError Parser::TokenError() {
1281 return Error("cannot parse value starting with: " +
1282 TokenToStringId(token_));
1283}
1284
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001285CheckedError Parser::ParseSingleValue(Value &e) {
Wouter van Oortmerssend3ac0bc2016-06-15 13:54:17 -07001286 // First see if this could be a conversion function:
1287 if (token_ == kTokenIdentifier && *cursor_ == '(') {
1288 auto functionname = attribute_;
1289 NEXT();
1290 EXPECT('(');
1291 ECHECK(ParseSingleValue(e));
1292 EXPECT(')');
1293 #define FLATBUFFERS_FN_DOUBLE(name, op) \
1294 if (functionname == name) { \
1295 auto x = strtod(e.constant.c_str(), nullptr); \
1296 e.constant = NumToString(op); \
1297 }
1298 FLATBUFFERS_FN_DOUBLE("deg", x / M_PI * 180);
1299 FLATBUFFERS_FN_DOUBLE("rad", x * M_PI / 180);
1300 FLATBUFFERS_FN_DOUBLE("sin", sin(x));
1301 FLATBUFFERS_FN_DOUBLE("cos", cos(x));
1302 FLATBUFFERS_FN_DOUBLE("tan", tan(x));
1303 FLATBUFFERS_FN_DOUBLE("asin", asin(x));
1304 FLATBUFFERS_FN_DOUBLE("acos", acos(x));
1305 FLATBUFFERS_FN_DOUBLE("atan", atan(x));
1306 // TODO(wvo): add more useful conversion functions here.
1307 #undef FLATBUFFERS_FN_DOUBLE
1308 // Then check if this could be a string/identifier enum value:
1309 } else if (e.type.base_type != BASE_TYPE_STRING &&
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001310 e.type.base_type != BASE_TYPE_NONE &&
1311 (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001312 if (IsIdentifierStart(attribute_[0])) { // Enum value.
1313 int64_t val;
1314 ECHECK(ParseEnumFromString(e.type, &val));
1315 e.constant = NumToString(val);
1316 NEXT();
1317 } else { // Numeric constant in string.
1318 if (IsInteger(e.type.base_type)) {
Sahil Jainb6ba3222016-08-25 23:37:30 -04001319 char *end;
1320 e.constant = NumToString(StringToInt(attribute_.c_str(), &end));
1321 if (*end)
1322 return Error("invalid integer: " + attribute_);
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001323 } else if (IsFloat(e.type.base_type)) {
Sahil Jainb6ba3222016-08-25 23:37:30 -04001324 char *end;
1325 e.constant = NumToString(strtod(attribute_.c_str(), &end));
1326 if (*end)
1327 return Error("invalid float: " + attribute_);
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001328 } else {
1329 assert(0); // Shouldn't happen, we covered all types.
1330 e.constant = "0";
1331 }
Wouter van Oortmerssen83dc5ed2016-04-11 11:08:09 -07001332 NEXT();
Wouter van Oortmerssenfbc8af42016-03-07 17:22:51 -08001333 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001334 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001335 bool match = false;
1336 ECHECK(TryTypedValue(kTokenIntegerConstant,
1337 IsScalar(e.type.base_type),
1338 e,
1339 BASE_TYPE_INT,
1340 &match));
1341 ECHECK(TryTypedValue(kTokenFloatConstant,
1342 IsFloat(e.type.base_type),
1343 e,
1344 BASE_TYPE_FLOAT,
1345 &match));
1346 ECHECK(TryTypedValue(kTokenStringConstant,
1347 e.type.base_type == BASE_TYPE_STRING,
1348 e,
1349 BASE_TYPE_STRING,
1350 &match));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001351 if (!match) return TokenError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001352 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001353 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001354}
1355
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001356StructDef *Parser::LookupCreateStruct(const std::string &name,
1357 bool create_if_new, bool definition) {
1358 std::string qualified_name = namespaces_.back()->GetFullyQualifiedName(name);
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001359 // See if it exists pre-declared by an unqualified use.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001360 auto struct_def = structs_.Lookup(name);
1361 if (struct_def && struct_def->predecl) {
1362 if (definition) {
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001363 // Make sure it has the current namespace, and is registered under its
1364 // qualified name.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001365 struct_def->defined_namespace = namespaces_.back();
1366 structs_.Move(name, qualified_name);
1367 }
1368 return struct_def;
1369 }
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001370 // See if it exists pre-declared by an qualified use.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001371 struct_def = structs_.Lookup(qualified_name);
Wouter van Oortmerssen20c00822016-02-12 16:20:33 -08001372 if (struct_def && struct_def->predecl) {
1373 if (definition) {
1374 // Make sure it has the current namespace.
1375 struct_def->defined_namespace = namespaces_.back();
1376 }
1377 return struct_def;
1378 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001379 if (!definition) {
1380 // Search thru parent namespaces.
1381 for (size_t components = namespaces_.back()->components.size();
1382 components && !struct_def; components--) {
1383 struct_def = structs_.Lookup(
1384 namespaces_.back()->GetFullyQualifiedName(name, components - 1));
1385 }
1386 }
1387 if (!struct_def && create_if_new) {
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001388 struct_def = new StructDef();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001389 if (definition) {
1390 structs_.Add(qualified_name, struct_def);
1391 struct_def->name = name;
1392 struct_def->defined_namespace = namespaces_.back();
1393 } else {
1394 // Not a definition.
1395 // Rather than failing, we create a "pre declared" StructDef, due to
1396 // circular references, and check for errors at the end of parsing.
1397 // It is defined in the root namespace, since we don't know what the
1398 // final namespace will be.
1399 // TODO: maybe safer to use special namespace?
1400 structs_.Add(name, struct_def);
1401 struct_def->name = name;
1402 struct_def->defined_namespace = new Namespace();
1403 namespaces_.insert(namespaces_.begin(), struct_def->defined_namespace);
1404 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001405 }
1406 return struct_def;
1407}
1408
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001409CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
Max Galkinc3807fa2015-03-07 08:49:55 -08001410 std::vector<std::string> enum_comment = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001411 NEXT();
Max Galkinc3807fa2015-03-07 08:49:55 -08001412 std::string enum_name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001413 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001414 auto &enum_def = *new EnumDef();
Max Galkinc3807fa2015-03-07 08:49:55 -08001415 enum_def.name = enum_name;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001416 enum_def.file = file_being_parsed_;
Max Galkinc3807fa2015-03-07 08:49:55 -08001417 enum_def.doc_comment = enum_comment;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001418 enum_def.is_union = is_union;
Wouter van Oortmerssen7b805352014-09-23 11:55:42 -07001419 enum_def.defined_namespace = namespaces_.back();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001420 if (enums_.Add(namespaces_.back()->GetFullyQualifiedName(enum_name),
1421 &enum_def))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001422 return Error("enum already exists: " + enum_name);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001423 if (is_union) {
1424 enum_def.underlying_type.base_type = BASE_TYPE_UTYPE;
1425 enum_def.underlying_type.enum_def = &enum_def;
Wouter van Oortmerssena5f50012014-07-02 12:01:21 -07001426 } else {
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -08001427 if (opts.proto_mode) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001428 enum_def.underlying_type.base_type = BASE_TYPE_INT;
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001429 } else {
1430 // Give specialized error message, since this type spec used to
1431 // be optional in the first FlatBuffers release.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001432 if (!Is(':')) {
1433 return Error("must specify the underlying integer type for this"
1434 " enum (e.g. \': short\', which was the default).");
1435 } else {
1436 NEXT();
1437 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001438 // Specify the integer type underlying this enum.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001439 ECHECK(ParseType(enum_def.underlying_type));
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001440 if (!IsInteger(enum_def.underlying_type.base_type))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001441 return Error("underlying enum type must be integral");
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001442 }
Wouter van Oortmerssen3fb6a862014-07-14 17:49:04 -07001443 // Make this type refer back to the enum it was derived from.
1444 enum_def.underlying_type.enum_def = &enum_def;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001445 }
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001446 ECHECK(ParseMetaData(&enum_def.attributes));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001447 EXPECT('{');
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001448 if (is_union) enum_def.vals.Add("NONE", new EnumVal("NONE", 0));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001449 for (;;) {
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -08001450 if (opts.proto_mode && attribute_ == "option") {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001451 ECHECK(ParseProtoOption());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001452 } else {
1453 auto value_name = attribute_;
1454 auto full_name = value_name;
1455 std::vector<std::string> value_comment = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001456 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen36390322016-06-17 18:16:11 -07001457 if (is_union) {
1458 ECHECK(ParseNamespacing(&full_name, &value_name));
Wouter van Oortmerssend70f5ac2016-07-29 10:45:32 -07001459 if (opts.union_value_namespacing) {
1460 // Since we can't namespace the actual enum identifiers, turn
1461 // namespace parts into part of the identifier.
1462 value_name = full_name;
1463 std::replace(value_name.begin(), value_name.end(), '.', '_');
1464 }
Wouter van Oortmerssen36390322016-06-17 18:16:11 -07001465 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001466 auto prevsize = enum_def.vals.vec.size();
1467 auto value = enum_def.vals.vec.size()
1468 ? enum_def.vals.vec.back()->value + 1
1469 : 0;
1470 auto &ev = *new EnumVal(value_name, value);
1471 if (enum_def.vals.Add(value_name, &ev))
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001472 return Error("enum value already exists: " + value_name);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001473 ev.doc_comment = value_comment;
1474 if (is_union) {
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -07001475 if (Is(':')) {
1476 NEXT();
1477 ECHECK(ParseType(ev.union_type));
1478 if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
1479 ev.union_type.base_type != BASE_TYPE_STRING)
1480 return Error("union value type may only be table/struct/string");
1481 enum_def.uses_type_aliases = true;
1482 } else {
1483 ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
1484 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001485 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001486 if (Is('=')) {
1487 NEXT();
Wouter van Oortmerssend7793082016-02-10 11:25:31 -08001488 ev.value = StringToInt(attribute_.c_str());
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001489 EXPECT(kTokenIntegerConstant);
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -08001490 if (!opts.proto_mode && prevsize &&
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001491 enum_def.vals.vec[prevsize - 1]->value >= ev.value)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001492 return Error("enum values must be specified in ascending order");
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001493 }
Wouter van Oortmerssen9d01bfa2017-05-10 17:21:47 -07001494 if (is_union) {
1495 if (ev.value < 0 || ev.value >= 256)
1496 return Error("union enum value must fit in a ubyte");
1497 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001498 if (opts.proto_mode && Is('[')) {
1499 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001500 // ignore attributes on enums.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001501 while (token_ != ']') NEXT();
1502 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001503 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001504 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001505 if (!Is(opts.proto_mode ? ';' : ',')) break;
1506 NEXT();
1507 if (Is('}')) break;
1508 }
1509 EXPECT('}');
Wouter van Oortmerssen127d3502014-07-17 15:12:37 -07001510 if (enum_def.attributes.Lookup("bit_flags")) {
1511 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
1512 ++it) {
1513 if (static_cast<size_t>((*it)->value) >=
1514 SizeOf(enum_def.underlying_type.base_type) * 8)
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001515 return Error("bit flag out of range of underlying integral type");
Wouter van Oortmerssen9c3de1e2014-07-25 15:04:35 -07001516 (*it)->value = 1LL << (*it)->value;
Wouter van Oortmerssen127d3502014-07-17 15:12:37 -07001517 }
1518 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001519 if (dest) *dest = &enum_def;
Wouter van Oortmerssen9b3d8b32017-01-27 15:28:57 -08001520 types_.Add(namespaces_.back()->GetFullyQualifiedName(enum_def.name),
1521 new Type(BASE_TYPE_UNION, nullptr, &enum_def));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001522 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001523}
1524
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001525CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001526 auto &struct_def = *LookupCreateStruct(name, true, true);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001527 if (!struct_def.predecl) return Error("datatype already exists: " + name);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001528 struct_def.predecl = false;
1529 struct_def.name = name;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001530 struct_def.file = file_being_parsed_;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001531 // Move this struct to the back of the vector just in case it was predeclared,
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001532 // to preserve declaration order.
Dmitry Ermolov370693a2017-04-20 02:55:41 +03001533 *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001534 *dest = &struct_def;
1535 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001536}
1537
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001538CheckedError Parser::CheckClash(std::vector<FieldDef*> &fields,
1539 StructDef *struct_def,
1540 const char *suffix,
1541 BaseType basetype) {
1542 auto len = strlen(suffix);
1543 for (auto it = fields.begin(); it != fields.end(); ++it) {
1544 auto &fname = (*it)->name;
1545 if (fname.length() > len &&
1546 fname.compare(fname.length() - len, len, suffix) == 0 &&
1547 (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
1548 auto field = struct_def->fields.Lookup(
1549 fname.substr(0, fname.length() - len));
1550 if (field && field->value.type.base_type == basetype)
1551 return Error("Field " + fname +
1552 " would clash with generated functions for field " +
1553 field->name);
1554 }
1555 }
1556 return NoError();
1557}
Wouter van Oortmerssend7793082016-02-10 11:25:31 -08001558
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001559static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
1560 auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
1561 auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
1562 return a_id < b_id;
1563}
1564
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001565CheckedError Parser::ParseDecl() {
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001566 std::vector<std::string> dc = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001567 bool fixed = Is(kTokenStruct);
1568 if (fixed) NEXT() else EXPECT(kTokenTable);
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 Oortmerssen9b3d8b32017-01-27 15:28:57 -08001627 types_.Add(namespaces_.back()->GetFullyQualifiedName(struct_def->name),
1628 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;
1641 service_def.defined_namespace = namespaces_.back();
1642 if (services_.Add(namespaces_.back()->GetFullyQualifiedName(service_name),
1643 &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 {
1648 auto rpc_name = attribute_;
1649 EXPECT(kTokenIdentifier);
1650 EXPECT('(');
1651 Type reqtype, resptype;
1652 ECHECK(ParseTypeIdent(reqtype));
1653 EXPECT(')');
1654 EXPECT(':');
1655 ECHECK(ParseTypeIdent(resptype));
1656 if (reqtype.base_type != BASE_TYPE_STRUCT || reqtype.struct_def->fixed ||
1657 resptype.base_type != BASE_TYPE_STRUCT || resptype.struct_def->fixed)
1658 return Error("rpc request and response types must be tables");
1659 auto &rpc = *new RPCCall();
1660 rpc.name = rpc_name;
1661 rpc.request = reqtype.struct_def;
1662 rpc.response = resptype.struct_def;
1663 if (service_def.calls.Add(rpc_name, &rpc))
1664 return Error("rpc already exists: " + rpc_name);
Wouter van Oortmerssene6b79f02016-03-09 15:03:05 -08001665 ECHECK(ParseMetaData(&rpc.attributes));
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08001666 EXPECT(';');
1667 } while (token_ != '}');
1668 NEXT();
1669 return NoError();
1670}
1671
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001672bool Parser::SetRootType(const char *name) {
Wouter van Oortmerssen4dcaec72015-12-09 16:41:12 -08001673 root_struct_def_ = structs_.Lookup(name);
1674 if (!root_struct_def_)
1675 root_struct_def_ = structs_.Lookup(
1676 namespaces_.back()->GetFullyQualifiedName(name));
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07001677 return root_struct_def_ != nullptr;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08001678}
1679
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001680void Parser::MarkGenerated() {
Wouter van Oortmerssen3881bbd2015-11-30 16:42:48 -08001681 // This function marks all existing definitions as having already
1682 // been generated, which signals no code for included files should be
1683 // generated.
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001684 for (auto it = enums_.vec.begin();
1685 it != enums_.vec.end(); ++it) {
1686 (*it)->generated = true;
1687 }
1688 for (auto it = structs_.vec.begin();
1689 it != structs_.vec.end(); ++it) {
Robbie McElrath0e85eee2017-06-26 09:07:02 -07001690 if (!(*it)->predecl) {
1691 (*it)->generated = true;
1692 }
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001693 }
Wouter van Oortmerssen48f37f92016-04-13 18:16:05 -07001694 for (auto it = services_.vec.begin();
1695 it != services_.vec.end(); ++it) {
1696 (*it)->generated = true;
1697 }
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07001698}
1699
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001700CheckedError Parser::ParseNamespace() {
1701 NEXT();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001702 auto ns = new Namespace();
1703 namespaces_.push_back(ns);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001704 if (token_ != ';') {
1705 for (;;) {
1706 ns->components.push_back(attribute_);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001707 EXPECT(kTokenIdentifier);
1708 if (Is('.')) NEXT() else break;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001709 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001710 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001711 EXPECT(';');
1712 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001713}
1714
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001715static bool compareEnumVals(const EnumVal *a, const EnumVal* b) {
1716 return a->value < b->value;
1717}
1718
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001719// Best effort parsing of .proto declarations, with the aim to turn them
1720// in the closest corresponding FlatBuffer equivalent.
1721// We parse everything as identifiers instead of keywords, since we don't
1722// want protobuf keywords to become invalid identifiers in FlatBuffers.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001723CheckedError Parser::ParseProtoDecl() {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001724 bool isextend = attribute_ == "extend";
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001725 if (attribute_ == "package") {
1726 // These are identical in syntax to FlatBuffer's namespace decl.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001727 ECHECK(ParseNamespace());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001728 } else if (attribute_ == "message" || isextend) {
Advay Mengle3ad85362015-03-31 02:03:11 -07001729 std::vector<std::string> struct_comment = doc_comment_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001730 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001731 StructDef *struct_def = nullptr;
1732 if (isextend) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001733 if (Is('.')) NEXT(); // qualified names may start with a . ?
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001734 auto id = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001735 EXPECT(kTokenIdentifier);
1736 ECHECK(ParseNamespacing(&id, nullptr));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001737 struct_def = LookupCreateStruct(id, false);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001738 if (!struct_def)
1739 return Error("cannot extend unknown message type: " + id);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001740 } else {
1741 std::string name = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001742 EXPECT(kTokenIdentifier);
1743 ECHECK(StartStruct(name, &struct_def));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001744 // Since message definitions can be nested, we create a new namespace.
1745 auto ns = new Namespace();
1746 // Copy of current namespace.
1747 *ns = *namespaces_.back();
1748 // But with current message name.
1749 ns->components.push_back(name);
1750 namespaces_.push_back(ns);
1751 }
1752 struct_def->doc_comment = struct_comment;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001753 ECHECK(ParseProtoFields(struct_def, isextend, false));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001754 if (!isextend) {
1755 // We have to remove the nested namespace, but we can't just throw it
1756 // away, so put it at the beginning of the vector.
1757 auto ns = namespaces_.back();
1758 namespaces_.pop_back();
1759 namespaces_.insert(namespaces_.begin(), ns);
1760 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001761 if (Is(';')) NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001762 } else if (attribute_ == "enum") {
1763 // These are almost the same, just with different terminator:
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001764 EnumDef *enum_def;
1765 ECHECK(ParseEnum(false, &enum_def));
1766 if (Is(';')) NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001767 // Protobuf allows them to be specified in any order, so sort afterwards.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001768 auto &v = enum_def->vals.vec;
Wouter van Oortmerssend7793082016-02-10 11:25:31 -08001769 std::sort(v.begin(), v.end(), compareEnumVals);
Chandra Penkeb63ebad2016-01-06 08:31:53 -08001770
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001771 // Temp: remove any duplicates, as .fbs files can't handle them.
1772 for (auto it = v.begin(); it != v.end(); ) {
1773 if (it != v.begin() && it[0]->value == it[-1]->value) it = v.erase(it);
1774 else ++it;
1775 }
1776 } else if (attribute_ == "syntax") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001777 NEXT();
1778 EXPECT('=');
1779 EXPECT(kTokenStringConstant);
1780 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001781 } else if (attribute_ == "option") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001782 ECHECK(ParseProtoOption());
1783 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001784 } else if (attribute_ == "service") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001785 NEXT();
1786 EXPECT(kTokenIdentifier);
1787 ECHECK(ParseProtoCurliesOrIdent());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001788 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001789 return Error("don\'t know how to parse .proto declaration starting with " +
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001790 TokenToStringId(token_));
1791 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001792 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001793}
1794
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001795CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend,
1796 bool inside_oneof) {
1797 EXPECT('{');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001798 while (token_ != '}') {
1799 if (attribute_ == "message" || attribute_ == "extend" ||
1800 attribute_ == "enum") {
1801 // Nested declarations.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001802 ECHECK(ParseProtoDecl());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001803 } else if (attribute_ == "extensions") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001804 NEXT();
1805 EXPECT(kTokenIntegerConstant);
1806 if (Is(kTokenIdentifier)) {
1807 NEXT(); // to
1808 NEXT(); // num
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001809 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001810 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001811 } else if (attribute_ == "option") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001812 ECHECK(ParseProtoOption());
1813 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001814 } else if (attribute_ == "reserved") { // Skip these.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001815 NEXT();
1816 EXPECT(kTokenIntegerConstant);
1817 while (Is(',')) { NEXT(); EXPECT(kTokenIntegerConstant); }
1818 EXPECT(';');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001819 } else {
1820 std::vector<std::string> field_comment = doc_comment_;
1821 // Parse the qualifier.
1822 bool required = false;
1823 bool repeated = false;
1824 bool oneof = false;
1825 if (!inside_oneof) {
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001826 if (attribute_ == "optional") {
1827 // This is the default.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001828 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001829 } else if (attribute_ == "required") {
1830 required = true;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001831 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001832 } else if (attribute_ == "repeated") {
1833 repeated = true;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001834 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001835 } else if (attribute_ == "oneof") {
1836 oneof = true;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001837 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001838 } else {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001839 // can't error, proto3 allows decls without any of the above.
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001840 }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001841 }
1842 StructDef *anonymous_struct = nullptr;
1843 Type type;
1844 if (attribute_ == "group" || oneof) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001845 if (!oneof) EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001846 auto name = "Anonymous" + NumToString(anonymous_counter++);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001847 ECHECK(StartStruct(name, &anonymous_struct));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001848 type = Type(BASE_TYPE_STRUCT, anonymous_struct);
1849 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001850 ECHECK(ParseTypeFromProtoType(&type));
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001851 }
1852 // Repeated elements get mapped to a vector.
1853 if (repeated) {
1854 type.element = type.base_type;
1855 type.base_type = BASE_TYPE_VECTOR;
1856 }
1857 std::string name = attribute_;
1858 // Protos may use our keywords "attribute" & "namespace" as an identifier.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001859 if (Is(kTokenAttribute) || Is(kTokenNameSpace)) {
1860 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001861 // TODO: simpler to just not make these keywords?
1862 name += "_"; // Have to make it not a keyword.
1863 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001864 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001865 }
1866 if (!oneof) {
Wouter van Oortmerssen2abe24b2015-09-28 09:42:45 -07001867 // Parse the field id. Since we're just translating schemas, not
1868 // any kind of binary compatibility, we can safely ignore these, and
1869 // assign our own.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001870 EXPECT('=');
1871 EXPECT(kTokenIntegerConstant);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001872 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001873 FieldDef *field = nullptr;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001874 if (isextend) {
1875 // We allow a field to be re-defined when extending.
1876 // TODO: are there situations where that is problematic?
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001877 field = struct_def->fields.Lookup(name);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001878 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001879 if (!field) ECHECK(AddField(*struct_def, name, type, &field));
1880 field->doc_comment = field_comment;
1881 if (!IsScalar(type.base_type)) field->required = required;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001882 // See if there's a default specified.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001883 if (Is('[')) {
1884 NEXT();
1885 for (;;) {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001886 auto key = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001887 ECHECK(ParseProtoKey());
1888 EXPECT('=');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001889 auto val = attribute_;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001890 ECHECK(ParseProtoCurliesOrIdent());
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001891 if (key == "default") {
1892 // Temp: skip non-numeric defaults (enums).
1893 auto numeric = strpbrk(val.c_str(), "0123456789-+.");
1894 if (IsScalar(type.base_type) && numeric == val.c_str())
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001895 field->value.constant = val;
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001896 } else if (key == "deprecated") {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001897 field->deprecated = val == "true";
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001898 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001899 if (!Is(',')) break;
1900 NEXT();
1901 }
1902 EXPECT(']');
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001903 }
1904 if (anonymous_struct) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001905 ECHECK(ParseProtoFields(anonymous_struct, false, oneof));
1906 if (Is(';')) NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001907 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001908 EXPECT(';');
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001909 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001910 }
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001911 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001912 NEXT();
1913 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001914}
1915
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001916CheckedError Parser::ParseProtoKey() {
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001917 if (token_ == '(') {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001918 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001919 // Skip "(a.b)" style custom attributes.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001920 while (token_ == '.' || token_ == kTokenIdentifier) NEXT();
1921 EXPECT(')');
1922 while (Is('.')) { NEXT(); EXPECT(kTokenIdentifier); }
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001923 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001924 EXPECT(kTokenIdentifier);
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001925 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001926 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001927}
1928
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001929CheckedError Parser::ParseProtoCurliesOrIdent() {
1930 if (Is('{')) {
1931 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001932 for (int nesting = 1; nesting; ) {
1933 if (token_ == '{') nesting++;
1934 else if (token_ == '}') nesting--;
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001935 NEXT();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001936 }
1937 } else {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001938 NEXT(); // Any single token.
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001939 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001940 return NoError();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07001941}
1942
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001943CheckedError Parser::ParseProtoOption() {
1944 NEXT();
1945 ECHECK(ParseProtoKey());
1946 EXPECT('=');
1947 ECHECK(ParseProtoCurliesOrIdent());
1948 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001949}
1950
1951// Parse a protobuf type, and map it to the corresponding FlatBuffer one.
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001952CheckedError Parser::ParseTypeFromProtoType(Type *type) {
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001953 struct type_lookup { const char *proto_type; BaseType fb_type; };
1954 static type_lookup lookup[] = {
1955 { "float", BASE_TYPE_FLOAT }, { "double", BASE_TYPE_DOUBLE },
1956 { "int32", BASE_TYPE_INT }, { "int64", BASE_TYPE_LONG },
1957 { "uint32", BASE_TYPE_UINT }, { "uint64", BASE_TYPE_ULONG },
1958 { "sint32", BASE_TYPE_INT }, { "sint64", BASE_TYPE_LONG },
1959 { "fixed32", BASE_TYPE_UINT }, { "fixed64", BASE_TYPE_ULONG },
1960 { "sfixed32", BASE_TYPE_INT }, { "sfixed64", BASE_TYPE_LONG },
1961 { "bool", BASE_TYPE_BOOL },
1962 { "string", BASE_TYPE_STRING },
1963 { "bytes", BASE_TYPE_STRING },
1964 { nullptr, BASE_TYPE_NONE }
1965 };
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001966 for (auto tl = lookup; tl->proto_type; tl++) {
1967 if (attribute_ == tl->proto_type) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001968 type->base_type = tl->fb_type;
1969 NEXT();
1970 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001971 }
1972 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08001973 if (Is('.')) NEXT(); // qualified names may start with a . ?
1974 ECHECK(ParseTypeIdent(*type));
1975 return NoError();
Wouter van Oortmerssend38b9af2014-09-26 16:46:30 -07001976}
1977
Nalinichandra Penke13d05942015-12-22 00:02:19 -08001978CheckedError Parser::SkipAnyJsonValue() {
1979 switch (token_) {
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001980 case '{': {
Stewart Milesa8923222017-07-13 06:27:39 -07001981 size_t fieldn_outer = 0;
1982 return ParseTableDelimiters(fieldn_outer, nullptr,
1983 [](const std::string &,
1984 size_t &fieldn, const StructDef *,
1985 void *state) -> CheckedError {
1986 auto *parser = static_cast<Parser *>(state);
1987 ECHECK(parser->SkipAnyJsonValue());
1988 fieldn++;
1989 return NoError();
1990 },
1991 this);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07001992 }
1993 case '[': {
1994 size_t count = 0;
Stewart Milesa8923222017-07-13 06:27:39 -07001995 return ParseVectorDelimiters(count, [](size_t &,
1996 void *state) -> CheckedError {
1997 return static_cast<Parser *>(state)->SkipAnyJsonValue();
1998 },
1999 this);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002000 }
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002001 case kTokenStringConstant:
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002002 EXPECT(kTokenStringConstant);
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002003 break;
2004 case kTokenIntegerConstant:
2005 EXPECT(kTokenIntegerConstant);
2006 break;
2007 case kTokenFloatConstant:
2008 EXPECT(kTokenFloatConstant);
2009 break;
2010 default:
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002011 return TokenError();
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002012 }
2013 return NoError();
2014}
2015
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002016CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
2017 switch (token_) {
2018 case '{': {
Stewart Milesa8923222017-07-13 06:27:39 -07002019 std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state(
2020 this, builder);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002021 auto start = builder->StartMap();
Stewart Milesa8923222017-07-13 06:27:39 -07002022 size_t fieldn_outer = 0;
2023 auto err = ParseTableDelimiters(fieldn_outer, nullptr,
2024 [](const std::string &name,
2025 size_t &fieldn, const StructDef *,
2026 void *state) -> CheckedError {
2027 auto *parser_and_builder =
2028 static_cast<std::pair<Parser *, flexbuffers::Builder *> *>(
2029 state);
2030 auto *parser = parser_and_builder->first;
2031 auto *current_builder = parser_and_builder->second;
2032 current_builder->Key(name);
2033 ECHECK(parser->ParseFlexBufferValue(current_builder));
2034 fieldn++;
2035 return NoError();
2036 },
2037 &parser_and_builder_state);
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002038 ECHECK(err);
2039 builder->EndMap(start);
2040 break;
Nalinichandra Penkecbab2662016-02-22 14:27:08 -06002041 }
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002042 case '[':{
2043 auto start = builder->StartVector();
2044 size_t count = 0;
Stewart Milesa8923222017-07-13 06:27:39 -07002045 std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state(
2046 this, builder);
2047 ECHECK(ParseVectorDelimiters(count, [](size_t &,
2048 void *state) -> CheckedError {
2049 auto *parser_and_builder =
2050 static_cast<std::pair<Parser *, flexbuffers::Builder *> *>(
2051 state);
2052 return parser_and_builder->first->ParseFlexBufferValue(
2053 parser_and_builder->second);
2054 },
2055 &parser_and_builder_state));
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002056 builder->EndVector(start, false, false);
2057 break;
Nalinichandra Penkecbab2662016-02-22 14:27:08 -06002058 }
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002059 case kTokenStringConstant:
2060 builder->String(attribute_);
2061 EXPECT(kTokenStringConstant);
2062 break;
2063 case kTokenIntegerConstant:
2064 builder->Int(StringToInt(attribute_.c_str()));
2065 EXPECT(kTokenIntegerConstant);
2066 break;
2067 case kTokenFloatConstant:
2068 builder->Double(strtod(attribute_.c_str(), nullptr));
2069 EXPECT(kTokenFloatConstant);
2070 break;
2071 default:
2072 return TokenError();
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002073 }
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002074 return NoError();
2075}
2076
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002077bool Parser::ParseFlexBuffer(const char *source, const char *source_filename,
2078 flexbuffers::Builder *builder) {
2079 auto ok = !StartParseFile(source, source_filename).Check() &&
2080 !ParseFlexBufferValue(builder).Check();
2081 if (ok) builder->Finish();
2082 return ok;
Nalinichandra Penke13d05942015-12-22 00:02:19 -08002083}
2084
Wouter van Oortmerssen30642c52014-09-22 15:49:43 -07002085bool Parser::Parse(const char *source, const char **include_paths,
2086 const char *source_filename) {
Robbie McElrath0e85eee2017-06-26 09:07:02 -07002087 return !ParseRoot(source, include_paths, source_filename).Check();
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002088}
2089
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002090CheckedError Parser::StartParseFile(const char *source, const char *source_filename) {
2091 file_being_parsed_ = source_filename ? source_filename : "";
2092 source_ = cursor_ = source;
2093 line_ = 1;
2094 error_.clear();
2095 ECHECK(SkipByteOrderMark());
2096 NEXT();
2097 if (Is(kTokenEof))
2098 return Error("input file is empty");
2099 return NoError();
2100}
2101
Robbie McElrath0e85eee2017-06-26 09:07:02 -07002102CheckedError Parser::ParseRoot(const char *source, const char **include_paths,
2103 const char *source_filename) {
2104 ECHECK(DoParse(source, include_paths, source_filename, nullptr));
2105
2106 // Check that all types were defined.
2107 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
2108 if ((*it)->predecl) {
2109 return Error("type referenced but not defined: " + (*it)->name);
2110 }
2111 }
2112
2113 // This check has to happen here and not earlier, because only now do we
2114 // know for sure what the type of these are.
2115 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
2116 auto &enum_def = **it;
2117 if (enum_def.is_union) {
2118 for (auto val_it = enum_def.vals.vec.begin();
2119 val_it != enum_def.vals.vec.end();
2120 ++val_it) {
2121 auto &val = **val_it;
2122 if (opts.lang_to_generate != IDLOptions::kCpp &&
2123 val.union_type.struct_def && val.union_type.struct_def->fixed)
2124 return Error(
2125 "only tables can be union elements in the generated language: "
2126 + val.name);
2127 }
2128 }
2129 }
2130 return NoError();
2131}
2132
2133CheckedError Parser::DoParse(const char *source,
2134 const char **include_paths,
2135 const char *source_filename,
2136 const char *include_filename) {
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002137 if (source_filename &&
Pavel Kalinnikov642254b2017-06-02 17:50:18 +02002138 included_files_.find(source_filename) == included_files_.end()) {
2139 included_files_[source_filename] = include_filename ? include_filename : "";
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002140 files_included_per_file_[source_filename] = std::set<std::string>();
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002141 }
2142 if (!include_paths) {
Wouter van Oortmerssen1e6f8f52015-06-22 10:23:42 -07002143 static const char *current_directory[] = { "", nullptr };
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002144 include_paths = current_directory;
2145 }
Yonggang Lifea6b522017-01-03 13:54:15 -08002146 field_stack_.clear();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002147 builder_.Clear();
Wouter van Oortmerssen94680f52015-10-05 17:39:08 -07002148 // Start with a blank namespace just in case this file doesn't have one.
2149 namespaces_.push_back(new Namespace());
Louis-Paul CORDIERe7e4dc72017-03-10 17:50:44 +01002150
Wouter van Oortmerssen8f864aa2017-06-05 17:45:44 -07002151 ECHECK(StartParseFile(source, source_filename));
Louis-Paul CORDIERe7e4dc72017-03-10 17:50:44 +01002152
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002153 // Includes must come before type declarations:
2154 for (;;) {
2155 // Parse pre-include proto statements if any:
2156 if (opts.proto_mode &&
2157 (attribute_ == "option" || attribute_ == "syntax" ||
2158 attribute_ == "package")) {
2159 ECHECK(ParseProtoDecl());
Wouter van Oortmerssen3f936c52017-01-18 16:23:35 -08002160 } else if (Is(kTokenNativeInclude)) {
2161 NEXT();
Stewart Milesa8923222017-07-13 06:27:39 -07002162 vector_emplace_back(&native_included_files_, attribute_);
Wouter van Oortmerssen3f936c52017-01-18 16:23:35 -08002163 EXPECT(kTokenStringConstant);
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002164 } else if (Is(kTokenInclude) ||
2165 (opts.proto_mode &&
2166 attribute_ == "import" &&
2167 Is(kTokenIdentifier))) {
2168 NEXT();
2169 if (opts.proto_mode && attribute_ == "public") NEXT();
Wouter van Oortmerssenaaf55982017-05-18 17:18:43 -07002170 auto name = flatbuffers::PosixPath(attribute_.c_str());
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002171 EXPECT(kTokenStringConstant);
2172 // Look for the file in include_paths.
2173 std::string filepath;
2174 for (auto paths = include_paths; paths && *paths; paths++) {
2175 filepath = flatbuffers::ConCatPathFileName(*paths, name);
2176 if(FileExists(filepath.c_str())) break;
Wouter van Oortmerssenbe894f02014-08-19 14:20:05 -07002177 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002178 if (filepath.empty())
2179 return Error("unable to locate include file: " + name);
2180 if (source_filename)
2181 files_included_per_file_[source_filename].insert(filepath);
Pavel Kalinnikov642254b2017-06-02 17:50:18 +02002182 if (included_files_.find(filepath) == included_files_.end()) {
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002183 // We found an include file that we have not parsed yet.
2184 // Load it and parse it.
2185 std::string contents;
2186 if (!LoadFile(filepath.c_str(), true, &contents))
2187 return Error("unable to load include file: " + name);
Wouter van Oortmerssen22743ca2017-05-24 15:21:26 -07002188 ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
2189 name.c_str()));
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002190 // We generally do not want to output code for any included files:
2191 if (!opts.generate_all) MarkGenerated();
2192 // This is the easiest way to continue this file after an include:
2193 // instead of saving and restoring all the state, we simply start the
2194 // file anew. This will cause it to encounter the same include
2195 // statement again, but this time it will skip it, because it was
2196 // entered into included_files_.
2197 // This is recursive, but only go as deep as the number of include
2198 // statements.
Wouter van Oortmerssen22743ca2017-05-24 15:21:26 -07002199 return DoParse(source, include_paths, source_filename, include_filename);
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002200 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002201 EXPECT(';');
2202 } else {
2203 break;
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002204 }
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002205 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002206 // Now parse all other kinds of declarations:
2207 while (token_ != kTokenEof) {
2208 if (opts.proto_mode) {
2209 ECHECK(ParseProtoDecl());
2210 } else if (token_ == kTokenNameSpace) {
2211 ECHECK(ParseNamespace());
2212 } else if (token_ == '{') {
2213 if (!root_struct_def_)
2214 return Error("no root type set to parse json with");
2215 if (builder_.GetSize()) {
2216 return Error("cannot have more than one json object in a file");
2217 }
2218 uoffset_t toff;
2219 ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
2220 builder_.Finish(Offset<Table>(toff),
2221 file_identifier_.length() ? file_identifier_.c_str() : nullptr);
2222 } else if (token_ == kTokenEnum) {
2223 ECHECK(ParseEnum(false, nullptr));
2224 } else if (token_ == kTokenUnion) {
2225 ECHECK(ParseEnum(true, nullptr));
2226 } else if (token_ == kTokenRootType) {
2227 NEXT();
2228 auto root_type = attribute_;
2229 EXPECT(kTokenIdentifier);
2230 ECHECK(ParseNamespacing(&root_type, nullptr));
2231 if (!SetRootType(root_type.c_str()))
2232 return Error("unknown root type: " + root_type);
2233 if (root_struct_def_->fixed)
2234 return Error("root type must be a table");
2235 EXPECT(';');
2236 } else if (token_ == kTokenFileIdentifier) {
2237 NEXT();
2238 file_identifier_ = attribute_;
2239 EXPECT(kTokenStringConstant);
2240 if (file_identifier_.length() !=
2241 FlatBufferBuilder::kFileIdentifierLength)
2242 return Error("file_identifier must be exactly " +
2243 NumToString(FlatBufferBuilder::kFileIdentifierLength) +
2244 " characters");
2245 EXPECT(';');
2246 } else if (token_ == kTokenFileExtension) {
2247 NEXT();
2248 file_extension_ = attribute_;
2249 EXPECT(kTokenStringConstant);
2250 EXPECT(';');
2251 } else if(token_ == kTokenInclude) {
2252 return Error("includes must come before declarations");
2253 } else if(token_ == kTokenAttribute) {
2254 NEXT();
2255 auto name = attribute_;
2256 EXPECT(kTokenStringConstant);
2257 EXPECT(';');
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002258 known_attributes_[name] = false;
Wouter van Oortmerssen1a63eb42016-03-07 18:07:10 -08002259 } else if (token_ == kTokenService) {
2260 ECHECK(ParseService());
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002261 } else {
2262 ECHECK(ParseDecl());
2263 }
2264 }
Wouter van Oortmerssen40a33b12015-12-09 18:06:56 -08002265 return NoError();
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002266}
2267
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002268std::set<std::string> Parser::GetIncludedFilesRecursive(
2269 const std::string &file_name) const {
2270 std::set<std::string> included_files;
2271 std::list<std::string> to_process;
2272
2273 if (file_name.empty()) return included_files;
2274 to_process.push_back(file_name);
2275
2276 while (!to_process.empty()) {
2277 std::string current = to_process.front();
2278 to_process.pop_front();
2279 included_files.insert(current);
2280
Stewart Milesa8923222017-07-13 06:27:39 -07002281 // Workaround the lack of const accessor in C++98 maps.
2282 auto &new_files =
2283 (*const_cast<std::map<std::string, std::set<std::string>> *>(
2284 &files_included_per_file_))[current];
Gabriel Martinezdf4909e2014-11-04 10:00:56 -08002285 for (auto it = new_files.begin(); it != new_files.end(); ++it) {
2286 if (included_files.find(*it) == included_files.end())
2287 to_process.push_back(*it);
2288 }
2289 }
2290
2291 return included_files;
2292}
2293
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002294// Schema serialization functionality:
2295
Chandra Penkeb63ebad2016-01-06 08:31:53 -08002296template<typename T> bool compareName(const T* a, const T* b) {
Xun Liudf0991b2016-09-14 10:33:06 -07002297 return a->defined_namespace->GetFullyQualifiedName(a->name)
2298 < b->defined_namespace->GetFullyQualifiedName(b->name);
Chandra Penkeb63ebad2016-01-06 08:31:53 -08002299}
2300
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002301template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
2302 // Pre-sort these vectors, such that we can set the correct indices for them.
2303 auto vec = defvec;
Chandra Penkeb63ebad2016-01-06 08:31:53 -08002304 std::sort(vec.begin(), vec.end(), compareName<T>);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002305 for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
2306}
2307
2308void Parser::Serialize() {
2309 builder_.Clear();
2310 AssignIndices(structs_.vec);
2311 AssignIndices(enums_.vec);
2312 std::vector<Offset<reflection::Object>> object_offsets;
2313 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002314 auto offset = (*it)->Serialize(&builder_, *this);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002315 object_offsets.push_back(offset);
2316 (*it)->serialized_location = offset.o;
2317 }
2318 std::vector<Offset<reflection::Enum>> enum_offsets;
2319 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002320 auto offset = (*it)->Serialize(&builder_, *this);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002321 enum_offsets.push_back(offset);
2322 (*it)->serialized_location = offset.o;
2323 }
2324 auto schema_offset = reflection::CreateSchema(
2325 builder_,
2326 builder_.CreateVectorOfSortedTables(&object_offsets),
2327 builder_.CreateVectorOfSortedTables(&enum_offsets),
2328 builder_.CreateString(file_identifier_),
2329 builder_.CreateString(file_extension_),
Wouter van Oortmerssen36c7e9a2015-06-29 15:21:48 -07002330 root_struct_def_
2331 ? root_struct_def_->serialized_location
2332 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002333 builder_.Finish(schema_offset, reflection::SchemaIdentifier());
2334}
2335
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002336Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
2337 const Parser &parser) const {
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002338 std::vector<Offset<reflection::Field>> field_offsets;
2339 for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
Wouter van Oortmerssen622b8d02015-06-15 15:57:48 -07002340 field_offsets.push_back(
2341 (*it)->Serialize(builder,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002342 static_cast<uint16_t>(it - fields.vec.begin()), parser));
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002343 }
Xun Liudf0991b2016-09-14 10:33:06 -07002344 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002345 return reflection::CreateObject(*builder,
Xun Liudf0991b2016-09-14 10:33:06 -07002346 builder->CreateString(qualified_name),
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002347 builder->CreateVectorOfSortedTables(
2348 &field_offsets),
Wouter van Oortmerssencb2b2be2015-06-23 16:06:35 -07002349 fixed,
2350 static_cast<int>(minalign),
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002351 static_cast<int>(bytesize),
Wouter van Oortmerssen1fb6b9e2017-02-13 16:15:55 -08002352 SerializeAttributes(builder, parser),
2353 parser.opts.binary_schema_comments
2354 ? builder->CreateVectorOfStrings(
2355 doc_comment)
2356 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002357}
2358
2359Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002360 uint16_t id,
2361 const Parser &parser) const {
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002362 return reflection::CreateField(*builder,
2363 builder->CreateString(name),
2364 value.type.Serialize(builder),
2365 id,
2366 value.offset,
2367 IsInteger(value.type.base_type)
2368 ? StringToInt(value.constant.c_str())
2369 : 0,
2370 IsFloat(value.type.base_type)
2371 ? strtod(value.constant.c_str(), nullptr)
2372 : 0.0,
2373 deprecated,
2374 required,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002375 key,
Wouter van Oortmerssen1fb6b9e2017-02-13 16:15:55 -08002376 SerializeAttributes(builder, parser),
2377 parser.opts.binary_schema_comments
2378 ? builder->CreateVectorOfStrings(doc_comment)
2379 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002380 // TODO: value.constant is almost always "0", we could save quite a bit of
2381 // space by sharing it. Same for common values of value.type.
2382}
2383
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002384Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
2385 const Parser &parser) const {
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002386 std::vector<Offset<reflection::EnumVal>> enumval_offsets;
2387 for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
2388 enumval_offsets.push_back((*it)->Serialize(builder));
2389 }
Xun Liudf0991b2016-09-14 10:33:06 -07002390 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002391 return reflection::CreateEnum(*builder,
Xun Liudf0991b2016-09-14 10:33:06 -07002392 builder->CreateString(qualified_name),
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002393 builder->CreateVector(enumval_offsets),
2394 is_union,
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002395 underlying_type.Serialize(builder),
Wouter van Oortmerssen1fb6b9e2017-02-13 16:15:55 -08002396 SerializeAttributes(builder, parser),
2397 parser.opts.binary_schema_comments
2398 ? builder->CreateVectorOfStrings(doc_comment)
2399 : 0);
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002400}
2401
2402Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const
2403 {
2404 return reflection::CreateEnumVal(*builder,
2405 builder->CreateString(name),
2406 value,
Wouter van Oortmerssenb0752e12017-04-10 15:56:51 -07002407 union_type.struct_def
2408 ? union_type.struct_def->
2409 serialized_location
2410 : 0,
2411 union_type.Serialize(builder));
Wouter van Oortmerssen81312c22015-05-21 16:33:29 -07002412}
2413
2414Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
2415 return reflection::CreateType(*builder,
2416 static_cast<reflection::BaseType>(base_type),
2417 static_cast<reflection::BaseType>(element),
2418 struct_def ? struct_def->index :
2419 (enum_def ? enum_def->index : -1));
2420}
2421
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002422flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<
2423 reflection::KeyValue>>>
2424 Definition::SerializeAttributes(FlatBufferBuilder *builder,
2425 const Parser &parser) const {
2426 std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -07002427 for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) {
2428 auto it = parser.known_attributes_.find(kv->first);
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002429 assert(it != parser.known_attributes_.end());
2430 if (!it->second) { // Custom attribute.
2431 attrs.push_back(
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -07002432 reflection::CreateKeyValue(*builder, builder->CreateString(kv->first),
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002433 builder->CreateString(
Wouter van Oortmerssene92ae512016-06-02 14:55:35 -07002434 kv->second->constant)));
Wouter van Oortmerssen72fc45a2016-04-11 17:36:56 -07002435 }
2436 }
2437 if (attrs.size()) {
2438 return builder->CreateVectorOfSortedTables(&attrs);
2439 } else {
2440 return 0;
2441 }
2442}
2443
Wouter van Oortmerssen05b00c52016-07-20 17:24:50 -07002444std::string Parser::ConformTo(const Parser &base) {
2445 for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) {
2446 auto &struct_def = **sit;
2447 auto qualified_name =
2448 struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name);
2449 auto struct_def_base = base.structs_.Lookup(qualified_name);
2450 if (!struct_def_base) continue;
2451 for (auto fit = struct_def.fields.vec.begin();
2452 fit != struct_def.fields.vec.end(); ++fit) {
2453 auto &field = **fit;
2454 auto field_base = struct_def_base->fields.Lookup(field.name);
2455 if (field_base) {
2456 if (field.value.offset != field_base->value.offset)
2457 return "offsets differ for field: " + field.name;
2458 if (field.value.constant != field_base->value.constant)
2459 return "defaults differ for field: " + field.name;
2460 if (!EqualByName(field.value.type, field_base->value.type))
2461 return "types differ for field: " + field.name;
2462 } else {
2463 // Doesn't have to exist, deleting fields is fine.
2464 // But we should check if there is a field that has the same offset
2465 // but is incompatible (in the case of field renaming).
2466 for (auto fbit = struct_def_base->fields.vec.begin();
2467 fbit != struct_def_base->fields.vec.end(); ++fbit) {
2468 field_base = *fbit;
2469 if (field.value.offset == field_base->value.offset) {
2470 if (!EqualByName(field.value.type, field_base->value.type))
2471 return "field renamed to different type: " + field.name;
2472 break;
2473 }
2474 }
2475 }
2476 }
2477 }
2478 for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) {
2479 auto &enum_def = **eit;
2480 auto qualified_name =
2481 enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name);
2482 auto enum_def_base = base.enums_.Lookup(qualified_name);
2483 if (!enum_def_base) continue;
2484 for (auto evit = enum_def.vals.vec.begin();
2485 evit != enum_def.vals.vec.end(); ++evit) {
2486 auto &enum_val = **evit;
2487 auto enum_val_base = enum_def_base->vals.Lookup(enum_val.name);
2488 if (enum_val_base) {
2489 if (enum_val.value != enum_val_base->value)
2490 return "values differ for enum: " + enum_val.name;
2491 }
2492 }
2493 }
2494 return "";
2495}
2496
Wouter van Oortmerssen26a30732014-01-27 16:52:49 -08002497} // namespace flatbuffers