1 /* 2 * Copyright 2014 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <algorithm> 18 #include <list> 19 #include <iostream> 20 21 #include <math.h> 22 23 #include "flatbuffers/idl.h" 24 #include "flatbuffers/util.h" 25 26 namespace flatbuffers { 27 28 const double kPi = 3.14159265358979323846; 29 30 const char *const kTypeNames[] = { 31 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ 32 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ 33 IDLTYPE, 34 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) 35 #undef FLATBUFFERS_TD 36 nullptr 37 }; 38 39 const char kTypeSizes[] = { 40 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ 41 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ 42 sizeof(CTYPE), 43 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) 44 #undef FLATBUFFERS_TD 45 }; 46 47 // The enums in the reflection schema should match the ones we use internally. 48 // Compare the last element to check if these go out of sync. 49 static_assert(BASE_TYPE_UNION == 50 static_cast<BaseType>(reflection::Union), 51 "enums don't match"); 52 53 // Any parsing calls have to be wrapped in this macro, which automates 54 // handling of recursive error checking a bit. It will check the received 55 // CheckedError object, and return straight away on error. 56 #define ECHECK(call) { auto ce = (call); if (ce.Check()) return ce; } 57 58 // These two functions are called hundreds of times below, so define a short 59 // form: 60 #define NEXT() ECHECK(Next()) 61 #define EXPECT(tok) ECHECK(Expect(tok)) 62 63 static bool ValidateUTF8(const std::string &str) { 64 const char *s = &str[0]; 65 const char * const sEnd = s + str.length(); 66 while (s < sEnd) { 67 if (FromUTF8(&s) < 0) { 68 return false; 69 } 70 } 71 return true; 72 } 73 74 void Parser::Message(const std::string &msg) { 75 error_ = file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : ""; 76 #ifdef _WIN32 77 error_ += "(" + NumToString(line_) + ")"; // MSVC alike 78 #else 79 if (file_being_parsed_.length()) error_ += ":"; 80 error_ += NumToString(line_) + ":0"; // gcc alike 81 #endif 82 error_ += ": " + msg; 83 } 84 85 void Parser::Warning(const std::string &msg) { 86 Message("warning: " + msg); 87 } 88 89 CheckedError Parser::Error(const std::string &msg) { 90 Message("error: " + msg); 91 return CheckedError(true); 92 } 93 94 inline CheckedError NoError() { return CheckedError(false); } 95 96 inline std::string OutOfRangeErrorMsg(int64_t val, const std::string &op, 97 int64_t limit) { 98 const std::string cause = NumToString(val) + op + NumToString(limit); 99 return "constant does not fit (" + cause + ")"; 100 } 101 102 // Ensure that integer values we parse fit inside the declared integer type. 103 CheckedError Parser::CheckInRange(int64_t val, int64_t min, int64_t max) { 104 if (val < min) 105 return Error(OutOfRangeErrorMsg(val, " < ", min)); 106 else if (val > max) 107 return Error(OutOfRangeErrorMsg(val, " > ", max)); 108 else 109 return NoError(); 110 } 111 112 // atot: templated version of atoi/atof: convert a string to an instance of T. 113 template<typename T> inline CheckedError atot(const char *s, Parser &parser, 114 T *val) { 115 int64_t i = StringToInt(s); 116 const int64_t min = flatbuffers::numeric_limits<T>::min(); 117 const int64_t max = flatbuffers::numeric_limits<T>::max(); 118 ECHECK(parser.CheckInRange(i, min, max)); 119 *val = (T)i; 120 return NoError(); 121 } 122 template<> inline CheckedError atot<uint64_t>(const char *s, Parser &parser, 123 uint64_t *val) { 124 (void)parser; 125 *val = StringToUInt(s); 126 return NoError(); 127 } 128 template<> inline CheckedError atot<bool>(const char *s, Parser &parser, 129 bool *val) { 130 (void)parser; 131 *val = 0 != atoi(s); 132 return NoError(); 133 } 134 template<> inline CheckedError atot<float>(const char *s, Parser &parser, 135 float *val) { 136 (void)parser; 137 *val = static_cast<float>(strtod(s, nullptr)); 138 return NoError(); 139 } 140 template<> inline CheckedError atot<double>(const char *s, Parser &parser, 141 double *val) { 142 (void)parser; 143 *val = strtod(s, nullptr); 144 return NoError(); 145 } 146 147 template<> inline CheckedError atot<Offset<void>>(const char *s, Parser &parser, 148 Offset<void> *val) { 149 (void)parser; 150 *val = Offset<void>(atoi(s)); 151 return NoError(); 152 } 153 154 std::string Namespace::GetFullyQualifiedName(const std::string &name, 155 size_t max_components) const { 156 // Early exit if we don't have a defined namespace. 157 if (components.size() == 0 || !max_components) { 158 return name; 159 } 160 std::stringstream stream; 161 for (size_t i = 0; i < std::min(components.size(), max_components); 162 i++) { 163 if (i) { 164 stream << "."; 165 } 166 stream << components[i]; 167 } 168 if (name.length()) stream << "." << name; 169 return stream.str(); 170 } 171 172 // Declare tokens we'll use. Single character tokens are represented by their 173 // ascii character code (e.g. '{'), others above 256. 174 #define FLATBUFFERS_GEN_TOKENS(TD) \ 175 TD(Eof, 256, "end of file") \ 176 TD(StringConstant, 257, "string constant") \ 177 TD(IntegerConstant, 258, "integer constant") \ 178 TD(FloatConstant, 259, "float constant") \ 179 TD(Identifier, 260, "identifier") 180 #ifdef __GNUC__ 181 __extension__ // Stop GCC complaining about trailing comma with -Wpendantic. 182 #endif 183 enum { 184 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE, 185 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN) 186 #undef FLATBUFFERS_TOKEN 187 }; 188 189 static std::string TokenToString(int t) { 190 static const char *tokens[] = { 191 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING, 192 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN) 193 #undef FLATBUFFERS_TOKEN 194 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ 195 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ 196 IDLTYPE, 197 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) 198 #undef FLATBUFFERS_TD 199 }; 200 if (t < 256) { // A single ascii char token. 201 std::string s; 202 s.append(1, static_cast<char>(t)); 203 return s; 204 } else { // Other tokens. 205 return tokens[t - 256]; 206 } 207 } 208 209 std::string Parser::TokenToStringId(int t) { 210 return t == kTokenIdentifier ? attribute_ : TokenToString(t); 211 } 212 213 // Parses exactly nibbles worth of hex digits into a number, or error. 214 CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) { 215 for (int i = 0; i < nibbles; i++) 216 if (!isxdigit(static_cast<const unsigned char>(cursor_[i]))) 217 return Error("escape code must be followed by " + NumToString(nibbles) + 218 " hex digits"); 219 std::string target(cursor_, cursor_ + nibbles); 220 *val = StringToUInt(target.c_str(), nullptr, 16); 221 cursor_ += nibbles; 222 return NoError(); 223 } 224 225 CheckedError Parser::SkipByteOrderMark() { 226 if (static_cast<unsigned char>(*cursor_) != 0xef) 227 return NoError(); 228 cursor_++; 229 if (static_cast<unsigned char>(*cursor_) != 0xbb) 230 return Error("invalid utf-8 byte order mark"); 231 cursor_++; 232 if (static_cast<unsigned char>(*cursor_) != 0xbf) 233 return Error("invalid utf-8 byte order mark"); 234 cursor_++; 235 return NoError(); 236 } 237 238 bool IsIdentifierStart(char c) { 239 return isalpha(static_cast<unsigned char>(c)) || c == '_'; 240 } 241 242 CheckedError Parser::Next() { 243 doc_comment_.clear(); 244 bool seen_newline = false; 245 attribute_.clear(); 246 for (;;) { 247 char c = *cursor_++; 248 token_ = c; 249 switch (c) { 250 case '\0': cursor_--; token_ = kTokenEof; return NoError(); 251 case ' ': case '\r': case '\t': break; 252 case '\n': line_++; seen_newline = true; break; 253 case '{': case '}': case '(': case ')': case '[': case ']': 254 case ',': case ':': case ';': case '=': return NoError(); 255 case '.': 256 if(!isdigit(static_cast<const unsigned char>(*cursor_))) return NoError(); 257 return Error("floating point constant can\'t start with \".\""); 258 case '\"': 259 case '\'': { 260 int unicode_high_surrogate = -1; 261 262 while (*cursor_ != c) { 263 if (*cursor_ < ' ' && *cursor_ >= 0) 264 return Error("illegal character in string constant"); 265 if (*cursor_ == '\\') { 266 cursor_++; 267 if (unicode_high_surrogate != -1 && 268 *cursor_ != 'u') { 269 return Error( 270 "illegal Unicode sequence (unpaired high surrogate)"); 271 } 272 switch (*cursor_) { 273 case 'n': attribute_ += '\n'; cursor_++; break; 274 case 't': attribute_ += '\t'; cursor_++; break; 275 case 'r': attribute_ += '\r'; cursor_++; break; 276 case 'b': attribute_ += '\b'; cursor_++; break; 277 case 'f': attribute_ += '\f'; cursor_++; break; 278 case '\"': attribute_ += '\"'; cursor_++; break; 279 case '\'': attribute_ += '\''; cursor_++; break; 280 case '\\': attribute_ += '\\'; cursor_++; break; 281 case '/': attribute_ += '/'; cursor_++; break; 282 case 'x': { // Not in the JSON standard 283 cursor_++; 284 uint64_t val; 285 ECHECK(ParseHexNum(2, &val)); 286 attribute_ += static_cast<char>(val); 287 break; 288 } 289 case 'u': { 290 cursor_++; 291 uint64_t val; 292 ECHECK(ParseHexNum(4, &val)); 293 if (val >= 0xD800 && val <= 0xDBFF) { 294 if (unicode_high_surrogate != -1) { 295 return Error( 296 "illegal Unicode sequence (multiple high surrogates)"); 297 } else { 298 unicode_high_surrogate = static_cast<int>(val); 299 } 300 } else if (val >= 0xDC00 && val <= 0xDFFF) { 301 if (unicode_high_surrogate == -1) { 302 return Error( 303 "illegal Unicode sequence (unpaired low surrogate)"); 304 } else { 305 int code_point = 0x10000 + 306 ((unicode_high_surrogate & 0x03FF) << 10) + 307 (val & 0x03FF); 308 ToUTF8(code_point, &attribute_); 309 unicode_high_surrogate = -1; 310 } 311 } else { 312 if (unicode_high_surrogate != -1) { 313 return Error( 314 "illegal Unicode sequence (unpaired high surrogate)"); 315 } 316 ToUTF8(static_cast<int>(val), &attribute_); 317 } 318 break; 319 } 320 default: return Error("unknown escape code in string constant"); 321 } 322 } else { // printable chars + UTF-8 bytes 323 if (unicode_high_surrogate != -1) { 324 return Error( 325 "illegal Unicode sequence (unpaired high surrogate)"); 326 } 327 attribute_ += *cursor_++; 328 } 329 } 330 if (unicode_high_surrogate != -1) { 331 return Error( 332 "illegal Unicode sequence (unpaired high surrogate)"); 333 } 334 cursor_++; 335 if (!opts.allow_non_utf8 && !ValidateUTF8(attribute_)) { 336 return Error("illegal UTF-8 sequence"); 337 } 338 token_ = kTokenStringConstant; 339 return NoError(); 340 } 341 case '/': 342 if (*cursor_ == '/') { 343 const char *start = ++cursor_; 344 while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++; 345 if (*start == '/') { // documentation comment 346 if (cursor_ != source_ && !seen_newline) 347 return Error( 348 "a documentation comment should be on a line on its own"); 349 doc_comment_.push_back(std::string(start + 1, cursor_)); 350 } 351 break; 352 } else if (*cursor_ == '*') { 353 cursor_++; 354 // TODO: make nested. 355 while (*cursor_ != '*' || cursor_[1] != '/') { 356 if (*cursor_ == '\n') line_++; 357 if (!*cursor_) return Error("end of file in comment"); 358 cursor_++; 359 } 360 cursor_ += 2; 361 break; 362 } 363 // fall thru 364 default: 365 if (IsIdentifierStart(c)) { 366 // Collect all chars of an identifier: 367 const char *start = cursor_ - 1; 368 while (isalnum(static_cast<unsigned char>(*cursor_)) || 369 *cursor_ == '_') 370 cursor_++; 371 attribute_.append(start, cursor_); 372 token_ = kTokenIdentifier; 373 return NoError(); 374 } else if (isdigit(static_cast<unsigned char>(c)) || c == '-') { 375 const char *start = cursor_ - 1; 376 if (c == '-' && *cursor_ == '0' && 377 (cursor_[1] == 'x' || cursor_[1] == 'X')) { 378 ++start; 379 ++cursor_; 380 attribute_.append(&c, &c + 1); 381 c = '0'; 382 } 383 if (c == '0' && (*cursor_ == 'x' || *cursor_ == 'X')) { 384 cursor_++; 385 while (isxdigit(static_cast<unsigned char>(*cursor_))) cursor_++; 386 attribute_.append(start + 2, cursor_); 387 attribute_ = NumToString(static_cast<int64_t>( 388 StringToUInt(attribute_.c_str(), nullptr, 16))); 389 token_ = kTokenIntegerConstant; 390 return NoError(); 391 } 392 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++; 393 if (*cursor_ == '.' || *cursor_ == 'e' || *cursor_ == 'E') { 394 if (*cursor_ == '.') { 395 cursor_++; 396 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++; 397 } 398 // See if this float has a scientific notation suffix. Both JSON 399 // and C++ (through strtod() we use) have the same format: 400 if (*cursor_ == 'e' || *cursor_ == 'E') { 401 cursor_++; 402 if (*cursor_ == '+' || *cursor_ == '-') cursor_++; 403 while (isdigit(static_cast<unsigned char>(*cursor_))) cursor_++; 404 } 405 token_ = kTokenFloatConstant; 406 } else { 407 token_ = kTokenIntegerConstant; 408 } 409 attribute_.append(start, cursor_); 410 return NoError(); 411 } 412 std::string ch; 413 ch = c; 414 if (c < ' ' || c > '~') ch = "code: " + NumToString(c); 415 return Error("illegal character: " + ch); 416 } 417 } 418 } 419 420 // Check if a given token is next. 421 bool Parser::Is(int t) { 422 return t == token_; 423 } 424 425 bool Parser::IsIdent(const char *id) { 426 return token_ == kTokenIdentifier && attribute_ == id; 427 } 428 429 // Expect a given token to be next, consume it, or error if not present. 430 CheckedError Parser::Expect(int t) { 431 if (t != token_) { 432 return Error("expecting: " + TokenToString(t) + " instead got: " + 433 TokenToStringId(token_)); 434 } 435 NEXT(); 436 return NoError(); 437 } 438 439 CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) { 440 while (Is('.')) { 441 NEXT(); 442 *id += "."; 443 *id += attribute_; 444 if (last) *last = attribute_; 445 EXPECT(kTokenIdentifier); 446 } 447 return NoError(); 448 } 449 450 EnumDef *Parser::LookupEnum(const std::string &id) { 451 // Search thru parent namespaces. 452 for (int components = static_cast<int>(current_namespace_->components.size()); 453 components >= 0; components--) { 454 auto ed = enums_.Lookup( 455 current_namespace_->GetFullyQualifiedName(id, components)); 456 if (ed) return ed; 457 } 458 return nullptr; 459 } 460 461 StructDef *Parser::LookupStruct(const std::string &id) const { 462 auto sd = structs_.Lookup(id); 463 if (sd) sd->refcount++; 464 return sd; 465 } 466 467 CheckedError Parser::ParseTypeIdent(Type &type) { 468 std::string id = attribute_; 469 EXPECT(kTokenIdentifier); 470 ECHECK(ParseNamespacing(&id, nullptr)); 471 auto enum_def = LookupEnum(id); 472 if (enum_def) { 473 type = enum_def->underlying_type; 474 if (enum_def->is_union) type.base_type = BASE_TYPE_UNION; 475 } else { 476 type.base_type = BASE_TYPE_STRUCT; 477 type.struct_def = LookupCreateStruct(id); 478 } 479 return NoError(); 480 } 481 482 // Parse any IDL type. 483 CheckedError Parser::ParseType(Type &type) { 484 if (token_ == kTokenIdentifier) { 485 if (IsIdent("bool")) { 486 type.base_type = BASE_TYPE_BOOL; 487 NEXT(); 488 } else if (IsIdent("byte") || IsIdent("int8")) { 489 type.base_type = BASE_TYPE_CHAR; 490 NEXT(); 491 } else if (IsIdent("ubyte") || IsIdent("uint8")) { 492 type.base_type = BASE_TYPE_UCHAR; 493 NEXT(); 494 } else if (IsIdent("short") || IsIdent("int16")) { 495 type.base_type = BASE_TYPE_SHORT; 496 NEXT(); 497 } else if (IsIdent("ushort") || IsIdent("uint16")) { 498 type.base_type = BASE_TYPE_USHORT; 499 NEXT(); 500 } else if (IsIdent("int") || IsIdent("int32")) { 501 type.base_type = BASE_TYPE_INT; 502 NEXT(); 503 } else if (IsIdent("uint") || IsIdent("uint32")) { 504 type.base_type = BASE_TYPE_UINT; 505 NEXT(); 506 } else if (IsIdent("long") || IsIdent("int64")) { 507 type.base_type = BASE_TYPE_LONG; 508 NEXT(); 509 } else if (IsIdent("ulong") || IsIdent("uint64")) { 510 type.base_type = BASE_TYPE_ULONG; 511 NEXT(); 512 } else if (IsIdent("float") || IsIdent("float32")) { 513 type.base_type = BASE_TYPE_FLOAT; 514 NEXT(); 515 } else if (IsIdent("double") || IsIdent("float64")) { 516 type.base_type = BASE_TYPE_DOUBLE; 517 NEXT(); 518 } else if (IsIdent("string")) { 519 type.base_type = BASE_TYPE_STRING; 520 NEXT(); 521 } else { 522 ECHECK(ParseTypeIdent(type)); 523 } 524 } else if (token_ == '[') { 525 NEXT(); 526 Type subtype; 527 ECHECK(ParseType(subtype)); 528 if (subtype.base_type == BASE_TYPE_VECTOR) { 529 // We could support this, but it will complicate things, and it's 530 // easier to work around with a struct around the inner vector. 531 return Error( 532 "nested vector types not supported (wrap in table first)."); 533 } 534 type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def); 535 type.element = subtype.base_type; 536 EXPECT(']'); 537 } else { 538 return Error("illegal type syntax"); 539 } 540 return NoError(); 541 } 542 543 CheckedError Parser::AddField(StructDef &struct_def, const std::string &name, 544 const Type &type, FieldDef **dest) { 545 auto &field = *new FieldDef(); 546 field.value.offset = 547 FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size())); 548 field.name = name; 549 field.file = struct_def.file; 550 field.value.type = type; 551 if (struct_def.fixed) { // statically compute the field offset 552 auto size = InlineSize(type); 553 auto alignment = InlineAlignment(type); 554 // structs_ need to have a predictable format, so we need to align to 555 // the largest scalar 556 struct_def.minalign = std::max(struct_def.minalign, alignment); 557 struct_def.PadLastField(alignment); 558 field.value.offset = static_cast<voffset_t>(struct_def.bytesize); 559 struct_def.bytesize += size; 560 } 561 if (struct_def.fields.Add(name, &field)) 562 return Error("field already exists: " + name); 563 *dest = &field; 564 return NoError(); 565 } 566 567 CheckedError Parser::ParseField(StructDef &struct_def) { 568 std::string name = attribute_; 569 570 if (LookupStruct(name)) 571 return Error("field name can not be the same as table/struct name"); 572 573 std::vector<std::string> dc = doc_comment_; 574 EXPECT(kTokenIdentifier); 575 EXPECT(':'); 576 Type type; 577 ECHECK(ParseType(type)); 578 579 if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type)) 580 return Error("structs_ may contain only scalar or struct fields"); 581 582 FieldDef *typefield = nullptr; 583 if (type.base_type == BASE_TYPE_UNION) { 584 // For union fields, add a second auto-generated field to hold the type, 585 // with a special suffix. 586 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), 587 type.enum_def->underlying_type, &typefield)); 588 } else if (type.base_type == BASE_TYPE_VECTOR && 589 type.element == BASE_TYPE_UNION) { 590 // Only cpp, js and ts supports the union vector feature so far. 591 if (!SupportsVectorOfUnions()) { 592 return Error("Vectors of unions are not yet supported in all " 593 "the specified programming languages."); 594 } 595 // For vector of union fields, add a second auto-generated vector field to 596 // hold the types, with a special suffix. 597 Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def); 598 union_vector.element = BASE_TYPE_UTYPE; 599 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), 600 union_vector, &typefield)); 601 } 602 603 FieldDef *field; 604 ECHECK(AddField(struct_def, name, type, &field)); 605 606 if (token_ == '=') { 607 NEXT(); 608 if (!IsScalar(type.base_type)) 609 return Error("default values currently only supported for scalars"); 610 ECHECK(ParseSingleValue(field->value)); 611 } 612 if (IsFloat(field->value.type.base_type)) { 613 if (!strpbrk(field->value.constant.c_str(), ".eE")) 614 field->value.constant += ".0"; 615 } 616 617 if (type.enum_def && 618 IsScalar(type.base_type) && 619 !struct_def.fixed && 620 !type.enum_def->attributes.Lookup("bit_flags") && 621 !type.enum_def->ReverseLookup(static_cast<int>( 622 StringToInt(field->value.constant.c_str())))) 623 Warning("enum " + type.enum_def->name + 624 " does not have a declaration for this field\'s default of " + 625 field->value.constant); 626 627 field->doc_comment = dc; 628 ECHECK(ParseMetaData(&field->attributes)); 629 field->deprecated = field->attributes.Lookup("deprecated") != nullptr; 630 auto hash_name = field->attributes.Lookup("hash"); 631 if (hash_name) { 632 switch (type.base_type) { 633 case BASE_TYPE_INT: 634 case BASE_TYPE_UINT: { 635 if (FindHashFunction32(hash_name->constant.c_str()) == nullptr) 636 return Error("Unknown hashing algorithm for 32 bit types: " + 637 hash_name->constant); 638 break; 639 } 640 case BASE_TYPE_LONG: 641 case BASE_TYPE_ULONG: { 642 if (FindHashFunction64(hash_name->constant.c_str()) == nullptr) 643 return Error("Unknown hashing algorithm for 64 bit types: " + 644 hash_name->constant); 645 break; 646 } 647 default: 648 return Error( 649 "only int, uint, long and ulong data types support hashing."); 650 } 651 } 652 auto cpp_type = field->attributes.Lookup("cpp_type"); 653 if (cpp_type) { 654 if (!hash_name) 655 return Error("cpp_type can only be used with a hashed field"); 656 } 657 if (field->deprecated && struct_def.fixed) 658 return Error("can't deprecate fields in a struct"); 659 field->required = field->attributes.Lookup("required") != nullptr; 660 if (field->required && (struct_def.fixed || 661 IsScalar(field->value.type.base_type))) 662 return Error("only non-scalar fields in tables may be 'required'"); 663 field->key = field->attributes.Lookup("key") != nullptr; 664 if (field->key) { 665 if (struct_def.has_key) 666 return Error("only one field may be set as 'key'"); 667 struct_def.has_key = true; 668 if (!IsScalar(field->value.type.base_type)) { 669 field->required = true; 670 if (field->value.type.base_type != BASE_TYPE_STRING) 671 return Error("'key' field must be string or scalar type"); 672 } 673 } 674 675 auto field_native_custom_alloc = field->attributes.Lookup("native_custom_alloc"); 676 if (field_native_custom_alloc) 677 return Error("native_custom_alloc can only be used with a table or struct definition"); 678 679 field->native_inline = field->attributes.Lookup("native_inline") != nullptr; 680 if (field->native_inline && !IsStruct(field->value.type)) 681 return Error("native_inline can only be defined on structs'"); 682 683 auto nested = field->attributes.Lookup("nested_flatbuffer"); 684 if (nested) { 685 if (nested->type.base_type != BASE_TYPE_STRING) 686 return Error( 687 "nested_flatbuffer attribute must be a string (the root type)"); 688 if (field->value.type.base_type != BASE_TYPE_VECTOR || 689 field->value.type.element != BASE_TYPE_UCHAR) 690 return Error( 691 "nested_flatbuffer attribute may only apply to a vector of ubyte"); 692 // This will cause an error if the root type of the nested flatbuffer 693 // wasn't defined elsewhere. 694 LookupCreateStruct(nested->constant); 695 696 // Keep a pointer to StructDef in FieldDef to simplify re-use later 697 auto nested_qualified_name = 698 current_namespace_->GetFullyQualifiedName(nested->constant); 699 field->nested_flatbuffer = LookupStruct(nested_qualified_name); 700 } 701 702 if (field->attributes.Lookup("flexbuffer")) { 703 field->flexbuffer = true; 704 uses_flexbuffers_ = true; 705 if (field->value.type.base_type != BASE_TYPE_VECTOR || 706 field->value.type.element != BASE_TYPE_UCHAR) 707 return Error( 708 "flexbuffer attribute may only apply to a vector of ubyte"); 709 } 710 711 if (typefield) { 712 if (!IsScalar(typefield->value.type.base_type)) { 713 // this is a union vector field 714 typefield->required = field->required; 715 } 716 // If this field is a union, and it has a manually assigned id, 717 // the automatically added type field should have an id as well (of N - 1). 718 auto attr = field->attributes.Lookup("id"); 719 if (attr) { 720 auto id = atoi(attr->constant.c_str()); 721 auto val = new Value(); 722 val->type = attr->type; 723 val->constant = NumToString(id - 1); 724 typefield->attributes.Add("id", val); 725 } 726 } 727 728 EXPECT(';'); 729 return NoError(); 730 } 731 732 CheckedError Parser::ParseString(Value &val) { 733 auto s = attribute_; 734 EXPECT(kTokenStringConstant); 735 val.constant = NumToString(builder_.CreateString(s).o); 736 return NoError(); 737 } 738 739 CheckedError Parser::ParseComma() { 740 if (!opts.protobuf_ascii_alike) EXPECT(','); 741 return NoError(); 742 } 743 744 CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field, 745 size_t parent_fieldn, 746 const StructDef *parent_struct_def) { 747 switch (val.type.base_type) { 748 case BASE_TYPE_UNION: { 749 assert(field); 750 std::string constant; 751 // Find corresponding type field we may have already parsed. 752 for (auto elem = field_stack_.rbegin(); 753 elem != field_stack_.rbegin() + parent_fieldn; ++elem) { 754 auto &type = elem->second->value.type; 755 if (type.base_type == BASE_TYPE_UTYPE && 756 type.enum_def == val.type.enum_def) { 757 constant = elem->first.constant; 758 break; 759 } 760 } 761 if (constant.empty()) { 762 // We haven't seen the type field yet. Sadly a lot of JSON writers 763 // output these in alphabetical order, meaning it comes after this 764 // value. So we scan past the value to find it, then come back here. 765 auto type_name = field->name + UnionTypeFieldSuffix(); 766 assert(parent_struct_def); 767 auto type_field = parent_struct_def->fields.Lookup(type_name); 768 assert(type_field); // Guaranteed by ParseField(). 769 // Remember where we are in the source file, so we can come back here. 770 auto backup = *static_cast<ParserState *>(this); 771 ECHECK(SkipAnyJsonValue()); // The table. 772 ECHECK(ParseComma()); 773 auto next_name = attribute_; 774 if (Is(kTokenStringConstant)) { 775 NEXT(); 776 } else { 777 EXPECT(kTokenIdentifier); 778 } 779 if (next_name != type_name) 780 return Error("missing type field after this union value: " + 781 type_name); 782 EXPECT(':'); 783 Value type_val = type_field->value; 784 ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr)); 785 constant = type_val.constant; 786 // Got the information we needed, now rewind: 787 *static_cast<ParserState *>(this) = backup; 788 } 789 uint8_t enum_idx; 790 ECHECK(atot(constant.c_str(), *this, &enum_idx)); 791 auto enum_val = val.type.enum_def->ReverseLookup(enum_idx); 792 if (!enum_val) return Error("illegal type id for: " + field->name); 793 if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) { 794 ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant, 795 nullptr)); 796 if (enum_val->union_type.struct_def->fixed) { 797 // All BASE_TYPE_UNION values are offsets, so turn this into one. 798 SerializeStruct(*enum_val->union_type.struct_def, val); 799 builder_.ClearOffsets(); 800 val.constant = NumToString(builder_.GetSize()); 801 } 802 } else if (enum_val->union_type.base_type == BASE_TYPE_STRING) { 803 ECHECK(ParseString(val)); 804 } else { 805 assert(false); 806 } 807 break; 808 } 809 case BASE_TYPE_STRUCT: 810 ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr)); 811 break; 812 case BASE_TYPE_STRING: { 813 ECHECK(ParseString(val)); 814 break; 815 } 816 case BASE_TYPE_VECTOR: { 817 uoffset_t off; 818 ECHECK(ParseVector(val.type.VectorType(), &off)); 819 val.constant = NumToString(off); 820 break; 821 } 822 case BASE_TYPE_INT: 823 case BASE_TYPE_UINT: 824 case BASE_TYPE_LONG: 825 case BASE_TYPE_ULONG: { 826 if (field && field->attributes.Lookup("hash") && 827 (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) { 828 ECHECK(ParseHash(val, field)); 829 } else { 830 ECHECK(ParseSingleValue(val)); 831 } 832 break; 833 } 834 default: 835 ECHECK(ParseSingleValue(val)); 836 break; 837 } 838 return NoError(); 839 } 840 841 void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) { 842 assert(val.constant.length() == struct_def.bytesize); 843 builder_.Align(struct_def.minalign); 844 builder_.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()), 845 struct_def.bytesize); 846 builder_.AddStructOffset(val.offset, builder_.GetSize()); 847 } 848 849 CheckedError Parser::ParseTableDelimiters(size_t &fieldn, 850 const StructDef *struct_def, 851 ParseTableDelimitersBody body, 852 void *state) { 853 // We allow tables both as JSON object{ .. } with field names 854 // or vector[..] with all fields in order 855 char terminator = '}'; 856 bool is_nested_vector = struct_def && Is('['); 857 if (is_nested_vector) { 858 NEXT(); 859 terminator = ']'; 860 } else { 861 EXPECT('{'); 862 } 863 for (;;) { 864 if ((!opts.strict_json || !fieldn) && Is(terminator)) break; 865 std::string name; 866 if (is_nested_vector) { 867 if (fieldn > struct_def->fields.vec.size()) { 868 return Error("too many unnamed fields in nested array"); 869 } 870 name = struct_def->fields.vec[fieldn]->name; 871 } else { 872 name = attribute_; 873 if (Is(kTokenStringConstant)) { 874 NEXT(); 875 } else { 876 EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); 877 } 878 if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':'); 879 } 880 ECHECK(body(name, fieldn, struct_def, state)); 881 if (Is(terminator)) break; 882 ECHECK(ParseComma()); 883 } 884 NEXT(); 885 if (is_nested_vector && fieldn != struct_def->fields.vec.size()) { 886 return Error("wrong number of unnamed fields in table vector"); 887 } 888 return NoError(); 889 } 890 891 CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, 892 uoffset_t *ovalue) { 893 size_t fieldn_outer = 0; 894 auto err = ParseTableDelimiters(fieldn_outer, &struct_def, 895 [](const std::string &name, size_t &fieldn, 896 const StructDef *struct_def_inner, 897 void *state) -> CheckedError { 898 Parser *parser = static_cast<Parser *>(state); 899 if (name == "$schema") { 900 ECHECK(parser->Expect(kTokenStringConstant)); 901 return NoError(); 902 } 903 auto field = struct_def_inner->fields.Lookup(name); 904 if (!field) { 905 if (!parser->opts.skip_unexpected_fields_in_json) { 906 return parser->Error("unknown field: " + name); 907 } else { 908 ECHECK(parser->SkipAnyJsonValue()); 909 } 910 } else { 911 if (parser->IsIdent("null")) { 912 ECHECK(parser->Next()); // Ignore this field. 913 } else { 914 Value val = field->value; 915 if (field->flexbuffer) { 916 flexbuffers::Builder builder(1024, 917 flexbuffers::BUILDER_FLAG_SHARE_ALL); 918 ECHECK(parser->ParseFlexBufferValue(&builder)); 919 builder.Finish(); 920 auto off = parser->builder_.CreateVector(builder.GetBuffer()); 921 val.constant = NumToString(off.o); 922 } else if (field->nested_flatbuffer) { 923 ECHECK(parser->ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner)); 924 } else { 925 ECHECK(parser->ParseAnyValue(val, field, fieldn, struct_def_inner)); 926 } 927 // Hardcoded insertion-sort with error-check. 928 // If fields are specified in order, then this loop exits immediately. 929 auto elem = parser->field_stack_.rbegin(); 930 for (; elem != parser->field_stack_.rbegin() + fieldn; ++elem) { 931 auto existing_field = elem->second; 932 if (existing_field == field) 933 return parser->Error("field set more than once: " + field->name); 934 if (existing_field->value.offset < field->value.offset) break; 935 } 936 // Note: elem points to before the insertion point, thus .base() points 937 // to the correct spot. 938 parser->field_stack_.insert(elem.base(), 939 std::make_pair(val, field)); 940 fieldn++; 941 } 942 } 943 return NoError(); 944 }, this); 945 ECHECK(err); 946 947 // Check if all required fields are parsed. 948 for (auto field_it = struct_def.fields.vec.begin(); 949 field_it != struct_def.fields.vec.end(); 950 ++field_it) { 951 auto required_field = *field_it; 952 if (!required_field->required) { 953 continue; 954 } 955 bool found = false; 956 for (auto pf_it = field_stack_.end() - fieldn_outer; 957 pf_it != field_stack_.end(); 958 ++pf_it) { 959 auto parsed_field = pf_it->second; 960 if (parsed_field == required_field) { 961 found = true; 962 break; 963 } 964 } 965 if (!found) { 966 return Error("required field is missing: " + required_field->name + " in " + struct_def.name); 967 } 968 } 969 970 if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size()) 971 return Error("struct: wrong number of initializers: " + struct_def.name); 972 973 auto start = struct_def.fixed 974 ? builder_.StartStruct(struct_def.minalign) 975 : builder_.StartTable(); 976 977 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; 978 size; 979 size /= 2) { 980 // Go through elements in reverse, since we're building the data backwards. 981 for (auto it = field_stack_.rbegin(); it != field_stack_.rbegin() + 982 fieldn_outer; 983 ++it) { 984 auto &field_value = it->first; 985 auto field = it->second; 986 if (!struct_def.sortbysize || 987 size == SizeOf(field_value.type.base_type)) { 988 switch (field_value.type.base_type) { 989 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ 990 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ 991 case BASE_TYPE_ ## ENUM: \ 992 builder_.Pad(field->padding); \ 993 if (struct_def.fixed) { \ 994 CTYPE val; \ 995 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \ 996 builder_.PushElement(val); \ 997 } else { \ 998 CTYPE val, valdef; \ 999 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \ 1000 ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \ 1001 builder_.AddElement(field_value.offset, val, valdef); \ 1002 } \ 1003 break; 1004 FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD); 1005 #undef FLATBUFFERS_TD 1006 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ 1007 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ 1008 case BASE_TYPE_ ## ENUM: \ 1009 builder_.Pad(field->padding); \ 1010 if (IsStruct(field->value.type)) { \ 1011 SerializeStruct(*field->value.type.struct_def, field_value); \ 1012 } else { \ 1013 CTYPE val; \ 1014 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \ 1015 builder_.AddOffset(field_value.offset, val); \ 1016 } \ 1017 break; 1018 FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD); 1019 #undef FLATBUFFERS_TD 1020 } 1021 } 1022 } 1023 } 1024 for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back(); 1025 1026 if (struct_def.fixed) { 1027 builder_.ClearOffsets(); 1028 builder_.EndStruct(); 1029 assert(value); 1030 // Temporarily store this struct in the value string, since it is to 1031 // be serialized in-place elsewhere. 1032 value->assign( 1033 reinterpret_cast<const char *>(builder_.GetCurrentBufferPointer()), 1034 struct_def.bytesize); 1035 builder_.PopBytes(struct_def.bytesize); 1036 assert(!ovalue); 1037 } else { 1038 auto val = builder_.EndTable(start); 1039 if (ovalue) *ovalue = val; 1040 if (value) *value = NumToString(val); 1041 } 1042 return NoError(); 1043 } 1044 1045 CheckedError Parser::ParseVectorDelimiters(size_t &count, 1046 ParseVectorDelimitersBody body, 1047 void *state) { 1048 EXPECT('['); 1049 for (;;) { 1050 if ((!opts.strict_json || !count) && Is(']')) break; 1051 ECHECK(body(count, state)); 1052 count++; 1053 if (Is(']')) break; 1054 ECHECK(ParseComma()); 1055 } 1056 NEXT(); 1057 return NoError(); 1058 } 1059 1060 CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) { 1061 size_t count = 0; 1062 std::pair<Parser *, const Type &> parser_and_type_state(this, type); 1063 auto err = ParseVectorDelimiters(count, 1064 [](size_t &, void *state) -> CheckedError { 1065 auto *parser_and_type = 1066 static_cast<std::pair<Parser *, const Type &> *>(state); 1067 auto *parser = parser_and_type->first; 1068 Value val; 1069 val.type = parser_and_type->second; 1070 ECHECK(parser->ParseAnyValue(val, nullptr, 0, nullptr)); 1071 parser->field_stack_.push_back(std::make_pair(val, nullptr)); 1072 return NoError(); 1073 }, &parser_and_type_state); 1074 ECHECK(err); 1075 1076 builder_.StartVector(count * InlineSize(type) / InlineAlignment(type), 1077 InlineAlignment(type)); 1078 for (size_t i = 0; i < count; i++) { 1079 // start at the back, since we're building the data backwards. 1080 auto &val = field_stack_.back().first; 1081 switch (val.type.base_type) { 1082 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ 1083 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ 1084 case BASE_TYPE_ ## ENUM: \ 1085 if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \ 1086 else { \ 1087 CTYPE elem; \ 1088 ECHECK(atot(val.constant.c_str(), *this, &elem)); \ 1089 builder_.PushElement(elem); \ 1090 } \ 1091 break; 1092 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) 1093 #undef FLATBUFFERS_TD 1094 } 1095 field_stack_.pop_back(); 1096 } 1097 1098 builder_.ClearOffsets(); 1099 *ovalue = builder_.EndVector(count); 1100 return NoError(); 1101 } 1102 1103 CheckedError Parser::ParseNestedFlatbuffer(Value &val, FieldDef *field, 1104 size_t fieldn, 1105 const StructDef *parent_struct_def) { 1106 if (token_ == '[') {// backwards compat for 'legacy' ubyte buffers 1107 ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def)); 1108 } else { 1109 auto cursor_at_value_begin = cursor_; 1110 ECHECK(SkipAnyJsonValue()); 1111 std::string substring(cursor_at_value_begin -1 , cursor_ -1); 1112 1113 // Create and initialize new parser 1114 Parser nested_parser; 1115 assert(field->nested_flatbuffer); 1116 nested_parser.root_struct_def_ = field->nested_flatbuffer; 1117 nested_parser.enums_ = enums_; 1118 nested_parser.opts = opts; 1119 nested_parser.uses_flexbuffers_ = uses_flexbuffers_; 1120 1121 // Parse JSON substring into new flatbuffer builder using nested_parser 1122 if (!nested_parser.Parse(substring.c_str(), nullptr, nullptr)) { 1123 ECHECK(Error(nested_parser.error_)); 1124 } 1125 auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(), nested_parser.builder_.GetSize()); 1126 val.constant = NumToString(off.o); 1127 1128 // Clean nested_parser before destruction to avoid deleting the elements in the SymbolTables 1129 nested_parser.enums_.dict.clear(); 1130 nested_parser.enums_.vec.clear(); 1131 } 1132 return NoError(); 1133 } 1134 1135 CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) { 1136 if (Is('(')) { 1137 NEXT(); 1138 for (;;) { 1139 auto name = attribute_; 1140 EXPECT(kTokenIdentifier); 1141 if (known_attributes_.find(name) == known_attributes_.end()) 1142 return Error("user define attributes must be declared before use: " + 1143 name); 1144 auto e = new Value(); 1145 attributes->Add(name, e); 1146 if (Is(':')) { 1147 NEXT(); 1148 ECHECK(ParseSingleValue(*e)); 1149 } 1150 if (Is(')')) { NEXT(); break; } 1151 EXPECT(','); 1152 } 1153 } 1154 return NoError(); 1155 } 1156 1157 CheckedError Parser::TryTypedValue(int dtoken, bool check, Value &e, 1158 BaseType req, bool *destmatch) { 1159 bool match = dtoken == token_; 1160 if (match) { 1161 *destmatch = true; 1162 e.constant = attribute_; 1163 if (!check) { 1164 if (e.type.base_type == BASE_TYPE_NONE) { 1165 e.type.base_type = req; 1166 } else { 1167 return Error(std::string("type mismatch: expecting: ") + 1168 kTypeNames[e.type.base_type] + 1169 ", found: " + 1170 kTypeNames[req]); 1171 } 1172 } 1173 NEXT(); 1174 } 1175 return NoError(); 1176 } 1177 1178 CheckedError Parser::ParseEnumFromString(Type &type, int64_t *result) { 1179 *result = 0; 1180 // Parse one or more enum identifiers, separated by spaces. 1181 const char *next = attribute_.c_str(); 1182 do { 1183 const char *divider = strchr(next, ' '); 1184 std::string word; 1185 if (divider) { 1186 word = std::string(next, divider); 1187 next = divider + strspn(divider, " "); 1188 } else { 1189 word = next; 1190 next += word.length(); 1191 } 1192 if (type.enum_def) { // The field has an enum type 1193 auto enum_val = type.enum_def->vals.Lookup(word); 1194 if (!enum_val) 1195 return Error("unknown enum value: " + word + 1196 ", for enum: " + type.enum_def->name); 1197 *result |= enum_val->value; 1198 } else { // No enum type, probably integral field. 1199 if (!IsInteger(type.base_type)) 1200 return Error("not a valid value for this field: " + word); 1201 // TODO: could check if its a valid number constant here. 1202 const char *dot = strrchr(word.c_str(), '.'); 1203 if (!dot) 1204 return Error("enum values need to be qualified by an enum type"); 1205 std::string enum_def_str(word.c_str(), dot); 1206 std::string enum_val_str(dot + 1, word.c_str() + word.length()); 1207 auto enum_def = LookupEnum(enum_def_str); 1208 if (!enum_def) return Error("unknown enum: " + enum_def_str); 1209 auto enum_val = enum_def->vals.Lookup(enum_val_str); 1210 if (!enum_val) return Error("unknown enum value: " + enum_val_str); 1211 *result |= enum_val->value; 1212 } 1213 } while(*next); 1214 return NoError(); 1215 } 1216 1217 1218 CheckedError Parser::ParseHash(Value &e, FieldDef* field) { 1219 assert(field); 1220 Value *hash_name = field->attributes.Lookup("hash"); 1221 switch (e.type.base_type) { 1222 case BASE_TYPE_INT: { 1223 auto hash = FindHashFunction32(hash_name->constant.c_str()); 1224 int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str())); 1225 e.constant = NumToString(hashed_value); 1226 break; 1227 } 1228 case BASE_TYPE_UINT: { 1229 auto hash = FindHashFunction32(hash_name->constant.c_str()); 1230 uint32_t hashed_value = hash(attribute_.c_str()); 1231 e.constant = NumToString(hashed_value); 1232 break; 1233 } 1234 case BASE_TYPE_LONG: { 1235 auto hash = FindHashFunction64(hash_name->constant.c_str()); 1236 int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str())); 1237 e.constant = NumToString(hashed_value); 1238 break; 1239 } 1240 case BASE_TYPE_ULONG: { 1241 auto hash = FindHashFunction64(hash_name->constant.c_str()); 1242 uint64_t hashed_value = hash(attribute_.c_str()); 1243 e.constant = NumToString(hashed_value); 1244 break; 1245 } 1246 default: 1247 assert(0); 1248 } 1249 NEXT(); 1250 return NoError(); 1251 } 1252 1253 CheckedError Parser::TokenError() { 1254 return Error("cannot parse value starting with: " + 1255 TokenToStringId(token_)); 1256 } 1257 1258 CheckedError Parser::ParseSingleValue(Value &e) { 1259 // First see if this could be a conversion function: 1260 if (token_ == kTokenIdentifier && *cursor_ == '(') { 1261 auto functionname = attribute_; 1262 NEXT(); 1263 EXPECT('('); 1264 ECHECK(ParseSingleValue(e)); 1265 EXPECT(')'); 1266 #define FLATBUFFERS_FN_DOUBLE(name, op) \ 1267 if (functionname == name) { \ 1268 auto x = strtod(e.constant.c_str(), nullptr); \ 1269 e.constant = NumToString(op); \ 1270 } 1271 FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180); 1272 FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180); 1273 FLATBUFFERS_FN_DOUBLE("sin", sin(x)); 1274 FLATBUFFERS_FN_DOUBLE("cos", cos(x)); 1275 FLATBUFFERS_FN_DOUBLE("tan", tan(x)); 1276 FLATBUFFERS_FN_DOUBLE("asin", asin(x)); 1277 FLATBUFFERS_FN_DOUBLE("acos", acos(x)); 1278 FLATBUFFERS_FN_DOUBLE("atan", atan(x)); 1279 // TODO(wvo): add more useful conversion functions here. 1280 #undef FLATBUFFERS_FN_DOUBLE 1281 // Then check if this could be a string/identifier enum value: 1282 } else if (e.type.base_type != BASE_TYPE_STRING && 1283 e.type.base_type != BASE_TYPE_BOOL && 1284 e.type.base_type != BASE_TYPE_NONE && 1285 (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) { 1286 if (IsIdentifierStart(attribute_[0])) { // Enum value. 1287 int64_t val; 1288 ECHECK(ParseEnumFromString(e.type, &val)); 1289 e.constant = NumToString(val); 1290 NEXT(); 1291 } else { // Numeric constant in string. 1292 if (IsInteger(e.type.base_type)) { 1293 char *end; 1294 e.constant = NumToString(StringToInt(attribute_.c_str(), &end)); 1295 if (*end) 1296 return Error("invalid integer: " + attribute_); 1297 } else if (IsFloat(e.type.base_type)) { 1298 char *end; 1299 e.constant = NumToString(strtod(attribute_.c_str(), &end)); 1300 if (*end) 1301 return Error("invalid float: " + attribute_); 1302 } else { 1303 assert(0); // Shouldn't happen, we covered all types. 1304 e.constant = "0"; 1305 } 1306 NEXT(); 1307 } 1308 } else { 1309 bool match = false; 1310 ECHECK(TryTypedValue(kTokenIntegerConstant, 1311 IsScalar(e.type.base_type), 1312 e, 1313 BASE_TYPE_INT, 1314 &match)); 1315 ECHECK(TryTypedValue(kTokenFloatConstant, 1316 IsFloat(e.type.base_type), 1317 e, 1318 BASE_TYPE_FLOAT, 1319 &match)); 1320 ECHECK(TryTypedValue(kTokenStringConstant, 1321 e.type.base_type == BASE_TYPE_STRING, 1322 e, 1323 BASE_TYPE_STRING, 1324 &match)); 1325 auto istrue = IsIdent("true"); 1326 if (istrue || IsIdent("false")) { 1327 attribute_ = NumToString(istrue); 1328 ECHECK(TryTypedValue(kTokenIdentifier, 1329 IsBool(e.type.base_type), 1330 e, 1331 BASE_TYPE_BOOL, 1332 &match)); 1333 } 1334 if (!match) return TokenError(); 1335 } 1336 return NoError(); 1337 } 1338 1339 StructDef *Parser::LookupCreateStruct(const std::string &name, 1340 bool create_if_new, bool definition) { 1341 std::string qualified_name = current_namespace_->GetFullyQualifiedName(name); 1342 // See if it exists pre-declared by an unqualified use. 1343 auto struct_def = LookupStruct(name); 1344 if (struct_def && struct_def->predecl) { 1345 if (definition) { 1346 // Make sure it has the current namespace, and is registered under its 1347 // qualified name. 1348 struct_def->defined_namespace = current_namespace_; 1349 structs_.Move(name, qualified_name); 1350 } 1351 return struct_def; 1352 } 1353 // See if it exists pre-declared by an qualified use. 1354 struct_def = LookupStruct(qualified_name); 1355 if (struct_def && struct_def->predecl) { 1356 if (definition) { 1357 // Make sure it has the current namespace. 1358 struct_def->defined_namespace = current_namespace_; 1359 } 1360 return struct_def; 1361 } 1362 if (!definition) { 1363 // Search thru parent namespaces. 1364 for (size_t components = current_namespace_->components.size(); 1365 components && !struct_def; components--) { 1366 struct_def = LookupStruct( 1367 current_namespace_->GetFullyQualifiedName(name, components - 1)); 1368 } 1369 } 1370 if (!struct_def && create_if_new) { 1371 struct_def = new StructDef(); 1372 if (definition) { 1373 structs_.Add(qualified_name, struct_def); 1374 struct_def->name = name; 1375 struct_def->defined_namespace = current_namespace_; 1376 } else { 1377 // Not a definition. 1378 // Rather than failing, we create a "pre declared" StructDef, due to 1379 // circular references, and check for errors at the end of parsing. 1380 // It is defined in the current namespace, as the best guess what the 1381 // final namespace will be. 1382 structs_.Add(name, struct_def); 1383 struct_def->name = name; 1384 struct_def->defined_namespace = current_namespace_; 1385 struct_def->original_location.reset(new std::string(file_being_parsed_ + 1386 ":" + NumToString(line_))); 1387 } 1388 } 1389 return struct_def; 1390 } 1391 1392 CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) { 1393 std::vector<std::string> enum_comment = doc_comment_; 1394 NEXT(); 1395 std::string enum_name = attribute_; 1396 EXPECT(kTokenIdentifier); 1397 auto &enum_def = *new EnumDef(); 1398 enum_def.name = enum_name; 1399 enum_def.file = file_being_parsed_; 1400 enum_def.doc_comment = enum_comment; 1401 enum_def.is_union = is_union; 1402 enum_def.defined_namespace = current_namespace_; 1403 if (enums_.Add(current_namespace_->GetFullyQualifiedName(enum_name), 1404 &enum_def)) 1405 return Error("enum already exists: " + enum_name); 1406 if (is_union) { 1407 enum_def.underlying_type.base_type = BASE_TYPE_UTYPE; 1408 enum_def.underlying_type.enum_def = &enum_def; 1409 } else { 1410 if (opts.proto_mode) { 1411 enum_def.underlying_type.base_type = BASE_TYPE_INT; 1412 } else { 1413 // Give specialized error message, since this type spec used to 1414 // be optional in the first FlatBuffers release. 1415 if (!Is(':')) { 1416 return Error("must specify the underlying integer type for this" 1417 " enum (e.g. \': short\', which was the default)."); 1418 } else { 1419 NEXT(); 1420 } 1421 // Specify the integer type underlying this enum. 1422 ECHECK(ParseType(enum_def.underlying_type)); 1423 if (!IsInteger(enum_def.underlying_type.base_type)) 1424 return Error("underlying enum type must be integral"); 1425 } 1426 // Make this type refer back to the enum it was derived from. 1427 enum_def.underlying_type.enum_def = &enum_def; 1428 } 1429 ECHECK(ParseMetaData(&enum_def.attributes)); 1430 EXPECT('{'); 1431 if (is_union) enum_def.vals.Add("NONE", new EnumVal("NONE", 0)); 1432 for (;;) { 1433 if (opts.proto_mode && attribute_ == "option") { 1434 ECHECK(ParseProtoOption()); 1435 } else { 1436 auto value_name = attribute_; 1437 auto full_name = value_name; 1438 std::vector<std::string> value_comment = doc_comment_; 1439 EXPECT(kTokenIdentifier); 1440 if (is_union) { 1441 ECHECK(ParseNamespacing(&full_name, &value_name)); 1442 if (opts.union_value_namespacing) { 1443 // Since we can't namespace the actual enum identifiers, turn 1444 // namespace parts into part of the identifier. 1445 value_name = full_name; 1446 std::replace(value_name.begin(), value_name.end(), '.', '_'); 1447 } 1448 } 1449 auto prevsize = enum_def.vals.vec.size(); 1450 auto value = enum_def.vals.vec.size() 1451 ? enum_def.vals.vec.back()->value + 1 1452 : 0; 1453 auto &ev = *new EnumVal(value_name, value); 1454 if (enum_def.vals.Add(value_name, &ev)) 1455 return Error("enum value already exists: " + value_name); 1456 ev.doc_comment = value_comment; 1457 if (is_union) { 1458 if (Is(':')) { 1459 NEXT(); 1460 ECHECK(ParseType(ev.union_type)); 1461 if (ev.union_type.base_type != BASE_TYPE_STRUCT && 1462 ev.union_type.base_type != BASE_TYPE_STRING) 1463 return Error("union value type may only be table/struct/string"); 1464 enum_def.uses_type_aliases = true; 1465 } else { 1466 ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name)); 1467 } 1468 } 1469 if (Is('=')) { 1470 NEXT(); 1471 ev.value = StringToInt(attribute_.c_str()); 1472 EXPECT(kTokenIntegerConstant); 1473 if (!opts.proto_mode && prevsize && 1474 enum_def.vals.vec[prevsize - 1]->value >= ev.value) 1475 return Error("enum values must be specified in ascending order"); 1476 } 1477 if (is_union) { 1478 if (ev.value < 0 || ev.value >= 256) 1479 return Error("union enum value must fit in a ubyte"); 1480 } 1481 if (opts.proto_mode && Is('[')) { 1482 NEXT(); 1483 // ignore attributes on enums. 1484 while (token_ != ']') NEXT(); 1485 NEXT(); 1486 } 1487 } 1488 if (!Is(opts.proto_mode ? ';' : ',')) break; 1489 NEXT(); 1490 if (Is('}')) break; 1491 } 1492 EXPECT('}'); 1493 if (enum_def.attributes.Lookup("bit_flags")) { 1494 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); 1495 ++it) { 1496 if (static_cast<size_t>((*it)->value) >= 1497 SizeOf(enum_def.underlying_type.base_type) * 8) 1498 return Error("bit flag out of range of underlying integral type"); 1499 (*it)->value = 1LL << (*it)->value; 1500 } 1501 } 1502 if (dest) *dest = &enum_def; 1503 types_.Add(current_namespace_->GetFullyQualifiedName(enum_def.name), 1504 new Type(BASE_TYPE_UNION, nullptr, &enum_def)); 1505 return NoError(); 1506 } 1507 1508 CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) { 1509 auto &struct_def = *LookupCreateStruct(name, true, true); 1510 if (!struct_def.predecl) return Error("datatype already exists: " + name); 1511 struct_def.predecl = false; 1512 struct_def.name = name; 1513 struct_def.file = file_being_parsed_; 1514 // Move this struct to the back of the vector just in case it was predeclared, 1515 // to preserve declaration order. 1516 *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def; 1517 *dest = &struct_def; 1518 return NoError(); 1519 } 1520 1521 CheckedError Parser::CheckClash(std::vector<FieldDef*> &fields, 1522 StructDef *struct_def, 1523 const char *suffix, 1524 BaseType basetype) { 1525 auto len = strlen(suffix); 1526 for (auto it = fields.begin(); it != fields.end(); ++it) { 1527 auto &fname = (*it)->name; 1528 if (fname.length() > len && 1529 fname.compare(fname.length() - len, len, suffix) == 0 && 1530 (*it)->value.type.base_type != BASE_TYPE_UTYPE) { 1531 auto field = struct_def->fields.Lookup( 1532 fname.substr(0, fname.length() - len)); 1533 if (field && field->value.type.base_type == basetype) 1534 return Error("Field " + fname + 1535 " would clash with generated functions for field " + 1536 field->name); 1537 } 1538 } 1539 return NoError(); 1540 } 1541 1542 bool Parser::SupportsVectorOfUnions() const { 1543 return opts.lang_to_generate != 0 && (opts.lang_to_generate & 1544 ~(IDLOptions::kCpp | IDLOptions::kJs | IDLOptions::kTs | IDLOptions::kPhp)) == 0; 1545 } 1546 1547 Namespace *Parser::UniqueNamespace(Namespace *ns) { 1548 for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) { 1549 if (ns->components == (*it)->components) { 1550 delete ns; 1551 return *it; 1552 } 1553 } 1554 namespaces_.push_back(ns); 1555 return ns; 1556 } 1557 1558 static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) { 1559 auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str()); 1560 auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str()); 1561 return a_id < b_id; 1562 } 1563 1564 CheckedError Parser::ParseDecl() { 1565 std::vector<std::string> dc = doc_comment_; 1566 bool fixed = IsIdent("struct"); 1567 if (!fixed && !IsIdent("table")) return Error("declaration expected"); 1568 NEXT(); 1569 std::string name = attribute_; 1570 EXPECT(kTokenIdentifier); 1571 StructDef *struct_def; 1572 ECHECK(StartStruct(name, &struct_def)); 1573 struct_def->doc_comment = dc; 1574 struct_def->fixed = fixed; 1575 ECHECK(ParseMetaData(&struct_def->attributes)); 1576 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"); 1581 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 || 1584 align < struct_def->minalign || 1585 align > FLATBUFFERS_MAX_ALIGNMENT || 1586 align & (align - 1)) 1587 return Error("force_align must be a power of two integer ranging from the" 1588 "struct\'s natural alignment to " + 1589 NumToString(FLATBUFFERS_MAX_ALIGNMENT)); 1590 struct_def->minalign = align; 1591 } 1592 struct_def->PadLastField(struct_def->minalign); 1593 // Check if this is a table that has manual id assignments 1594 auto &fields = struct_def->fields.vec; 1595 if (!struct_def->fixed && fields.size()) { 1596 size_t num_id_fields = 0; 1597 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()) 1604 return Error( 1605 "either all fields or no fields must have an 'id' attribute"); 1606 // Simply sort by id, then the fields are the same as if no ids had 1607 // been specified. 1608 std::sort(fields.begin(), fields.end(), compareFieldDefs); 1609 // 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())) 1612 return Error("field id\'s must be consecutive from 0, id " + 1613 NumToString(i) + " missing or set twice"); 1614 fields[i]->value.offset = FieldIndexToOffset(static_cast<voffset_t>(i)); 1615 } 1616 } 1617 } 1618 1619 ECHECK(CheckClash(fields, struct_def, UnionTypeFieldSuffix(), 1620 BASE_TYPE_UNION)); 1621 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)); 1626 EXPECT('}'); 1627 types_.Add(current_namespace_->GetFullyQualifiedName(struct_def->name), 1628 new Type(BASE_TYPE_STRUCT, struct_def, nullptr)); 1629 return NoError(); 1630 } 1631 1632 CheckedError 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 = current_namespace_; 1642 if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name), 1643 &service_def)) 1644 return Error("service already exists: " + service_name); 1645 ECHECK(ParseMetaData(&service_def.attributes)); 1646 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); 1665 ECHECK(ParseMetaData(&rpc.attributes)); 1666 EXPECT(';'); 1667 } while (token_ != '}'); 1668 NEXT(); 1669 return NoError(); 1670 } 1671 1672 bool Parser::SetRootType(const char *name) { 1673 root_struct_def_ = LookupStruct(name); 1674 if (!root_struct_def_) 1675 root_struct_def_ = LookupStruct( 1676 current_namespace_->GetFullyQualifiedName(name)); 1677 return root_struct_def_ != nullptr; 1678 } 1679 1680 void Parser::MarkGenerated() { 1681 // This function marks all existing definitions as having already 1682 // been generated, which signals no code for included files should be 1683 // generated. 1684 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) { 1690 if (!(*it)->predecl) { 1691 (*it)->generated = true; 1692 } 1693 } 1694 for (auto it = services_.vec.begin(); 1695 it != services_.vec.end(); ++it) { 1696 (*it)->generated = true; 1697 } 1698 } 1699 1700 CheckedError Parser::ParseNamespace() { 1701 NEXT(); 1702 auto ns = new Namespace(); 1703 namespaces_.push_back(ns); // Store it here to not leak upon error. 1704 if (token_ != ';') { 1705 for (;;) { 1706 ns->components.push_back(attribute_); 1707 EXPECT(kTokenIdentifier); 1708 if (Is('.')) NEXT() else break; 1709 } 1710 } 1711 namespaces_.pop_back(); 1712 current_namespace_ = UniqueNamespace(ns); 1713 EXPECT(';'); 1714 return NoError(); 1715 } 1716 1717 static bool compareEnumVals(const EnumVal *a, const EnumVal* b) { 1718 return a->value < b->value; 1719 } 1720 1721 // Best effort parsing of .proto declarations, with the aim to turn them 1722 // in the closest corresponding FlatBuffer equivalent. 1723 // We parse everything as identifiers instead of keywords, since we don't 1724 // want protobuf keywords to become invalid identifiers in FlatBuffers. 1725 CheckedError Parser::ParseProtoDecl() { 1726 bool isextend = IsIdent("extend"); 1727 if (IsIdent("package")) { 1728 // These are identical in syntax to FlatBuffer's namespace decl. 1729 ECHECK(ParseNamespace()); 1730 } else if (IsIdent("message") || isextend) { 1731 std::vector<std::string> struct_comment = doc_comment_; 1732 NEXT(); 1733 StructDef *struct_def = nullptr; 1734 Namespace *parent_namespace = nullptr; 1735 if (isextend) { 1736 if (Is('.')) NEXT(); // qualified names may start with a . ? 1737 auto id = attribute_; 1738 EXPECT(kTokenIdentifier); 1739 ECHECK(ParseNamespacing(&id, nullptr)); 1740 struct_def = LookupCreateStruct(id, false); 1741 if (!struct_def) 1742 return Error("cannot extend unknown message type: " + id); 1743 } else { 1744 std::string name = attribute_; 1745 EXPECT(kTokenIdentifier); 1746 ECHECK(StartStruct(name, &struct_def)); 1747 // Since message definitions can be nested, we create a new namespace. 1748 auto ns = new Namespace(); 1749 // Copy of current namespace. 1750 *ns = *current_namespace_; 1751 // But with current message name. 1752 ns->components.push_back(name); 1753 ns->from_table++; 1754 parent_namespace = current_namespace_; 1755 current_namespace_ = UniqueNamespace(ns); 1756 } 1757 struct_def->doc_comment = struct_comment; 1758 ECHECK(ParseProtoFields(struct_def, isextend, false)); 1759 if (!isextend) { 1760 current_namespace_ = parent_namespace; 1761 } 1762 if (Is(';')) NEXT(); 1763 } else if (IsIdent("enum")) { 1764 // These are almost the same, just with different terminator: 1765 EnumDef *enum_def; 1766 ECHECK(ParseEnum(false, &enum_def)); 1767 if (Is(';')) NEXT(); 1768 // Protobuf allows them to be specified in any order, so sort afterwards. 1769 auto &v = enum_def->vals.vec; 1770 std::sort(v.begin(), v.end(), compareEnumVals); 1771 1772 // Temp: remove any duplicates, as .fbs files can't handle them. 1773 for (auto it = v.begin(); it != v.end(); ) { 1774 if (it != v.begin() && it[0]->value == it[-1]->value) it = v.erase(it); 1775 else ++it; 1776 } 1777 } else if (IsIdent("syntax")) { // Skip these. 1778 NEXT(); 1779 EXPECT('='); 1780 EXPECT(kTokenStringConstant); 1781 EXPECT(';'); 1782 } else if (IsIdent("option")) { // Skip these. 1783 ECHECK(ParseProtoOption()); 1784 EXPECT(';'); 1785 } else if (IsIdent("service")) { // Skip these. 1786 NEXT(); 1787 EXPECT(kTokenIdentifier); 1788 ECHECK(ParseProtoCurliesOrIdent()); 1789 } else { 1790 return Error("don\'t know how to parse .proto declaration starting with " + 1791 TokenToStringId(token_)); 1792 } 1793 return NoError(); 1794 } 1795 1796 CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend, 1797 bool inside_oneof) { 1798 EXPECT('{'); 1799 while (token_ != '}') { 1800 if (IsIdent("message") || IsIdent("extend") || IsIdent("enum")) { 1801 // Nested declarations. 1802 ECHECK(ParseProtoDecl()); 1803 } else if (IsIdent("extensions")) { // Skip these. 1804 NEXT(); 1805 EXPECT(kTokenIntegerConstant); 1806 if (Is(kTokenIdentifier)) { 1807 NEXT(); // to 1808 NEXT(); // num 1809 } 1810 EXPECT(';'); 1811 } else if (IsIdent("option")) { // Skip these. 1812 ECHECK(ParseProtoOption()); 1813 EXPECT(';'); 1814 } else if (IsIdent("reserved")) { // Skip these. 1815 NEXT(); 1816 while (!Is(';')) { NEXT(); } // A variety of formats, just skip. 1817 NEXT(); 1818 } else { 1819 std::vector<std::string> field_comment = doc_comment_; 1820 // Parse the qualifier. 1821 bool required = false; 1822 bool repeated = false; 1823 bool oneof = false; 1824 if (!inside_oneof) { 1825 if (IsIdent("optional")) { 1826 // This is the default. 1827 NEXT(); 1828 } else if (IsIdent("required")) { 1829 required = true; 1830 NEXT(); 1831 } else if (IsIdent("repeated")) { 1832 repeated = true; 1833 NEXT(); 1834 } else if (IsIdent("oneof")) { 1835 oneof = true; 1836 NEXT(); 1837 } else { 1838 // can't error, proto3 allows decls without any of the above. 1839 } 1840 } 1841 StructDef *anonymous_struct = nullptr; 1842 Type type; 1843 if (IsIdent("group") || oneof) { 1844 if (!oneof) NEXT(); 1845 auto name = "Anonymous" + NumToString(anonymous_counter++); 1846 ECHECK(StartStruct(name, &anonymous_struct)); 1847 type = Type(BASE_TYPE_STRUCT, anonymous_struct); 1848 } else { 1849 ECHECK(ParseTypeFromProtoType(&type)); 1850 } 1851 // Repeated elements get mapped to a vector. 1852 if (repeated) { 1853 type.element = type.base_type; 1854 type.base_type = BASE_TYPE_VECTOR; 1855 if (type.element == BASE_TYPE_VECTOR) { 1856 // We have a vector or vectors, which FlatBuffers doesn't support. 1857 // For now make it a vector of string (since the source is likely 1858 // "repeated bytes"). 1859 // TODO(wvo): A better solution would be to wrap this in a table. 1860 type.element = BASE_TYPE_STRING; 1861 } 1862 } 1863 std::string name = attribute_; 1864 EXPECT(kTokenIdentifier); 1865 if (!oneof) { 1866 // Parse the field id. Since we're just translating schemas, not 1867 // any kind of binary compatibility, we can safely ignore these, and 1868 // assign our own. 1869 EXPECT('='); 1870 EXPECT(kTokenIntegerConstant); 1871 } 1872 FieldDef *field = nullptr; 1873 if (isextend) { 1874 // We allow a field to be re-defined when extending. 1875 // TODO: are there situations where that is problematic? 1876 field = struct_def->fields.Lookup(name); 1877 } 1878 if (!field) ECHECK(AddField(*struct_def, name, type, &field)); 1879 field->doc_comment = field_comment; 1880 if (!IsScalar(type.base_type)) field->required = required; 1881 // See if there's a default specified. 1882 if (Is('[')) { 1883 NEXT(); 1884 for (;;) { 1885 auto key = attribute_; 1886 ECHECK(ParseProtoKey()); 1887 EXPECT('='); 1888 auto val = attribute_; 1889 ECHECK(ParseProtoCurliesOrIdent()); 1890 if (key == "default") { 1891 // Temp: skip non-numeric defaults (enums). 1892 auto numeric = strpbrk(val.c_str(), "0123456789-+."); 1893 if (IsScalar(type.base_type) && numeric == val.c_str()) 1894 field->value.constant = val; 1895 } else if (key == "deprecated") { 1896 field->deprecated = val == "true"; 1897 } 1898 if (!Is(',')) break; 1899 NEXT(); 1900 } 1901 EXPECT(']'); 1902 } 1903 if (anonymous_struct) { 1904 ECHECK(ParseProtoFields(anonymous_struct, false, oneof)); 1905 if (Is(';')) NEXT(); 1906 } else { 1907 EXPECT(';'); 1908 } 1909 } 1910 } 1911 NEXT(); 1912 return NoError(); 1913 } 1914 1915 CheckedError Parser::ParseProtoKey() { 1916 if (token_ == '(') { 1917 NEXT(); 1918 // Skip "(a.b)" style custom attributes. 1919 while (token_ == '.' || token_ == kTokenIdentifier) NEXT(); 1920 EXPECT(')'); 1921 while (Is('.')) { NEXT(); EXPECT(kTokenIdentifier); } 1922 } else { 1923 EXPECT(kTokenIdentifier); 1924 } 1925 return NoError(); 1926 } 1927 1928 CheckedError Parser::ParseProtoCurliesOrIdent() { 1929 if (Is('{')) { 1930 NEXT(); 1931 for (int nesting = 1; nesting; ) { 1932 if (token_ == '{') nesting++; 1933 else if (token_ == '}') nesting--; 1934 NEXT(); 1935 } 1936 } else { 1937 NEXT(); // Any single token. 1938 } 1939 return NoError(); 1940 } 1941 1942 CheckedError Parser::ParseProtoOption() { 1943 NEXT(); 1944 ECHECK(ParseProtoKey()); 1945 EXPECT('='); 1946 ECHECK(ParseProtoCurliesOrIdent()); 1947 return NoError(); 1948 } 1949 1950 // Parse a protobuf type, and map it to the corresponding FlatBuffer one. 1951 CheckedError Parser::ParseTypeFromProtoType(Type *type) { 1952 struct type_lookup { const char *proto_type; BaseType fb_type, element; }; 1953 static type_lookup lookup[] = { 1954 { "float", BASE_TYPE_FLOAT, BASE_TYPE_NONE }, 1955 { "double", BASE_TYPE_DOUBLE, BASE_TYPE_NONE }, 1956 { "int32", BASE_TYPE_INT, BASE_TYPE_NONE }, 1957 { "int64", BASE_TYPE_LONG, BASE_TYPE_NONE }, 1958 { "uint32", BASE_TYPE_UINT, BASE_TYPE_NONE }, 1959 { "uint64", BASE_TYPE_ULONG, BASE_TYPE_NONE }, 1960 { "sint32", BASE_TYPE_INT, BASE_TYPE_NONE }, 1961 { "sint64", BASE_TYPE_LONG, BASE_TYPE_NONE }, 1962 { "fixed32", BASE_TYPE_UINT, BASE_TYPE_NONE }, 1963 { "fixed64", BASE_TYPE_ULONG, BASE_TYPE_NONE }, 1964 { "sfixed32", BASE_TYPE_INT, BASE_TYPE_NONE }, 1965 { "sfixed64", BASE_TYPE_LONG, BASE_TYPE_NONE }, 1966 { "bool", BASE_TYPE_BOOL, BASE_TYPE_NONE }, 1967 { "string", BASE_TYPE_STRING, BASE_TYPE_NONE }, 1968 { "bytes", BASE_TYPE_VECTOR, BASE_TYPE_UCHAR }, 1969 { nullptr, BASE_TYPE_NONE, BASE_TYPE_NONE } 1970 }; 1971 for (auto tl = lookup; tl->proto_type; tl++) { 1972 if (attribute_ == tl->proto_type) { 1973 type->base_type = tl->fb_type; 1974 type->element = tl->element; 1975 NEXT(); 1976 return NoError(); 1977 } 1978 } 1979 if (Is('.')) NEXT(); // qualified names may start with a . ? 1980 ECHECK(ParseTypeIdent(*type)); 1981 return NoError(); 1982 } 1983 1984 CheckedError Parser::SkipAnyJsonValue() { 1985 switch (token_) { 1986 case '{': { 1987 size_t fieldn_outer = 0; 1988 return ParseTableDelimiters(fieldn_outer, nullptr, 1989 [](const std::string &, 1990 size_t &fieldn, const StructDef *, 1991 void *state) -> CheckedError { 1992 auto *parser = static_cast<Parser *>(state); 1993 ECHECK(parser->SkipAnyJsonValue()); 1994 fieldn++; 1995 return NoError(); 1996 }, 1997 this); 1998 } 1999 case '[': { 2000 size_t count = 0; 2001 return ParseVectorDelimiters(count, [](size_t &, 2002 void *state) -> CheckedError { 2003 return static_cast<Parser *>(state)->SkipAnyJsonValue(); 2004 }, 2005 this); 2006 } 2007 case kTokenStringConstant: 2008 case kTokenIntegerConstant: 2009 case kTokenFloatConstant: 2010 NEXT(); 2011 break; 2012 default: 2013 if (IsIdent("true") || IsIdent("false") || IsIdent("null")) { NEXT(); } 2014 else return TokenError(); 2015 } 2016 return NoError(); 2017 } 2018 2019 CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) { 2020 switch (token_) { 2021 case '{': { 2022 std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state( 2023 this, builder); 2024 auto start = builder->StartMap(); 2025 size_t fieldn_outer = 0; 2026 auto err = ParseTableDelimiters(fieldn_outer, nullptr, 2027 [](const std::string &name, 2028 size_t &fieldn, const StructDef *, 2029 void *state) -> CheckedError { 2030 auto *parser_and_builder = 2031 static_cast<std::pair<Parser *, flexbuffers::Builder *> *>( 2032 state); 2033 auto *parser = parser_and_builder->first; 2034 auto *current_builder = parser_and_builder->second; 2035 current_builder->Key(name); 2036 ECHECK(parser->ParseFlexBufferValue(current_builder)); 2037 fieldn++; 2038 return NoError(); 2039 }, 2040 &parser_and_builder_state); 2041 ECHECK(err); 2042 builder->EndMap(start); 2043 break; 2044 } 2045 case '[':{ 2046 auto start = builder->StartVector(); 2047 size_t count = 0; 2048 std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state( 2049 this, builder); 2050 ECHECK(ParseVectorDelimiters(count, [](size_t &, 2051 void *state) -> CheckedError { 2052 auto *parser_and_builder = 2053 static_cast<std::pair<Parser *, flexbuffers::Builder *> *>( 2054 state); 2055 return parser_and_builder->first->ParseFlexBufferValue( 2056 parser_and_builder->second); 2057 }, 2058 &parser_and_builder_state)); 2059 builder->EndVector(start, false, false); 2060 break; 2061 } 2062 case kTokenStringConstant: 2063 builder->String(attribute_); 2064 EXPECT(kTokenStringConstant); 2065 break; 2066 case kTokenIntegerConstant: 2067 builder->Int(StringToInt(attribute_.c_str())); 2068 EXPECT(kTokenIntegerConstant); 2069 break; 2070 case kTokenFloatConstant: 2071 builder->Double(strtod(attribute_.c_str(), nullptr)); 2072 EXPECT(kTokenFloatConstant); 2073 break; 2074 default: 2075 if (IsIdent("true")) { builder->Bool(true); NEXT(); } 2076 else if (IsIdent("false")) { builder->Bool(false); NEXT(); } 2077 else if (IsIdent("null")) { builder->Null(); NEXT(); } 2078 else return TokenError(); 2079 } 2080 return NoError(); 2081 } 2082 2083 bool Parser::ParseFlexBuffer(const char *source, const char *source_filename, 2084 flexbuffers::Builder *builder) { 2085 auto ok = !StartParseFile(source, source_filename).Check() && 2086 !ParseFlexBufferValue(builder).Check(); 2087 if (ok) builder->Finish(); 2088 return ok; 2089 } 2090 2091 bool Parser::Parse(const char *source, const char **include_paths, 2092 const char *source_filename) { 2093 return !ParseRoot(source, include_paths, source_filename).Check(); 2094 } 2095 2096 CheckedError Parser::StartParseFile(const char *source, const char *source_filename) { 2097 file_being_parsed_ = source_filename ? source_filename : ""; 2098 source_ = cursor_ = source; 2099 line_ = 1; 2100 error_.clear(); 2101 ECHECK(SkipByteOrderMark()); 2102 NEXT(); 2103 if (Is(kTokenEof)) 2104 return Error("input file is empty"); 2105 return NoError(); 2106 } 2107 2108 CheckedError Parser::ParseRoot(const char *source, const char **include_paths, 2109 const char *source_filename) { 2110 ECHECK(DoParse(source, include_paths, source_filename, nullptr)); 2111 2112 // Check that all types were defined. 2113 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ) { 2114 auto &struct_def = **it; 2115 if (struct_def.predecl) { 2116 if (opts.proto_mode) { 2117 // Protos allow enums to be used before declaration, so check if that 2118 // is the case here. 2119 EnumDef *enum_def = nullptr; 2120 for (size_t components = struct_def.defined_namespace-> 2121 components.size() + 1; 2122 components && !enum_def; components--) { 2123 auto qualified_name = struct_def.defined_namespace-> 2124 GetFullyQualifiedName(struct_def.name, 2125 components - 1); 2126 enum_def = LookupEnum(qualified_name); 2127 } 2128 if (enum_def) { 2129 // This is pretty slow, but a simple solution for now. 2130 auto initial_count = struct_def.refcount; 2131 for (auto struct_it = structs_.vec.begin(); 2132 struct_it != structs_.vec.end(); 2133 ++struct_it) { 2134 auto &sd = **struct_it; 2135 for (auto field_it = sd.fields.vec.begin(); 2136 field_it != sd.fields.vec.end(); 2137 ++field_it) { 2138 auto &field = **field_it; 2139 if (field.value.type.struct_def == &struct_def) { 2140 field.value.type.struct_def = nullptr; 2141 field.value.type.enum_def = enum_def; 2142 auto &bt = field.value.type.base_type == BASE_TYPE_VECTOR 2143 ? field.value.type.element 2144 : field.value.type.base_type; 2145 assert(bt == BASE_TYPE_STRUCT); 2146 bt = enum_def->underlying_type.base_type; 2147 struct_def.refcount--; 2148 enum_def->refcount++; 2149 } 2150 } 2151 } 2152 if (struct_def.refcount) 2153 return Error("internal: " + NumToString(struct_def.refcount) + "/" + 2154 NumToString(initial_count) + 2155 " use(s) of pre-declaration enum not accounted for: " 2156 + enum_def->name); 2157 structs_.dict.erase(structs_.dict.find(struct_def.name)); 2158 it = structs_.vec.erase(it); 2159 delete &struct_def; 2160 continue; // Skip error. 2161 } 2162 } 2163 auto err = "type referenced but not defined (check namespace): " + 2164 struct_def.name; 2165 if (struct_def.original_location) 2166 err += ", originally at: " + *struct_def.original_location; 2167 return Error(err); 2168 } 2169 ++it; 2170 } 2171 2172 // This check has to happen here and not earlier, because only now do we 2173 // know for sure what the type of these are. 2174 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { 2175 auto &enum_def = **it; 2176 if (enum_def.is_union) { 2177 for (auto val_it = enum_def.vals.vec.begin(); 2178 val_it != enum_def.vals.vec.end(); 2179 ++val_it) { 2180 auto &val = **val_it; 2181 if (!SupportsVectorOfUnions() && 2182 val.union_type.struct_def && val.union_type.struct_def->fixed) 2183 return Error( 2184 "only tables can be union elements in the generated language: " 2185 + val.name); 2186 } 2187 } 2188 } 2189 return NoError(); 2190 } 2191 2192 CheckedError Parser::DoParse(const char *source, 2193 const char **include_paths, 2194 const char *source_filename, 2195 const char *include_filename) { 2196 if (source_filename && 2197 included_files_.find(source_filename) == included_files_.end()) { 2198 included_files_[source_filename] = include_filename ? include_filename : ""; 2199 files_included_per_file_[source_filename] = std::set<std::string>(); 2200 } 2201 if (!include_paths) { 2202 static const char *current_directory[] = { "", nullptr }; 2203 include_paths = current_directory; 2204 } 2205 field_stack_.clear(); 2206 builder_.Clear(); 2207 // Start with a blank namespace just in case this file doesn't have one. 2208 current_namespace_ = empty_namespace_; 2209 2210 ECHECK(StartParseFile(source, source_filename)); 2211 2212 // Includes must come before type declarations: 2213 for (;;) { 2214 // Parse pre-include proto statements if any: 2215 if (opts.proto_mode && 2216 (attribute_ == "option" || attribute_ == "syntax" || 2217 attribute_ == "package")) { 2218 ECHECK(ParseProtoDecl()); 2219 } else if (IsIdent("native_include")) { 2220 NEXT(); 2221 vector_emplace_back(&native_included_files_, attribute_); 2222 EXPECT(kTokenStringConstant); 2223 } else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) { 2224 NEXT(); 2225 if (opts.proto_mode && attribute_ == "public") NEXT(); 2226 auto name = flatbuffers::PosixPath(attribute_.c_str()); 2227 EXPECT(kTokenStringConstant); 2228 // Look for the file in include_paths. 2229 std::string filepath; 2230 for (auto paths = include_paths; paths && *paths; paths++) { 2231 filepath = flatbuffers::ConCatPathFileName(*paths, name); 2232 if(FileExists(filepath.c_str())) break; 2233 } 2234 if (filepath.empty()) 2235 return Error("unable to locate include file: " + name); 2236 if (source_filename) 2237 files_included_per_file_[source_filename].insert(filepath); 2238 if (included_files_.find(filepath) == included_files_.end()) { 2239 // We found an include file that we have not parsed yet. 2240 // Load it and parse it. 2241 std::string contents; 2242 if (!LoadFile(filepath.c_str(), true, &contents)) 2243 return Error("unable to load include file: " + name); 2244 ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(), 2245 name.c_str())); 2246 // We generally do not want to output code for any included files: 2247 if (!opts.generate_all) MarkGenerated(); 2248 // Reset these just in case the included file had them, and the 2249 // parent doesn't. 2250 root_struct_def_ = nullptr; 2251 file_identifier_.clear(); 2252 file_extension_.clear(); 2253 // This is the easiest way to continue this file after an include: 2254 // instead of saving and restoring all the state, we simply start the 2255 // file anew. This will cause it to encounter the same include 2256 // statement again, but this time it will skip it, because it was 2257 // entered into included_files_. 2258 // This is recursive, but only go as deep as the number of include 2259 // statements. 2260 return DoParse(source, include_paths, source_filename, include_filename); 2261 } 2262 EXPECT(';'); 2263 } else { 2264 break; 2265 } 2266 } 2267 // Now parse all other kinds of declarations: 2268 while (token_ != kTokenEof) { 2269 if (opts.proto_mode) { 2270 ECHECK(ParseProtoDecl()); 2271 } else if (IsIdent("namespace")) { 2272 ECHECK(ParseNamespace()); 2273 } else if (token_ == '{') { 2274 if (!root_struct_def_) 2275 return Error("no root type set to parse json with"); 2276 if (builder_.GetSize()) { 2277 return Error("cannot have more than one json object in a file"); 2278 } 2279 uoffset_t toff; 2280 ECHECK(ParseTable(*root_struct_def_, nullptr, &toff)); 2281 builder_.Finish(Offset<Table>(toff), 2282 file_identifier_.length() ? file_identifier_.c_str() : nullptr); 2283 } else if (IsIdent("enum")) { 2284 ECHECK(ParseEnum(false, nullptr)); 2285 } else if (IsIdent("union")) { 2286 ECHECK(ParseEnum(true, nullptr)); 2287 } else if (IsIdent("root_type")) { 2288 NEXT(); 2289 auto root_type = attribute_; 2290 EXPECT(kTokenIdentifier); 2291 ECHECK(ParseNamespacing(&root_type, nullptr)); 2292 if (!SetRootType(root_type.c_str())) 2293 return Error("unknown root type: " + root_type); 2294 if (root_struct_def_->fixed) 2295 return Error("root type must be a table"); 2296 EXPECT(';'); 2297 } else if (IsIdent("file_identifier")) { 2298 NEXT(); 2299 file_identifier_ = attribute_; 2300 EXPECT(kTokenStringConstant); 2301 if (file_identifier_.length() != 2302 FlatBufferBuilder::kFileIdentifierLength) 2303 return Error("file_identifier must be exactly " + 2304 NumToString(FlatBufferBuilder::kFileIdentifierLength) + 2305 " characters"); 2306 EXPECT(';'); 2307 } else if (IsIdent("file_extension")) { 2308 NEXT(); 2309 file_extension_ = attribute_; 2310 EXPECT(kTokenStringConstant); 2311 EXPECT(';'); 2312 } else if(IsIdent("include")) { 2313 return Error("includes must come before declarations"); 2314 } else if(IsIdent("attribute")) { 2315 NEXT(); 2316 auto name = attribute_; 2317 EXPECT(kTokenStringConstant); 2318 EXPECT(';'); 2319 known_attributes_[name] = false; 2320 } else if (IsIdent("rpc_service")) { 2321 ECHECK(ParseService()); 2322 } else { 2323 ECHECK(ParseDecl()); 2324 } 2325 } 2326 return NoError(); 2327 } 2328 2329 std::set<std::string> Parser::GetIncludedFilesRecursive( 2330 const std::string &file_name) const { 2331 std::set<std::string> included_files; 2332 std::list<std::string> to_process; 2333 2334 if (file_name.empty()) return included_files; 2335 to_process.push_back(file_name); 2336 2337 while (!to_process.empty()) { 2338 std::string current = to_process.front(); 2339 to_process.pop_front(); 2340 included_files.insert(current); 2341 2342 // Workaround the lack of const accessor in C++98 maps. 2343 auto &new_files = 2344 (*const_cast<std::map<std::string, std::set<std::string>> *>( 2345 &files_included_per_file_))[current]; 2346 for (auto it = new_files.begin(); it != new_files.end(); ++it) { 2347 if (included_files.find(*it) == included_files.end()) 2348 to_process.push_back(*it); 2349 } 2350 } 2351 2352 return included_files; 2353 } 2354 2355 // Schema serialization functionality: 2356 2357 template<typename T> bool compareName(const T* a, const T* b) { 2358 return a->defined_namespace->GetFullyQualifiedName(a->name) 2359 < b->defined_namespace->GetFullyQualifiedName(b->name); 2360 } 2361 2362 template<typename T> void AssignIndices(const std::vector<T *> &defvec) { 2363 // Pre-sort these vectors, such that we can set the correct indices for them. 2364 auto vec = defvec; 2365 std::sort(vec.begin(), vec.end(), compareName<T>); 2366 for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i; 2367 } 2368 2369 void Parser::Serialize() { 2370 builder_.Clear(); 2371 AssignIndices(structs_.vec); 2372 AssignIndices(enums_.vec); 2373 std::vector<Offset<reflection::Object>> object_offsets; 2374 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) { 2375 auto offset = (*it)->Serialize(&builder_, *this); 2376 object_offsets.push_back(offset); 2377 (*it)->serialized_location = offset.o; 2378 } 2379 std::vector<Offset<reflection::Enum>> enum_offsets; 2380 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { 2381 auto offset = (*it)->Serialize(&builder_, *this); 2382 enum_offsets.push_back(offset); 2383 (*it)->serialized_location = offset.o; 2384 } 2385 auto schema_offset = reflection::CreateSchema( 2386 builder_, 2387 builder_.CreateVectorOfSortedTables(&object_offsets), 2388 builder_.CreateVectorOfSortedTables(&enum_offsets), 2389 builder_.CreateString(file_identifier_), 2390 builder_.CreateString(file_extension_), 2391 root_struct_def_ 2392 ? root_struct_def_->serialized_location 2393 : 0); 2394 builder_.Finish(schema_offset, reflection::SchemaIdentifier()); 2395 } 2396 2397 Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder, 2398 const Parser &parser) const { 2399 std::vector<Offset<reflection::Field>> field_offsets; 2400 for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) { 2401 field_offsets.push_back( 2402 (*it)->Serialize(builder, 2403 static_cast<uint16_t>(it - fields.vec.begin()), parser)); 2404 } 2405 auto qualified_name = defined_namespace->GetFullyQualifiedName(name); 2406 return reflection::CreateObject(*builder, 2407 builder->CreateString(qualified_name), 2408 builder->CreateVectorOfSortedTables( 2409 &field_offsets), 2410 fixed, 2411 static_cast<int>(minalign), 2412 static_cast<int>(bytesize), 2413 SerializeAttributes(builder, parser), 2414 parser.opts.binary_schema_comments 2415 ? builder->CreateVectorOfStrings( 2416 doc_comment) 2417 : 0); 2418 } 2419 2420 Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder, 2421 uint16_t id, 2422 const Parser &parser) const { 2423 return reflection::CreateField(*builder, 2424 builder->CreateString(name), 2425 value.type.Serialize(builder), 2426 id, 2427 value.offset, 2428 IsInteger(value.type.base_type) 2429 ? StringToInt(value.constant.c_str()) 2430 : 0, 2431 IsFloat(value.type.base_type) 2432 ? strtod(value.constant.c_str(), nullptr) 2433 : 0.0, 2434 deprecated, 2435 required, 2436 key, 2437 SerializeAttributes(builder, parser), 2438 parser.opts.binary_schema_comments 2439 ? builder->CreateVectorOfStrings(doc_comment) 2440 : 0); 2441 // TODO: value.constant is almost always "0", we could save quite a bit of 2442 // space by sharing it. Same for common values of value.type. 2443 } 2444 2445 Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder, 2446 const Parser &parser) const { 2447 std::vector<Offset<reflection::EnumVal>> enumval_offsets; 2448 for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) { 2449 enumval_offsets.push_back((*it)->Serialize(builder)); 2450 } 2451 auto qualified_name = defined_namespace->GetFullyQualifiedName(name); 2452 return reflection::CreateEnum(*builder, 2453 builder->CreateString(qualified_name), 2454 builder->CreateVector(enumval_offsets), 2455 is_union, 2456 underlying_type.Serialize(builder), 2457 SerializeAttributes(builder, parser), 2458 parser.opts.binary_schema_comments 2459 ? builder->CreateVectorOfStrings(doc_comment) 2460 : 0); 2461 } 2462 2463 Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const 2464 { 2465 return reflection::CreateEnumVal(*builder, 2466 builder->CreateString(name), 2467 value, 2468 union_type.struct_def 2469 ? union_type.struct_def-> 2470 serialized_location 2471 : 0, 2472 union_type.Serialize(builder)); 2473 } 2474 2475 Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const { 2476 return reflection::CreateType(*builder, 2477 static_cast<reflection::BaseType>(base_type), 2478 static_cast<reflection::BaseType>(element), 2479 struct_def ? struct_def->index : 2480 (enum_def ? enum_def->index : -1)); 2481 } 2482 2483 flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset< 2484 reflection::KeyValue>>> 2485 Definition::SerializeAttributes(FlatBufferBuilder *builder, 2486 const Parser &parser) const { 2487 std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs; 2488 for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) { 2489 auto it = parser.known_attributes_.find(kv->first); 2490 assert(it != parser.known_attributes_.end()); 2491 if (!it->second) { // Custom attribute. 2492 attrs.push_back( 2493 reflection::CreateKeyValue(*builder, builder->CreateString(kv->first), 2494 builder->CreateString( 2495 kv->second->constant))); 2496 } 2497 } 2498 if (attrs.size()) { 2499 return builder->CreateVectorOfSortedTables(&attrs); 2500 } else { 2501 return 0; 2502 } 2503 } 2504 2505 std::string Parser::ConformTo(const Parser &base) { 2506 for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) { 2507 auto &struct_def = **sit; 2508 auto qualified_name = 2509 struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name); 2510 auto struct_def_base = base.LookupStruct(qualified_name); 2511 if (!struct_def_base) continue; 2512 for (auto fit = struct_def.fields.vec.begin(); 2513 fit != struct_def.fields.vec.end(); ++fit) { 2514 auto &field = **fit; 2515 auto field_base = struct_def_base->fields.Lookup(field.name); 2516 if (field_base) { 2517 if (field.value.offset != field_base->value.offset) 2518 return "offsets differ for field: " + field.name; 2519 if (field.value.constant != field_base->value.constant) 2520 return "defaults differ for field: " + field.name; 2521 if (!EqualByName(field.value.type, field_base->value.type)) 2522 return "types differ for field: " + field.name; 2523 } else { 2524 // Doesn't have to exist, deleting fields is fine. 2525 // But we should check if there is a field that has the same offset 2526 // but is incompatible (in the case of field renaming). 2527 for (auto fbit = struct_def_base->fields.vec.begin(); 2528 fbit != struct_def_base->fields.vec.end(); ++fbit) { 2529 field_base = *fbit; 2530 if (field.value.offset == field_base->value.offset) { 2531 if (!EqualByName(field.value.type, field_base->value.type)) 2532 return "field renamed to different type: " + field.name; 2533 break; 2534 } 2535 } 2536 } 2537 } 2538 } 2539 for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) { 2540 auto &enum_def = **eit; 2541 auto qualified_name = 2542 enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name); 2543 auto enum_def_base = base.enums_.Lookup(qualified_name); 2544 if (!enum_def_base) continue; 2545 for (auto evit = enum_def.vals.vec.begin(); 2546 evit != enum_def.vals.vec.end(); ++evit) { 2547 auto &enum_val = **evit; 2548 auto enum_val_base = enum_def_base->vals.Lookup(enum_val.name); 2549 if (enum_val_base) { 2550 if (enum_val.value != enum_val_base->value) 2551 return "values differ for enum: " + enum_val.name; 2552 } 2553 } 2554 } 2555 return ""; 2556 } 2557 2558 } // namespace flatbuffers 2559