/src/flatbuffers/src/idl_parser.cpp
Line | Count | Source (jump to first uncovered line) |
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 <cmath> |
19 | | #include <iostream> |
20 | | #include <list> |
21 | | #include <string> |
22 | | #include <utility> |
23 | | |
24 | | #include "flatbuffers/base.h" |
25 | | #include "flatbuffers/buffer.h" |
26 | | #include "flatbuffers/idl.h" |
27 | | #include "flatbuffers/reflection_generated.h" |
28 | | #include "flatbuffers/util.h" |
29 | | |
30 | | namespace flatbuffers { |
31 | | |
32 | | // Reflects the version at the compiling time of binary(lib/dll/so). |
33 | 0 | const char *FLATBUFFERS_VERSION() { |
34 | | // clang-format off |
35 | 0 | return |
36 | 0 | FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "." |
37 | 0 | FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "." |
38 | 0 | FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION); |
39 | | // clang-format on |
40 | 0 | } |
41 | | |
42 | | namespace { |
43 | | |
44 | | static const double kPi = 3.14159265358979323846; |
45 | | |
46 | | // The enums in the reflection schema should match the ones we use internally. |
47 | | // Compare the last element to check if these go out of sync. |
48 | | static_assert(BASE_TYPE_VECTOR64 == |
49 | | static_cast<BaseType>(reflection::MaxBaseType - 1), |
50 | | "enums don't match"); |
51 | | |
52 | | // Any parsing calls have to be wrapped in this macro, which automates |
53 | | // handling of recursive error checking a bit. It will check the received |
54 | | // CheckedError object, and return straight away on error. |
55 | | #define ECHECK(call) \ |
56 | 15.7M | { \ |
57 | 15.7M | auto ce = (call); \ |
58 | 15.7M | if (ce.Check()) return ce; \ |
59 | 15.7M | } |
60 | | |
61 | | // These two functions are called hundreds of times below, so define a short |
62 | | // form: |
63 | 4.78M | #define NEXT() ECHECK(Next()) |
64 | 2.97M | #define EXPECT(tok) ECHECK(Expect(tok)) |
65 | | |
66 | 1.38k | static bool ValidateUTF8(const std::string &str) { |
67 | 1.38k | const char *s = &str[0]; |
68 | 1.38k | const char *const sEnd = s + str.length(); |
69 | 46.6k | while (s < sEnd) { |
70 | 45.3k | if (FromUTF8(&s) < 0) { return false; } |
71 | 45.3k | } |
72 | 1.31k | return true; |
73 | 1.38k | } |
74 | | |
75 | 37.6k | static bool IsLowerSnakeCase(const std::string &str) { |
76 | 144k | for (size_t i = 0; i < str.length(); i++) { |
77 | 118k | char c = str[i]; |
78 | 118k | if (!check_ascii_range(c, 'a', 'z') && !is_digit(c) && c != '_') { |
79 | 11.2k | return false; |
80 | 11.2k | } |
81 | 118k | } |
82 | 26.3k | return true; |
83 | 37.6k | } |
84 | | |
85 | | static void DeserializeDoc(std::vector<std::string> &doc, |
86 | 0 | const Vector<Offset<String>> *documentation) { |
87 | 0 | if (documentation == nullptr) return; |
88 | 0 | for (uoffset_t index = 0; index < documentation->size(); index++) |
89 | 0 | doc.push_back(documentation->Get(index)->str()); |
90 | 0 | } |
91 | | |
92 | 14.9M | static CheckedError NoError() { return CheckedError(false); } |
93 | | |
94 | 1.83k | template<typename T> static std::string TypeToIntervalString() { |
95 | 1.83k | return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " + |
96 | 1.83k | NumToString((flatbuffers::numeric_limits<T>::max)()) + "]"; |
97 | 1.83k | } idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<unsigned char>() Line | Count | Source | 94 | 481 | template<typename T> static std::string TypeToIntervalString() { | 95 | 481 | return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " + | 96 | 481 | NumToString((flatbuffers::numeric_limits<T>::max)()) + "]"; | 97 | 481 | } |
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<signed char>() Line | Count | Source | 94 | 291 | template<typename T> static std::string TypeToIntervalString() { | 95 | 291 | return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " + | 96 | 291 | NumToString((flatbuffers::numeric_limits<T>::max)()) + "]"; | 97 | 291 | } |
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<short>() Line | Count | Source | 94 | 232 | template<typename T> static std::string TypeToIntervalString() { | 95 | 232 | return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " + | 96 | 232 | NumToString((flatbuffers::numeric_limits<T>::max)()) + "]"; | 97 | 232 | } |
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<unsigned short>() Line | Count | Source | 94 | 239 | template<typename T> static std::string TypeToIntervalString() { | 95 | 239 | return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " + | 96 | 239 | NumToString((flatbuffers::numeric_limits<T>::max)()) + "]"; | 97 | 239 | } |
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<int>() Line | Count | Source | 94 | 210 | template<typename T> static std::string TypeToIntervalString() { | 95 | 210 | return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " + | 96 | 210 | NumToString((flatbuffers::numeric_limits<T>::max)()) + "]"; | 97 | 210 | } |
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<unsigned int>() Line | Count | Source | 94 | 259 | template<typename T> static std::string TypeToIntervalString() { | 95 | 259 | return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " + | 96 | 259 | NumToString((flatbuffers::numeric_limits<T>::max)()) + "]"; | 97 | 259 | } |
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<long>() Line | Count | Source | 94 | 20 | template<typename T> static std::string TypeToIntervalString() { | 95 | 20 | return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " + | 96 | 20 | NumToString((flatbuffers::numeric_limits<T>::max)()) + "]"; | 97 | 20 | } |
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<unsigned long>() Line | Count | Source | 94 | 100 | template<typename T> static std::string TypeToIntervalString() { | 95 | 100 | return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " + | 96 | 100 | NumToString((flatbuffers::numeric_limits<T>::max)()) + "]"; | 97 | 100 | } |
Unexecuted instantiation: idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<float>() Unexecuted instantiation: idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<double>() |
98 | | |
99 | | // atot: template version of atoi/atof: convert a string to an instance of T. |
100 | | template<typename T> |
101 | 282k | static bool atot_scalar(const char *s, T *val, bool_constant<false>) { |
102 | 282k | return StringToNumber(s, val); |
103 | 282k | } idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<unsigned short>(char const*, unsigned short*, std::__1::integral_constant<bool, false>) Line | Count | Source | 101 | 15.9k | static bool atot_scalar(const char *s, T *val, bool_constant<false>) { | 102 | 15.9k | return StringToNumber(s, val); | 103 | 15.9k | } |
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<unsigned int>(char const*, unsigned int*, std::__1::integral_constant<bool, false>) Line | Count | Source | 101 | 8.39k | static bool atot_scalar(const char *s, T *val, bool_constant<false>) { | 102 | 8.39k | return StringToNumber(s, val); | 103 | 8.39k | } |
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<unsigned char>(char const*, unsigned char*, std::__1::integral_constant<bool, false>) Line | Count | Source | 101 | 64.9k | static bool atot_scalar(const char *s, T *val, bool_constant<false>) { | 102 | 64.9k | return StringToNumber(s, val); | 103 | 64.9k | } |
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<signed char>(char const*, signed char*, std::__1::integral_constant<bool, false>) Line | Count | Source | 101 | 37.0k | static bool atot_scalar(const char *s, T *val, bool_constant<false>) { | 102 | 37.0k | return StringToNumber(s, val); | 103 | 37.0k | } |
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<short>(char const*, short*, std::__1::integral_constant<bool, false>) Line | Count | Source | 101 | 25.8k | static bool atot_scalar(const char *s, T *val, bool_constant<false>) { | 102 | 25.8k | return StringToNumber(s, val); | 103 | 25.8k | } |
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<int>(char const*, int*, std::__1::integral_constant<bool, false>) Line | Count | Source | 101 | 33.5k | static bool atot_scalar(const char *s, T *val, bool_constant<false>) { | 102 | 33.5k | return StringToNumber(s, val); | 103 | 33.5k | } |
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<long>(char const*, long*, std::__1::integral_constant<bool, false>) Line | Count | Source | 101 | 49.4k | static bool atot_scalar(const char *s, T *val, bool_constant<false>) { | 102 | 49.4k | return StringToNumber(s, val); | 103 | 49.4k | } |
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<unsigned long>(char const*, unsigned long*, std::__1::integral_constant<bool, false>) Line | Count | Source | 101 | 46.9k | static bool atot_scalar(const char *s, T *val, bool_constant<false>) { | 102 | 46.9k | return StringToNumber(s, val); | 103 | 46.9k | } |
|
104 | | |
105 | | template<typename T> |
106 | 64.8k | static bool atot_scalar(const char *s, T *val, bool_constant<true>) { |
107 | | // Normalize NaN parsed from fbs or json to unsigned NaN. |
108 | 64.8k | if (false == StringToNumber(s, val)) return false; |
109 | 64.7k | *val = (*val != *val) ? std::fabs(*val) : *val; |
110 | 64.7k | return true; |
111 | 64.8k | } idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<float>(char const*, float*, std::__1::integral_constant<bool, true>) Line | Count | Source | 106 | 28.7k | static bool atot_scalar(const char *s, T *val, bool_constant<true>) { | 107 | | // Normalize NaN parsed from fbs or json to unsigned NaN. | 108 | 28.7k | if (false == StringToNumber(s, val)) return false; | 109 | 28.7k | *val = (*val != *val) ? std::fabs(*val) : *val; | 110 | 28.7k | return true; | 111 | 28.7k | } |
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<double>(char const*, double*, std::__1::integral_constant<bool, true>) Line | Count | Source | 106 | 36.1k | static bool atot_scalar(const char *s, T *val, bool_constant<true>) { | 107 | | // Normalize NaN parsed from fbs or json to unsigned NaN. | 108 | 36.1k | if (false == StringToNumber(s, val)) return false; | 109 | 36.0k | *val = (*val != *val) ? std::fabs(*val) : *val; | 110 | 36.0k | return true; | 111 | 36.1k | } |
|
112 | | |
113 | | template<typename T> |
114 | 347k | static CheckedError atot(const char *s, Parser &parser, T *val) { |
115 | 347k | auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>()); |
116 | 347k | if (done) return NoError(); |
117 | 1.35k | if (0 == *val) |
118 | 452 | return parser.Error("invalid number: \"" + std::string(s) + "\""); |
119 | 900 | else |
120 | 900 | return parser.Error("invalid number: \"" + std::string(s) + "\"" + |
121 | 900 | ", constant does not fit " + TypeToIntervalString<T>()); |
122 | 1.35k | } idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<unsigned short>(char const*, flatbuffers::Parser&, unsigned short*) Line | Count | Source | 114 | 15.9k | static CheckedError atot(const char *s, Parser &parser, T *val) { | 115 | 15.9k | auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>()); | 116 | 15.9k | if (done) return NoError(); | 117 | 199 | if (0 == *val) | 118 | 43 | return parser.Error("invalid number: \"" + std::string(s) + "\""); | 119 | 156 | else | 120 | 156 | return parser.Error("invalid number: \"" + std::string(s) + "\"" + | 121 | 156 | ", constant does not fit " + TypeToIntervalString<T>()); | 122 | 199 | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<unsigned int>(char const*, flatbuffers::Parser&, unsigned int*) Line | Count | Source | 114 | 8.39k | static CheckedError atot(const char *s, Parser &parser, T *val) { | 115 | 8.39k | auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>()); | 116 | 8.39k | if (done) return NoError(); | 117 | 166 | if (0 == *val) | 118 | 48 | return parser.Error("invalid number: \"" + std::string(s) + "\""); | 119 | 118 | else | 120 | 118 | return parser.Error("invalid number: \"" + std::string(s) + "\"" + | 121 | 118 | ", constant does not fit " + TypeToIntervalString<T>()); | 122 | 166 | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<unsigned char>(char const*, flatbuffers::Parser&, unsigned char*) Line | Count | Source | 114 | 64.9k | static CheckedError atot(const char *s, Parser &parser, T *val) { | 115 | 64.9k | auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>()); | 116 | 64.9k | if (done) return NoError(); | 117 | 250 | if (0 == *val) | 118 | 69 | return parser.Error("invalid number: \"" + std::string(s) + "\""); | 119 | 181 | else | 120 | 181 | return parser.Error("invalid number: \"" + std::string(s) + "\"" + | 121 | 181 | ", constant does not fit " + TypeToIntervalString<T>()); | 122 | 250 | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<signed char>(char const*, flatbuffers::Parser&, signed char*) Line | Count | Source | 114 | 37.0k | static CheckedError atot(const char *s, Parser &parser, T *val) { | 115 | 37.0k | auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>()); | 116 | 37.0k | if (done) return NoError(); | 117 | 170 | if (0 == *val) | 118 | 36 | return parser.Error("invalid number: \"" + std::string(s) + "\""); | 119 | 134 | else | 120 | 134 | return parser.Error("invalid number: \"" + std::string(s) + "\"" + | 121 | 134 | ", constant does not fit " + TypeToIntervalString<T>()); | 122 | 170 | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<short>(char const*, flatbuffers::Parser&, short*) Line | Count | Source | 114 | 25.8k | static CheckedError atot(const char *s, Parser &parser, T *val) { | 115 | 25.8k | auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>()); | 116 | 25.8k | if (done) return NoError(); | 117 | 138 | if (0 == *val) | 118 | 37 | return parser.Error("invalid number: \"" + std::string(s) + "\""); | 119 | 101 | else | 120 | 101 | return parser.Error("invalid number: \"" + std::string(s) + "\"" + | 121 | 101 | ", constant does not fit " + TypeToIntervalString<T>()); | 122 | 138 | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<int>(char const*, flatbuffers::Parser&, int*) Line | Count | Source | 114 | 33.5k | static CheckedError atot(const char *s, Parser &parser, T *val) { | 115 | 33.5k | auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>()); | 116 | 33.5k | if (done) return NoError(); | 117 | 152 | if (0 == *val) | 118 | 60 | return parser.Error("invalid number: \"" + std::string(s) + "\""); | 119 | 92 | else | 120 | 92 | return parser.Error("invalid number: \"" + std::string(s) + "\"" + | 121 | 92 | ", constant does not fit " + TypeToIntervalString<T>()); | 122 | 152 | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<long>(char const*, flatbuffers::Parser&, long*) Line | Count | Source | 114 | 49.4k | static CheckedError atot(const char *s, Parser &parser, T *val) { | 115 | 49.4k | auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>()); | 116 | 49.4k | if (done) return NoError(); | 117 | 43 | if (0 == *val) | 118 | 24 | return parser.Error("invalid number: \"" + std::string(s) + "\""); | 119 | 19 | else | 120 | 19 | return parser.Error("invalid number: \"" + std::string(s) + "\"" + | 121 | 19 | ", constant does not fit " + TypeToIntervalString<T>()); | 122 | 43 | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<unsigned long>(char const*, flatbuffers::Parser&, unsigned long*) Line | Count | Source | 114 | 46.9k | static CheckedError atot(const char *s, Parser &parser, T *val) { | 115 | 46.9k | auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>()); | 116 | 46.9k | if (done) return NoError(); | 117 | 129 | if (0 == *val) | 118 | 30 | return parser.Error("invalid number: \"" + std::string(s) + "\""); | 119 | 99 | else | 120 | 99 | return parser.Error("invalid number: \"" + std::string(s) + "\"" + | 121 | 99 | ", constant does not fit " + TypeToIntervalString<T>()); | 122 | 129 | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<float>(char const*, flatbuffers::Parser&, float*) Line | Count | Source | 114 | 28.7k | static CheckedError atot(const char *s, Parser &parser, T *val) { | 115 | 28.7k | auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>()); | 116 | 28.7k | if (done) return NoError(); | 117 | 58 | if (0 == *val) | 118 | 58 | return parser.Error("invalid number: \"" + std::string(s) + "\""); | 119 | 0 | else | 120 | 0 | return parser.Error("invalid number: \"" + std::string(s) + "\"" + | 121 | 0 | ", constant does not fit " + TypeToIntervalString<T>()); | 122 | 58 | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<double>(char const*, flatbuffers::Parser&, double*) Line | Count | Source | 114 | 36.1k | static CheckedError atot(const char *s, Parser &parser, T *val) { | 115 | 36.1k | auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>()); | 116 | 36.1k | if (done) return NoError(); | 117 | 47 | if (0 == *val) | 118 | 47 | return parser.Error("invalid number: \"" + std::string(s) + "\""); | 119 | 0 | else | 120 | 0 | return parser.Error("invalid number: \"" + std::string(s) + "\"" + | 121 | 0 | ", constant does not fit " + TypeToIntervalString<T>()); | 122 | 47 | } |
|
123 | | template<> |
124 | | CheckedError atot<Offset<void>>(const char *s, Parser &parser, |
125 | 155k | Offset<void> *val) { |
126 | 155k | (void)parser; |
127 | 155k | *val = Offset<void>(atoi(s)); |
128 | 155k | return NoError(); |
129 | 155k | } |
130 | | |
131 | | template<> |
132 | | CheckedError atot<Offset64<void>>(const char *s, Parser &parser, |
133 | 23.6k | Offset64<void> *val) { |
134 | 23.6k | (void)parser; |
135 | 23.6k | *val = Offset64<void>(atoi(s)); |
136 | 23.6k | return NoError(); |
137 | 23.6k | } |
138 | | |
139 | | template<typename T> |
140 | | static T *LookupTableByName(const SymbolTable<T> &table, |
141 | | const std::string &name, |
142 | | const Namespace ¤t_namespace, |
143 | 258k | size_t skip_top) { |
144 | 258k | const auto &components = current_namespace.components; |
145 | 258k | if (table.dict.empty()) return nullptr; |
146 | 235k | if (components.size() < skip_top) return nullptr; |
147 | 86.8k | const auto N = components.size() - skip_top; |
148 | 86.8k | std::string full_name; |
149 | 1.00M | for (size_t i = 0; i < N; i++) { |
150 | 918k | full_name += components[i]; |
151 | 918k | full_name += '.'; |
152 | 918k | } |
153 | 1.00M | for (size_t i = N; i > 0; i--) { |
154 | 918k | full_name += name; |
155 | 918k | auto obj = table.Lookup(full_name); |
156 | 918k | if (obj) return obj; |
157 | 918k | auto len = full_name.size() - components[i - 1].size() - 1 - name.size(); |
158 | 918k | full_name.resize(len); |
159 | 918k | } |
160 | 86.5k | FLATBUFFERS_ASSERT(full_name.empty()); |
161 | 86.5k | return table.Lookup(name); // lookup in global namespace |
162 | 86.5k | } idl_parser.cpp:flatbuffers::EnumDef* flatbuffers::(anonymous namespace)::LookupTableByName<flatbuffers::EnumDef>(flatbuffers::SymbolTable<flatbuffers::EnumDef> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, flatbuffers::Namespace const&, unsigned long) Line | Count | Source | 143 | 57.7k | size_t skip_top) { | 144 | 57.7k | const auto &components = current_namespace.components; | 145 | 57.7k | if (table.dict.empty()) return nullptr; | 146 | 41.8k | if (components.size() < skip_top) return nullptr; | 147 | 41.8k | const auto N = components.size() - skip_top; | 148 | 41.8k | std::string full_name; | 149 | 87.0k | for (size_t i = 0; i < N; i++) { | 150 | 45.1k | full_name += components[i]; | 151 | 45.1k | full_name += '.'; | 152 | 45.1k | } | 153 | 86.8k | for (size_t i = N; i > 0; i--) { | 154 | 45.1k | full_name += name; | 155 | 45.1k | auto obj = table.Lookup(full_name); | 156 | 45.1k | if (obj) return obj; | 157 | 44.9k | auto len = full_name.size() - components[i - 1].size() - 1 - name.size(); | 158 | 44.9k | full_name.resize(len); | 159 | 44.9k | } | 160 | 41.7k | FLATBUFFERS_ASSERT(full_name.empty()); | 161 | 41.7k | return table.Lookup(name); // lookup in global namespace | 162 | 41.7k | } |
idl_parser.cpp:flatbuffers::StructDef* flatbuffers::(anonymous namespace)::LookupTableByName<flatbuffers::StructDef>(flatbuffers::SymbolTable<flatbuffers::StructDef> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, flatbuffers::Namespace const&, unsigned long) Line | Count | Source | 143 | 200k | size_t skip_top) { | 144 | 200k | const auto &components = current_namespace.components; | 145 | 200k | if (table.dict.empty()) return nullptr; | 146 | 193k | if (components.size() < skip_top) return nullptr; | 147 | 44.9k | const auto N = components.size() - skip_top; | 148 | 44.9k | std::string full_name; | 149 | 918k | for (size_t i = 0; i < N; i++) { | 150 | 873k | full_name += components[i]; | 151 | 873k | full_name += '.'; | 152 | 873k | } | 153 | 918k | for (size_t i = N; i > 0; i--) { | 154 | 873k | full_name += name; | 155 | 873k | auto obj = table.Lookup(full_name); | 156 | 873k | if (obj) return obj; | 157 | 873k | auto len = full_name.size() - components[i - 1].size() - 1 - name.size(); | 158 | 873k | full_name.resize(len); | 159 | 873k | } | 160 | 44.8k | FLATBUFFERS_ASSERT(full_name.empty()); | 161 | 44.8k | return table.Lookup(name); // lookup in global namespace | 162 | 44.8k | } |
|
163 | | |
164 | | // Declare tokens we'll use. Single character tokens are represented by their |
165 | | // ascii character code (e.g. '{'), others above 256. |
166 | | // clang-format off |
167 | | #define FLATBUFFERS_GEN_TOKENS(TD) \ |
168 | 17.7k | TD(Eof, 256, "end of file") \ |
169 | 17.7k | TD(StringConstant, 257, "string constant") \ |
170 | 17.7k | TD(IntegerConstant, 258, "integer constant") \ |
171 | 17.7k | TD(FloatConstant, 259, "float constant") \ |
172 | 17.7k | TD(Identifier, 260, "identifier") |
173 | | #ifdef __GNUC__ |
174 | | __extension__ // Stop GCC complaining about trailing comma with -Wpendantic. |
175 | | #endif |
176 | | enum { |
177 | | #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE, |
178 | | FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN) |
179 | | #undef FLATBUFFERS_TOKEN |
180 | | }; |
181 | | |
182 | 17.7k | static std::string TokenToString(int t) { |
183 | 17.7k | static const char * const tokens[] = { |
184 | 88.8k | #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING, |
185 | 88.8k | FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN) |
186 | 17.7k | #undef FLATBUFFERS_TOKEN |
187 | 17.7k | #define FLATBUFFERS_TD(ENUM, IDLTYPE, ...) \ |
188 | 337k | IDLTYPE, |
189 | 337k | FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) |
190 | 17.7k | #undef FLATBUFFERS_TD |
191 | 17.7k | }; |
192 | 17.7k | if (t < 256) { // A single ascii char token. |
193 | 9.24k | std::string s; |
194 | 9.24k | s.append(1, static_cast<char>(t)); |
195 | 9.24k | return s; |
196 | 9.24k | } else { // Other tokens. |
197 | 8.52k | return tokens[t - 256]; |
198 | 8.52k | } |
199 | 17.7k | } |
200 | | // clang-format on |
201 | | |
202 | 7.74M | static bool IsIdentifierStart(char c) { return is_alpha(c) || (c == '_'); } |
203 | | |
204 | | static bool CompareSerializedScalars(const uint8_t *a, const uint8_t *b, |
205 | 88.6M | const FieldDef &key) { |
206 | 88.6M | switch (key.value.type.base_type) { |
207 | 0 | #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ |
208 | 88.6M | case BASE_TYPE_##ENUM: { \ |
209 | 88.6M | CTYPE def = static_cast<CTYPE>(0); \ |
210 | 88.6M | if (!a || !b) { StringToNumber(key.value.constant.c_str(), &def); } \ |
211 | 88.6M | const auto av = a ? ReadScalar<CTYPE>(a) : def; \ |
212 | 88.6M | const auto bv = b ? ReadScalar<CTYPE>(b) : def; \ |
213 | 88.6M | return av < bv; \ |
214 | 88.6M | } |
215 | 88.6M | FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) |
216 | 0 | #undef FLATBUFFERS_TD |
217 | 0 | default: { |
218 | 0 | FLATBUFFERS_ASSERT(false && "scalar type expected"); |
219 | 0 | return false; |
220 | 0 | } |
221 | 88.6M | } |
222 | 88.6M | } |
223 | | |
224 | | static bool CompareTablesByScalarKey(const Offset<Table> *_a, |
225 | | const Offset<Table> *_b, |
226 | 88.6M | const FieldDef &key) { |
227 | 88.6M | const voffset_t offset = key.value.offset; |
228 | | // Indirect offset pointer to table pointer. |
229 | 88.6M | auto a = reinterpret_cast<const uint8_t *>(_a) + ReadScalar<uoffset_t>(_a); |
230 | 88.6M | auto b = reinterpret_cast<const uint8_t *>(_b) + ReadScalar<uoffset_t>(_b); |
231 | | // Fetch field address from table. |
232 | 88.6M | a = reinterpret_cast<const Table *>(a)->GetAddressOf(offset); |
233 | 88.6M | b = reinterpret_cast<const Table *>(b)->GetAddressOf(offset); |
234 | 88.6M | return CompareSerializedScalars(a, b, key); |
235 | 88.6M | } |
236 | | |
237 | | static bool CompareTablesByStringKey(const Offset<Table> *_a, |
238 | | const Offset<Table> *_b, |
239 | 109k | const FieldDef &key) { |
240 | 109k | const voffset_t offset = key.value.offset; |
241 | | // Indirect offset pointer to table pointer. |
242 | 109k | auto a = reinterpret_cast<const uint8_t *>(_a) + ReadScalar<uoffset_t>(_a); |
243 | 109k | auto b = reinterpret_cast<const uint8_t *>(_b) + ReadScalar<uoffset_t>(_b); |
244 | | // Fetch field address from table. |
245 | 109k | a = reinterpret_cast<const Table *>(a)->GetAddressOf(offset); |
246 | 109k | b = reinterpret_cast<const Table *>(b)->GetAddressOf(offset); |
247 | 109k | if (a && b) { |
248 | | // Indirect offset pointer to string pointer. |
249 | 109k | a += ReadScalar<uoffset_t>(a); |
250 | 109k | b += ReadScalar<uoffset_t>(b); |
251 | 109k | return *reinterpret_cast<const String *>(a) < |
252 | 109k | *reinterpret_cast<const String *>(b); |
253 | 109k | } else { |
254 | 0 | return a ? true : false; |
255 | 0 | } |
256 | 109k | } |
257 | | |
258 | 99.3k | static void SwapSerializedTables(Offset<Table> *a, Offset<Table> *b) { |
259 | | // These are serialized offsets, so are relative where they are |
260 | | // stored in memory, so compute the distance between these pointers: |
261 | 99.3k | ptrdiff_t diff = (b - a) * sizeof(Offset<Table>); |
262 | 99.3k | FLATBUFFERS_ASSERT(diff >= 0); // Guaranteed by SimpleQsort. |
263 | 99.3k | auto udiff = static_cast<uoffset_t>(diff); |
264 | 99.3k | a->o = EndianScalar(ReadScalar<uoffset_t>(a) - udiff); |
265 | 99.3k | b->o = EndianScalar(ReadScalar<uoffset_t>(b) + udiff); |
266 | 99.3k | std::swap(*a, *b); |
267 | 99.3k | } |
268 | | |
269 | | // See below for why we need our own sort :( |
270 | | template<typename T, typename F, typename S> |
271 | | static void SimpleQsort(T *begin, T *end, size_t width, F comparator, |
272 | 158k | S swapper) { |
273 | 158k | if (end - begin <= static_cast<ptrdiff_t>(width)) return; |
274 | 76.0k | auto l = begin + width; |
275 | 76.0k | auto r = end; |
276 | 88.8M | while (l < r) { |
277 | 88.8M | if (comparator(begin, l)) { |
278 | 26.4k | r -= width; |
279 | 26.4k | swapper(l, r); |
280 | 88.7M | } else { |
281 | 88.7M | l += width; |
282 | 88.7M | } |
283 | 88.8M | } |
284 | 76.0k | l -= width; |
285 | 76.0k | swapper(begin, l); |
286 | 76.0k | SimpleQsort(begin, l, width, comparator, swapper); |
287 | 76.0k | SimpleQsort(r, end, width, comparator, swapper); |
288 | 76.0k | } idl_parser.cpp:void flatbuffers::(anonymous namespace)::SimpleQsort<unsigned char, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_1, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_2>(unsigned char*, unsigned char*, unsigned long, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_1, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_2) Line | Count | Source | 272 | 3.52k | S swapper) { | 273 | 3.52k | if (end - begin <= static_cast<ptrdiff_t>(width)) return; | 274 | 1.72k | auto l = begin + width; | 275 | 1.72k | auto r = end; | 276 | 87.6k | while (l < r) { | 277 | 85.9k | if (comparator(begin, l)) { | 278 | 1.43k | r -= width; | 279 | 1.43k | swapper(l, r); | 280 | 84.4k | } else { | 281 | 84.4k | l += width; | 282 | 84.4k | } | 283 | 85.9k | } | 284 | 1.72k | l -= width; | 285 | 1.72k | swapper(begin, l); | 286 | 1.72k | SimpleQsort(begin, l, width, comparator, swapper); | 287 | 1.72k | SimpleQsort(r, end, width, comparator, swapper); | 288 | 1.72k | } |
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SimpleQsort<flatbuffers::Offset<flatbuffers::Table>, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_3, void (*)(flatbuffers::Offset<flatbuffers::Table>*, flatbuffers::Offset<flatbuffers::Table>*)>(flatbuffers::Offset<flatbuffers::Table>*, flatbuffers::Offset<flatbuffers::Table>*, unsigned long, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_3, void (*)(flatbuffers::Offset<flatbuffers::Table>*, flatbuffers::Offset<flatbuffers::Table>*)) Line | Count | Source | 272 | 12.5k | S swapper) { | 273 | 12.5k | if (end - begin <= static_cast<ptrdiff_t>(width)) return; | 274 | 3.68k | auto l = begin + width; | 275 | 3.68k | auto r = end; | 276 | 112k | while (l < r) { | 277 | 109k | if (comparator(begin, l)) { | 278 | 9.58k | r -= width; | 279 | 9.58k | swapper(l, r); | 280 | 99.6k | } else { | 281 | 99.6k | l += width; | 282 | 99.6k | } | 283 | 109k | } | 284 | 3.68k | l -= width; | 285 | 3.68k | swapper(begin, l); | 286 | 3.68k | SimpleQsort(begin, l, width, comparator, swapper); | 287 | 3.68k | SimpleQsort(r, end, width, comparator, swapper); | 288 | 3.68k | } |
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SimpleQsort<flatbuffers::Offset<flatbuffers::Table>, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_4, void (*)(flatbuffers::Offset<flatbuffers::Table>*, flatbuffers::Offset<flatbuffers::Table>*)>(flatbuffers::Offset<flatbuffers::Table>*, flatbuffers::Offset<flatbuffers::Table>*, unsigned long, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_4, void (*)(flatbuffers::Offset<flatbuffers::Table>*, flatbuffers::Offset<flatbuffers::Table>*)) Line | Count | Source | 272 | 142k | S swapper) { | 273 | 142k | if (end - begin <= static_cast<ptrdiff_t>(width)) return; | 274 | 70.6k | auto l = begin + width; | 275 | 70.6k | auto r = end; | 276 | 88.6M | while (l < r) { | 277 | 88.6M | if (comparator(begin, l)) { | 278 | 15.4k | r -= width; | 279 | 15.4k | swapper(l, r); | 280 | 88.5M | } else { | 281 | 88.5M | l += width; | 282 | 88.5M | } | 283 | 88.6M | } | 284 | 70.6k | l -= width; | 285 | 70.6k | swapper(begin, l); | 286 | 70.6k | SimpleQsort(begin, l, width, comparator, swapper); | 287 | 70.6k | SimpleQsort(r, end, width, comparator, swapper); | 288 | 70.6k | } |
|
289 | | |
290 | 9.11k | template<typename T> static inline void SingleValueRepack(Value &e, T val) { |
291 | | // Remove leading zeros. |
292 | 9.11k | if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); } |
293 | 9.11k | } idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<unsigned char>(flatbuffers::Value&, unsigned char) Line | Count | Source | 290 | 173 | template<typename T> static inline void SingleValueRepack(Value &e, T val) { | 291 | | // Remove leading zeros. | 292 | 173 | if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); } | 293 | 173 | } |
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<signed char>(flatbuffers::Value&, signed char) Line | Count | Source | 290 | 187 | template<typename T> static inline void SingleValueRepack(Value &e, T val) { | 291 | | // Remove leading zeros. | 292 | 187 | if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); } | 293 | 187 | } |
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<short>(flatbuffers::Value&, short) Line | Count | Source | 290 | 325 | template<typename T> static inline void SingleValueRepack(Value &e, T val) { | 291 | | // Remove leading zeros. | 292 | 325 | if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); } | 293 | 325 | } |
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<unsigned short>(flatbuffers::Value&, unsigned short) Line | Count | Source | 290 | 288 | template<typename T> static inline void SingleValueRepack(Value &e, T val) { | 291 | | // Remove leading zeros. | 292 | 288 | if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); } | 293 | 288 | } |
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<int>(flatbuffers::Value&, int) Line | Count | Source | 290 | 6.91k | template<typename T> static inline void SingleValueRepack(Value &e, T val) { | 291 | | // Remove leading zeros. | 292 | 6.91k | if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); } | 293 | 6.91k | } |
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<unsigned int>(flatbuffers::Value&, unsigned int) Line | Count | Source | 290 | 334 | template<typename T> static inline void SingleValueRepack(Value &e, T val) { | 291 | | // Remove leading zeros. | 292 | 334 | if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); } | 293 | 334 | } |
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<long>(flatbuffers::Value&, long) Line | Count | Source | 290 | 415 | template<typename T> static inline void SingleValueRepack(Value &e, T val) { | 291 | | // Remove leading zeros. | 292 | 415 | if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); } | 293 | 415 | } |
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<unsigned long>(flatbuffers::Value&, unsigned long) Line | Count | Source | 290 | 475 | template<typename T> static inline void SingleValueRepack(Value &e, T val) { | 291 | | // Remove leading zeros. | 292 | 475 | if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); } | 293 | 475 | } |
|
294 | | |
295 | | #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0) |
296 | | // Normalize defaults NaN to unsigned quiet-NaN(0) if value was parsed from |
297 | | // hex-float literal. |
298 | 146 | static void SingleValueRepack(Value &e, float val) { |
299 | 146 | if (val != val) e.constant = "nan"; |
300 | 146 | } |
301 | 105 | static void SingleValueRepack(Value &e, double val) { |
302 | 105 | if (val != val) e.constant = "nan"; |
303 | 105 | } |
304 | | #endif |
305 | | |
306 | 0 | template<typename T> static uint64_t EnumDistanceImpl(T e1, T e2) { |
307 | 0 | if (e1 < e2) { std::swap(e1, e2); } // use std for scalars |
308 | | // Signed overflow may occur, use unsigned calculation. |
309 | | // The unsigned overflow is well-defined by C++ standard (modulo 2^n). |
310 | 0 | return static_cast<uint64_t>(e1) - static_cast<uint64_t>(e2); |
311 | 0 | } Unexecuted instantiation: idl_parser.cpp:unsigned long flatbuffers::(anonymous namespace)::EnumDistanceImpl<unsigned long>(unsigned long, unsigned long) Unexecuted instantiation: idl_parser.cpp:unsigned long flatbuffers::(anonymous namespace)::EnumDistanceImpl<long>(long, long) |
312 | | |
313 | 98.7k | static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) { |
314 | 98.7k | auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str()); |
315 | 98.7k | auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str()); |
316 | 98.7k | return a_id < b_id; |
317 | 98.7k | } |
318 | | |
319 | | static Namespace *GetNamespace( |
320 | | const std::string &qualified_name, std::vector<Namespace *> &namespaces, |
321 | 0 | std::map<std::string, Namespace *> &namespaces_index) { |
322 | 0 | size_t dot = qualified_name.find_last_of('.'); |
323 | 0 | std::string namespace_name = (dot != std::string::npos) |
324 | 0 | ? std::string(qualified_name.c_str(), dot) |
325 | 0 | : ""; |
326 | 0 | Namespace *&ns = namespaces_index[namespace_name]; |
327 | |
|
328 | 0 | if (!ns) { |
329 | 0 | ns = new Namespace(); |
330 | 0 | namespaces.push_back(ns); |
331 | |
|
332 | 0 | size_t pos = 0; |
333 | |
|
334 | 0 | for (;;) { |
335 | 0 | dot = qualified_name.find('.', pos); |
336 | 0 | if (dot == std::string::npos) { break; } |
337 | 0 | ns->components.push_back(qualified_name.substr(pos, dot - pos)); |
338 | 0 | pos = dot + 1; |
339 | 0 | } |
340 | 0 | } |
341 | |
|
342 | 0 | return ns; |
343 | 0 | } |
344 | | |
345 | | // Generate a unique hash for a file based on its name and contents (if any). |
346 | 98 | static uint64_t HashFile(const char *source_filename, const char *source) { |
347 | 98 | uint64_t hash = 0; |
348 | | |
349 | 98 | if (source_filename) |
350 | 98 | hash = HashFnv1a<uint64_t>(StripPath(source_filename).c_str()); |
351 | | |
352 | 98 | if (source && *source) hash ^= HashFnv1a<uint64_t>(source); |
353 | | |
354 | 98 | return hash; |
355 | 98 | } |
356 | | |
357 | 0 | template<typename T> static bool compareName(const T *a, const T *b) { |
358 | 0 | return a->defined_namespace->GetFullyQualifiedName(a->name) < |
359 | 0 | b->defined_namespace->GetFullyQualifiedName(b->name); |
360 | 0 | } Unexecuted instantiation: idl_parser.cpp:bool flatbuffers::(anonymous namespace)::compareName<flatbuffers::StructDef>(flatbuffers::StructDef const*, flatbuffers::StructDef const*) Unexecuted instantiation: idl_parser.cpp:bool flatbuffers::(anonymous namespace)::compareName<flatbuffers::EnumDef>(flatbuffers::EnumDef const*, flatbuffers::EnumDef const*) |
361 | | |
362 | 0 | template<typename T> static void AssignIndices(const std::vector<T *> &defvec) { |
363 | | // Pre-sort these vectors, such that we can set the correct indices for them. |
364 | 0 | auto vec = defvec; |
365 | 0 | std::sort(vec.begin(), vec.end(), compareName<T>); |
366 | 0 | for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i; |
367 | 0 | } Unexecuted instantiation: idl_parser.cpp:void flatbuffers::(anonymous namespace)::AssignIndices<flatbuffers::StructDef>(std::__1::vector<flatbuffers::StructDef*, std::__1::allocator<flatbuffers::StructDef*> > const&) Unexecuted instantiation: idl_parser.cpp:void flatbuffers::(anonymous namespace)::AssignIndices<flatbuffers::EnumDef>(std::__1::vector<flatbuffers::EnumDef*, std::__1::allocator<flatbuffers::EnumDef*> > const&) |
368 | | |
369 | | } // namespace |
370 | | |
371 | 43.3k | void Parser::Message(const std::string &msg) { |
372 | 43.3k | if (!error_.empty()) error_ += "\n"; // log all warnings and errors |
373 | 43.3k | error_ += file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : ""; |
374 | | // clang-format off |
375 | | |
376 | | #ifdef _WIN32 // MSVC alike |
377 | | error_ += |
378 | | "(" + NumToString(line_) + ", " + NumToString(CursorPosition()) + ")"; |
379 | | #else // gcc alike |
380 | 43.3k | if (file_being_parsed_.length()) error_ += ":"; |
381 | 43.3k | error_ += NumToString(line_) + ": " + NumToString(CursorPosition()); |
382 | 43.3k | #endif |
383 | | // clang-format on |
384 | 43.3k | error_ += ": " + msg; |
385 | 43.3k | } |
386 | | |
387 | 18.2k | void Parser::Warning(const std::string &msg) { |
388 | 18.2k | if (!opts.no_warnings) { |
389 | 18.2k | Message("warning: " + msg); |
390 | 18.2k | has_warning_ = true; // for opts.warnings_as_errors |
391 | 18.2k | } |
392 | 18.2k | } |
393 | | |
394 | 25.1k | CheckedError Parser::Error(const std::string &msg) { |
395 | 25.1k | Message("error: " + msg); |
396 | 25.1k | return CheckedError(true); |
397 | 25.1k | } |
398 | | |
399 | 11 | CheckedError Parser::RecurseError() { |
400 | 11 | return Error("maximum parsing depth " + NumToString(parse_depth_counter_) + |
401 | 11 | " reached"); |
402 | 11 | } |
403 | | |
404 | 0 | const std::string &Parser::GetPooledString(const std::string &s) const { |
405 | 0 | return *(string_cache_.insert(s).first); |
406 | 0 | } |
407 | | |
408 | | class Parser::ParseDepthGuard { |
409 | | public: |
410 | | explicit ParseDepthGuard(Parser *parser_not_null) |
411 | 680k | : parser_(*parser_not_null), caller_depth_(parser_.parse_depth_counter_) { |
412 | 680k | FLATBUFFERS_ASSERT(caller_depth_ <= (FLATBUFFERS_MAX_PARSING_DEPTH) && |
413 | 680k | "Check() must be called to prevent stack overflow"); |
414 | 680k | parser_.parse_depth_counter_ += 1; |
415 | 680k | } |
416 | | |
417 | 680k | ~ParseDepthGuard() { parser_.parse_depth_counter_ -= 1; } |
418 | | |
419 | 680k | CheckedError Check() { |
420 | 680k | return caller_depth_ >= (FLATBUFFERS_MAX_PARSING_DEPTH) |
421 | 680k | ? parser_.RecurseError() |
422 | 680k | : CheckedError(false); |
423 | 680k | } |
424 | | |
425 | | FLATBUFFERS_DELETE_FUNC(ParseDepthGuard(const ParseDepthGuard &)); |
426 | | FLATBUFFERS_DELETE_FUNC(ParseDepthGuard &operator=(const ParseDepthGuard &)); |
427 | | |
428 | | private: |
429 | | Parser &parser_; |
430 | | const int caller_depth_; |
431 | | }; |
432 | | |
433 | | std::string Namespace::GetFullyQualifiedName(const std::string &name, |
434 | 527k | size_t max_components) const { |
435 | | // Early exit if we don't have a defined namespace. |
436 | 527k | if (components.empty() || !max_components) { return name; } |
437 | 245k | std::string stream_str; |
438 | 1.29M | for (size_t i = 0; i < std::min(components.size(), max_components); i++) { |
439 | 1.05M | stream_str += components[i]; |
440 | 1.05M | stream_str += '.'; |
441 | 1.05M | } |
442 | 245k | if (!stream_str.empty()) stream_str.pop_back(); |
443 | 245k | if (name.length()) { |
444 | 245k | stream_str += '.'; |
445 | 245k | stream_str += name; |
446 | 245k | } |
447 | 245k | return stream_str; |
448 | 527k | } |
449 | | |
450 | 9.52k | std::string Parser::TokenToStringId(int t) const { |
451 | 9.52k | return t == kTokenIdentifier ? attribute_ : TokenToString(t); |
452 | 9.52k | } |
453 | | |
454 | | // Parses exactly nibbles worth of hex digits into a number, or error. |
455 | 2.77k | CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) { |
456 | 2.77k | FLATBUFFERS_ASSERT(nibbles > 0); |
457 | 13.2k | for (int i = 0; i < nibbles; i++) |
458 | 10.5k | if (!is_xdigit(cursor_[i])) |
459 | 40 | return Error("escape code must be followed by " + NumToString(nibbles) + |
460 | 40 | " hex digits"); |
461 | 2.73k | std::string target(cursor_, cursor_ + nibbles); |
462 | 2.73k | *val = StringToUInt(target.c_str(), 16); |
463 | 2.73k | cursor_ += nibbles; |
464 | 2.73k | return NoError(); |
465 | 2.77k | } |
466 | | |
467 | 27.3k | CheckedError Parser::SkipByteOrderMark() { |
468 | 27.3k | if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError(); |
469 | 21 | cursor_++; |
470 | 21 | if (static_cast<unsigned char>(*cursor_) != 0xbb) |
471 | 10 | return Error("invalid utf-8 byte order mark"); |
472 | 11 | cursor_++; |
473 | 11 | if (static_cast<unsigned char>(*cursor_) != 0xbf) |
474 | 10 | return Error("invalid utf-8 byte order mark"); |
475 | 1 | cursor_++; |
476 | 1 | return NoError(); |
477 | 11 | } |
478 | | |
479 | 4.78M | CheckedError Parser::Next() { |
480 | 4.78M | doc_comment_.clear(); |
481 | 4.78M | prev_cursor_ = cursor_; |
482 | 4.78M | bool seen_newline = cursor_ == source_; |
483 | 4.78M | attribute_.clear(); |
484 | 4.78M | attr_is_trivial_ascii_string_ = true; |
485 | 4.93M | for (;;) { |
486 | 4.93M | char c = *cursor_++; |
487 | 4.93M | token_ = c; |
488 | 4.93M | switch (c) { |
489 | 23.3k | case '\0': |
490 | 23.3k | cursor_--; |
491 | 23.3k | token_ = kTokenEof; |
492 | 23.3k | return NoError(); |
493 | 18.7k | case ' ': |
494 | 32.1k | case '\r': |
495 | 71.2k | case '\t': break; |
496 | 60.1k | case '\n': |
497 | 60.1k | MarkNewLine(); |
498 | 60.1k | seen_newline = true; |
499 | 60.1k | break; |
500 | 166k | case '{': |
501 | 316k | case '}': |
502 | 340k | case '(': |
503 | 363k | case ')': |
504 | 648k | case '[': |
505 | 922k | case ']': |
506 | 922k | case '<': |
507 | 922k | case '>': |
508 | 2.15M | case ',': |
509 | 2.51M | case ':': |
510 | 2.57M | case ';': |
511 | 2.72M | case '=': return NoError(); |
512 | 24.0k | case '\"': |
513 | 72.6k | case '\'': { |
514 | 72.6k | int unicode_high_surrogate = -1; |
515 | | |
516 | 1.46M | while (*cursor_ != c) { |
517 | 1.39M | if (*cursor_ < ' ' && static_cast<signed char>(*cursor_) >= 0) |
518 | 290 | return Error("illegal character in string constant"); |
519 | 1.39M | if (*cursor_ == '\\') { |
520 | 6.43k | attr_is_trivial_ascii_string_ = false; // has escape sequence |
521 | 6.43k | cursor_++; |
522 | 6.43k | if (unicode_high_surrogate != -1 && *cursor_ != 'u') { |
523 | 14 | return Error( |
524 | 14 | "illegal Unicode sequence (unpaired high surrogate)"); |
525 | 14 | } |
526 | 6.41k | switch (*cursor_) { |
527 | 405 | case 'n': |
528 | 405 | attribute_ += '\n'; |
529 | 405 | cursor_++; |
530 | 405 | break; |
531 | 242 | case 't': |
532 | 242 | attribute_ += '\t'; |
533 | 242 | cursor_++; |
534 | 242 | break; |
535 | 736 | case 'r': |
536 | 736 | attribute_ += '\r'; |
537 | 736 | cursor_++; |
538 | 736 | break; |
539 | 625 | case 'b': |
540 | 625 | attribute_ += '\b'; |
541 | 625 | cursor_++; |
542 | 625 | break; |
543 | 422 | case 'f': |
544 | 422 | attribute_ += '\f'; |
545 | 422 | cursor_++; |
546 | 422 | break; |
547 | 248 | case '\"': |
548 | 248 | attribute_ += '\"'; |
549 | 248 | cursor_++; |
550 | 248 | break; |
551 | 233 | case '\'': |
552 | 233 | attribute_ += '\''; |
553 | 233 | cursor_++; |
554 | 233 | break; |
555 | 349 | case '\\': |
556 | 349 | attribute_ += '\\'; |
557 | 349 | cursor_++; |
558 | 349 | break; |
559 | 372 | case '/': |
560 | 372 | attribute_ += '/'; |
561 | 372 | cursor_++; |
562 | 372 | break; |
563 | 247 | case 'x': { // Not in the JSON standard |
564 | 247 | cursor_++; |
565 | 247 | uint64_t val; |
566 | 247 | ECHECK(ParseHexNum(2, &val)); |
567 | 242 | attribute_ += static_cast<char>(val); |
568 | 242 | break; |
569 | 247 | } |
570 | 2.52k | case 'u': { |
571 | 2.52k | cursor_++; |
572 | 2.52k | uint64_t val; |
573 | 2.52k | ECHECK(ParseHexNum(4, &val)); |
574 | 2.49k | if (val >= 0xD800 && val <= 0xDBFF) { |
575 | 656 | if (unicode_high_surrogate != -1) { |
576 | 2 | return Error( |
577 | 2 | "illegal Unicode sequence (multiple high surrogates)"); |
578 | 654 | } else { |
579 | 654 | unicode_high_surrogate = static_cast<int>(val); |
580 | 654 | } |
581 | 1.83k | } else if (val >= 0xDC00 && val <= 0xDFFF) { |
582 | 609 | if (unicode_high_surrogate == -1) { |
583 | 7 | return Error( |
584 | 7 | "illegal Unicode sequence (unpaired low surrogate)"); |
585 | 602 | } else { |
586 | 602 | int code_point = 0x10000 + |
587 | 602 | ((unicode_high_surrogate & 0x03FF) << 10) + |
588 | 602 | (val & 0x03FF); |
589 | 602 | ToUTF8(code_point, &attribute_); |
590 | 602 | unicode_high_surrogate = -1; |
591 | 602 | } |
592 | 1.22k | } else { |
593 | 1.22k | if (unicode_high_surrogate != -1) { |
594 | 1 | return Error( |
595 | 1 | "illegal Unicode sequence (unpaired high surrogate)"); |
596 | 1 | } |
597 | 1.22k | ToUTF8(static_cast<int>(val), &attribute_); |
598 | 1.22k | } |
599 | 2.48k | break; |
600 | 2.49k | } |
601 | 2.48k | default: return Error("unknown escape code in string constant"); |
602 | 6.41k | } |
603 | 1.39M | } else { // printable chars + UTF-8 bytes |
604 | 1.39M | if (unicode_high_surrogate != -1) { |
605 | 12 | return Error( |
606 | 12 | "illegal Unicode sequence (unpaired high surrogate)"); |
607 | 12 | } |
608 | | // reset if non-printable |
609 | 1.39M | attr_is_trivial_ascii_string_ &= |
610 | 1.39M | check_ascii_range(*cursor_, ' ', '~'); |
611 | | |
612 | 1.39M | attribute_ += *cursor_++; |
613 | 1.39M | } |
614 | 1.39M | } |
615 | 72.2k | if (unicode_high_surrogate != -1) { |
616 | 9 | return Error("illegal Unicode sequence (unpaired high surrogate)"); |
617 | 9 | } |
618 | 72.2k | cursor_++; |
619 | 72.2k | if (!attr_is_trivial_ascii_string_ && !opts.allow_non_utf8 && |
620 | 72.2k | !ValidateUTF8(attribute_)) { |
621 | 72 | return Error("illegal UTF-8 sequence"); |
622 | 72 | } |
623 | 72.2k | token_ = kTokenStringConstant; |
624 | 72.2k | return NoError(); |
625 | 72.2k | } |
626 | 18.1k | case '/': |
627 | 18.1k | if (*cursor_ == '/') { |
628 | 17.8k | const char *start = ++cursor_; |
629 | 183k | while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++; |
630 | 17.8k | if (*start == '/') { // documentation comment |
631 | 12.9k | if (!seen_newline) |
632 | 1 | return Error( |
633 | 1 | "a documentation comment should be on a line on its own"); |
634 | 12.9k | doc_comment_.push_back(std::string(start + 1, cursor_)); |
635 | 12.9k | } |
636 | 17.8k | break; |
637 | 17.8k | } else if (*cursor_ == '*') { |
638 | 237 | cursor_++; |
639 | | // TODO: make nested. |
640 | 995 | while (*cursor_ != '*' || cursor_[1] != '/') { |
641 | 801 | if (*cursor_ == '\n') MarkNewLine(); |
642 | 801 | if (!*cursor_) return Error("end of file in comment"); |
643 | 758 | cursor_++; |
644 | 758 | } |
645 | 194 | cursor_ += 2; |
646 | 194 | break; |
647 | 237 | } |
648 | 37 | FLATBUFFERS_FALLTHROUGH(); // else fall thru |
649 | 1.96M | default: |
650 | 1.96M | if (IsIdentifierStart(c)) { |
651 | | // Collect all chars of an identifier: |
652 | 1.15M | const char *start = cursor_ - 1; |
653 | 5.76M | while (IsIdentifierStart(*cursor_) || is_digit(*cursor_)) cursor_++; |
654 | 1.15M | attribute_.append(start, cursor_); |
655 | 1.15M | token_ = kTokenIdentifier; |
656 | 1.15M | return NoError(); |
657 | 1.15M | } |
658 | | |
659 | 813k | const auto has_sign = (c == '+') || (c == '-'); |
660 | 813k | if (has_sign) { |
661 | | // Check for +/-inf which is considered a float constant. |
662 | 10.5k | if (strncmp(cursor_, "inf", 3) == 0 && |
663 | 10.5k | !(IsIdentifierStart(cursor_[3]) || is_digit(cursor_[3]))) { |
664 | 916 | attribute_.assign(cursor_ - 1, cursor_ + 3); |
665 | 916 | token_ = kTokenFloatConstant; |
666 | 916 | cursor_ += 3; |
667 | 916 | return NoError(); |
668 | 916 | } |
669 | | |
670 | 9.62k | if (IsIdentifierStart(*cursor_)) { |
671 | | // '-'/'+' and following identifier - it could be a predefined |
672 | | // constant. Return the sign in token_, see ParseSingleValue. |
673 | 2.37k | return NoError(); |
674 | 2.37k | } |
675 | 9.62k | } |
676 | | |
677 | 810k | auto dot_lvl = |
678 | 810k | (c == '.') ? 0 : 1; // dot_lvl==0 <=> exactly one '.' seen |
679 | 810k | if (!dot_lvl && !is_digit(*cursor_)) return NoError(); // enum? |
680 | | // Parser accepts hexadecimal-floating-literal (see C++ 5.13.4). |
681 | 754k | if (is_digit(c) || has_sign || !dot_lvl) { |
682 | 753k | const auto start = cursor_ - 1; |
683 | 753k | auto start_digits = !is_digit(c) ? cursor_ : cursor_ - 1; |
684 | 753k | if (!is_digit(c) && is_digit(*cursor_)) { |
685 | 37.8k | start_digits = cursor_; // see digit in cursor_ position |
686 | 37.8k | c = *cursor_++; |
687 | 37.8k | } |
688 | | // hex-float can't begind with '.' |
689 | 753k | auto use_hex = dot_lvl && (c == '0') && is_alpha_char(*cursor_, 'X'); |
690 | 753k | if (use_hex) start_digits = ++cursor_; // '0x' is the prefix, skip it |
691 | | // Read an integer number or mantisa of float-point number. |
692 | 757k | do { |
693 | 757k | if (use_hex) { |
694 | 65.8k | while (is_xdigit(*cursor_)) cursor_++; |
695 | 752k | } else { |
696 | 1.35M | while (is_digit(*cursor_)) cursor_++; |
697 | 752k | } |
698 | 757k | } while ((*cursor_ == '.') && (++cursor_) && (--dot_lvl >= 0)); |
699 | | // Exponent of float-point number. |
700 | 753k | if ((dot_lvl >= 0) && (cursor_ > start_digits)) { |
701 | | // The exponent suffix of hexadecimal float number is mandatory. |
702 | 753k | if (use_hex && !dot_lvl) start_digits = cursor_; |
703 | 753k | if ((use_hex && is_alpha_char(*cursor_, 'P')) || |
704 | 753k | is_alpha_char(*cursor_, 'E')) { |
705 | 1.94k | dot_lvl = 0; // Emulate dot to signal about float-point number. |
706 | 1.94k | cursor_++; |
707 | 1.94k | if (*cursor_ == '+' || *cursor_ == '-') cursor_++; |
708 | 1.94k | start_digits = cursor_; // the exponent-part has to have digits |
709 | | // Exponent is decimal integer number |
710 | 16.3k | while (is_digit(*cursor_)) cursor_++; |
711 | 1.94k | if (*cursor_ == '.') { |
712 | 1 | cursor_++; // If see a dot treat it as part of invalid number. |
713 | 1 | dot_lvl = -1; // Fall thru to Error(). |
714 | 1 | } |
715 | 1.94k | } |
716 | 753k | } |
717 | | // Finalize. |
718 | 753k | if ((dot_lvl >= 0) && (cursor_ > start_digits)) { |
719 | 753k | attribute_.append(start, cursor_); |
720 | 753k | token_ = dot_lvl ? kTokenIntegerConstant : kTokenFloatConstant; |
721 | 753k | return NoError(); |
722 | 753k | } else { |
723 | 136 | return Error("invalid number: " + std::string(start, cursor_)); |
724 | 136 | } |
725 | 753k | } |
726 | 538 | std::string ch; |
727 | 538 | ch = c; |
728 | 538 | if (false == check_ascii_range(c, ' ', '~')) |
729 | 402 | ch = "code: " + NumToString(c); |
730 | 538 | return Error("illegal character: " + ch); |
731 | 4.93M | } |
732 | 4.93M | } |
733 | 4.78M | } |
734 | | |
735 | | // Check if a given token is next. |
736 | 5.81M | bool Parser::Is(int t) const { return t == token_; } |
737 | | |
738 | 2.04M | bool Parser::IsIdent(const char *id) const { |
739 | 2.04M | return token_ == kTokenIdentifier && attribute_ == id; |
740 | 2.04M | } |
741 | | |
742 | | // Expect a given token to be next, consume it, or error if not present. |
743 | 2.97M | CheckedError Parser::Expect(int t) { |
744 | 2.97M | if (t != token_) { |
745 | 8.97k | return Error("expecting: " + TokenToString(t) + |
746 | 8.97k | " instead got: " + TokenToStringId(token_)); |
747 | 8.97k | } |
748 | 2.96M | NEXT(); |
749 | 2.96M | return NoError(); |
750 | 2.96M | } |
751 | | |
752 | 427k | CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) { |
753 | 446k | while (Is('.')) { |
754 | 19.1k | NEXT(); |
755 | 19.1k | *id += "."; |
756 | 19.1k | *id += attribute_; |
757 | 19.1k | if (last) *last = attribute_; |
758 | 19.1k | EXPECT(kTokenIdentifier); |
759 | 19.1k | } |
760 | 427k | return NoError(); |
761 | 427k | } |
762 | | |
763 | 57.7k | EnumDef *Parser::LookupEnum(const std::string &id) { |
764 | | // Search thru parent namespaces. |
765 | 57.7k | return LookupTableByName(enums_, id, *current_namespace_, 0); |
766 | 57.7k | } |
767 | | |
768 | 682k | StructDef *Parser::LookupStruct(const std::string &id) const { |
769 | 682k | auto sd = structs_.Lookup(id); |
770 | 682k | if (sd) sd->refcount++; |
771 | 682k | return sd; |
772 | 682k | } |
773 | | |
774 | | StructDef *Parser::LookupStructThruParentNamespaces( |
775 | 200k | const std::string &id) const { |
776 | 200k | auto sd = LookupTableByName(structs_, id, *current_namespace_, 1); |
777 | 200k | if (sd) sd->refcount++; |
778 | 200k | return sd; |
779 | 200k | } |
780 | | |
781 | 57.6k | CheckedError Parser::ParseTypeIdent(Type &type) { |
782 | 57.6k | std::string id = attribute_; |
783 | 57.6k | EXPECT(kTokenIdentifier); |
784 | 57.6k | ECHECK(ParseNamespacing(&id, nullptr)); |
785 | 57.5k | auto enum_def = LookupEnum(id); |
786 | 57.5k | if (enum_def) { |
787 | 30.1k | type = enum_def->underlying_type; |
788 | 30.1k | if (enum_def->is_union) type.base_type = BASE_TYPE_UNION; |
789 | 30.1k | } else { |
790 | 27.4k | type.base_type = BASE_TYPE_STRUCT; |
791 | 27.4k | type.struct_def = LookupCreateStruct(id); |
792 | 27.4k | } |
793 | 57.5k | return NoError(); |
794 | 57.6k | } |
795 | | |
796 | | // Parse any IDL type. |
797 | 78.7k | CheckedError Parser::ParseType(Type &type) { |
798 | 78.7k | if (token_ == kTokenIdentifier) { |
799 | 65.8k | if (IsIdent("bool")) { |
800 | 737 | type.base_type = BASE_TYPE_BOOL; |
801 | 737 | NEXT(); |
802 | 65.0k | } else if (IsIdent("byte") || IsIdent("int8")) { |
803 | 1.03k | type.base_type = BASE_TYPE_CHAR; |
804 | 1.03k | NEXT(); |
805 | 64.0k | } else if (IsIdent("ubyte") || IsIdent("uint8")) { |
806 | 4.92k | type.base_type = BASE_TYPE_UCHAR; |
807 | 4.92k | NEXT(); |
808 | 59.1k | } else if (IsIdent("short") || IsIdent("int16")) { |
809 | 881 | type.base_type = BASE_TYPE_SHORT; |
810 | 881 | NEXT(); |
811 | 58.2k | } else if (IsIdent("ushort") || IsIdent("uint16")) { |
812 | 708 | type.base_type = BASE_TYPE_USHORT; |
813 | 708 | NEXT(); |
814 | 57.5k | } else if (IsIdent("int") || IsIdent("int32")) { |
815 | 1.67k | type.base_type = BASE_TYPE_INT; |
816 | 1.67k | NEXT(); |
817 | 55.8k | } else if (IsIdent("uint") || IsIdent("uint32")) { |
818 | 1.45k | type.base_type = BASE_TYPE_UINT; |
819 | 1.45k | NEXT(); |
820 | 54.3k | } else if (IsIdent("long") || IsIdent("int64")) { |
821 | 2.58k | type.base_type = BASE_TYPE_LONG; |
822 | 2.58k | NEXT(); |
823 | 51.8k | } else if (IsIdent("ulong") || IsIdent("uint64")) { |
824 | 5.32k | type.base_type = BASE_TYPE_ULONG; |
825 | 5.32k | NEXT(); |
826 | 46.4k | } else if (IsIdent("float") || IsIdent("float32")) { |
827 | 791 | type.base_type = BASE_TYPE_FLOAT; |
828 | 791 | NEXT(); |
829 | 45.7k | } else if (IsIdent("double") || IsIdent("float64")) { |
830 | 493 | type.base_type = BASE_TYPE_DOUBLE; |
831 | 493 | NEXT(); |
832 | 45.2k | } else if (IsIdent("string")) { |
833 | 581 | type.base_type = BASE_TYPE_STRING; |
834 | 581 | NEXT(); |
835 | 44.6k | } else { |
836 | 44.6k | ECHECK(ParseTypeIdent(type)); |
837 | 44.5k | } |
838 | 65.8k | } else if (token_ == '[') { |
839 | 12.9k | ParseDepthGuard depth_guard(this); |
840 | 12.9k | ECHECK(depth_guard.Check()); |
841 | 12.9k | NEXT(); |
842 | 12.9k | Type subtype; |
843 | 12.9k | ECHECK(ParseType(subtype)); |
844 | 12.6k | if (IsSeries(subtype)) { |
845 | | // We could support this, but it will complicate things, and it's |
846 | | // easier to work around with a struct around the inner vector. |
847 | 2 | return Error("nested vector types not supported (wrap in table first)"); |
848 | 2 | } |
849 | 12.6k | if (token_ == ':') { |
850 | 695 | NEXT(); |
851 | 693 | if (token_ != kTokenIntegerConstant) { |
852 | 6 | return Error("length of fixed-length array must be an integer value"); |
853 | 6 | } |
854 | 687 | uint16_t fixed_length = 0; |
855 | 687 | bool check = StringToNumber(attribute_.c_str(), &fixed_length); |
856 | 687 | if (!check || fixed_length < 1) { |
857 | 117 | return Error( |
858 | 117 | "length of fixed-length array must be positive and fit to " |
859 | 117 | "uint16_t type"); |
860 | 117 | } |
861 | 570 | type = Type(BASE_TYPE_ARRAY, subtype.struct_def, subtype.enum_def, |
862 | 570 | fixed_length); |
863 | 570 | NEXT(); |
864 | 11.9k | } else { |
865 | 11.9k | type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def); |
866 | 11.9k | } |
867 | 12.5k | type.element = subtype.base_type; |
868 | 12.5k | EXPECT(']'); |
869 | 12.4k | } else { |
870 | 40 | return Error("illegal type syntax"); |
871 | 40 | } |
872 | 78.2k | return NoError(); |
873 | 78.7k | } |
874 | | |
875 | | CheckedError Parser::AddField(StructDef &struct_def, const std::string &name, |
876 | 48.7k | const Type &type, FieldDef **dest) { |
877 | 48.7k | auto &field = *new FieldDef(); |
878 | 48.7k | field.value.offset = |
879 | 48.7k | FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size())); |
880 | 48.7k | field.name = name; |
881 | 48.7k | field.file = struct_def.file; |
882 | 48.7k | field.value.type = type; |
883 | 48.7k | if (struct_def.fixed) { // statically compute the field offset |
884 | 2.26k | auto size = InlineSize(type); |
885 | 2.26k | auto alignment = InlineAlignment(type); |
886 | | // structs_ need to have a predictable format, so we need to align to |
887 | | // the largest scalar |
888 | 2.26k | struct_def.minalign = std::max(struct_def.minalign, alignment); |
889 | 2.26k | struct_def.PadLastField(alignment); |
890 | 2.26k | field.value.offset = static_cast<voffset_t>(struct_def.bytesize); |
891 | 2.26k | struct_def.bytesize += size; |
892 | 2.26k | } |
893 | 48.7k | if (struct_def.fields.Add(name, &field)) |
894 | 44 | return Error("field already exists: " + name); |
895 | 48.7k | *dest = &field; |
896 | 48.7k | return NoError(); |
897 | 48.7k | } |
898 | | |
899 | 37.6k | CheckedError Parser::ParseField(StructDef &struct_def) { |
900 | 37.6k | std::string name = attribute_; |
901 | | |
902 | 37.6k | if (LookupCreateStruct(name, false, false)) |
903 | 27 | return Error("field name can not be the same as table/struct name"); |
904 | | |
905 | 37.6k | if (!IsLowerSnakeCase(name)) { |
906 | 11.2k | Warning("field names should be lowercase snake_case, got: " + name); |
907 | 11.2k | } |
908 | | |
909 | 37.6k | std::vector<std::string> dc = doc_comment_; |
910 | 37.6k | EXPECT(kTokenIdentifier); |
911 | 37.4k | EXPECT(':'); |
912 | 37.2k | Type type; |
913 | 37.2k | ECHECK(ParseType(type)); |
914 | | |
915 | 37.1k | if (struct_def.fixed) { |
916 | 2.27k | if (IsIncompleteStruct(type) || |
917 | 2.27k | (IsArray(type) && IsIncompleteStruct(type.VectorType()))) { |
918 | 10 | std::string type_name = IsArray(type) ? type.VectorType().struct_def->name |
919 | 10 | : type.struct_def->name; |
920 | 10 | return Error( |
921 | 10 | std::string("Incomplete type in struct is not allowed, type name: ") + |
922 | 10 | type_name); |
923 | 10 | } |
924 | | |
925 | 2.26k | auto valid = IsScalar(type.base_type) || IsStruct(type); |
926 | 2.26k | if (!valid && IsArray(type)) { |
927 | 531 | const auto &elem_type = type.VectorType(); |
928 | 531 | valid |= IsScalar(elem_type.base_type) || IsStruct(elem_type); |
929 | 531 | } |
930 | 2.26k | if (!valid) |
931 | 2 | return Error("structs may contain only scalar or struct fields"); |
932 | 2.26k | } |
933 | | |
934 | 37.1k | if (!struct_def.fixed && IsArray(type)) |
935 | 1 | return Error("fixed-length array in table must be wrapped in struct"); |
936 | | |
937 | 37.1k | if (IsArray(type)) { |
938 | 530 | advanced_features_ |= reflection::AdvancedArrayFeatures; |
939 | 530 | if (!SupportsAdvancedArrayFeatures()) { |
940 | 0 | return Error( |
941 | 0 | "Arrays are not yet supported in all " |
942 | 0 | "the specified programming languages."); |
943 | 0 | } |
944 | 530 | } |
945 | | |
946 | 37.1k | FieldDef *typefield = nullptr; |
947 | 37.1k | if (type.base_type == BASE_TYPE_UNION) { |
948 | | // For union fields, add a second auto-generated field to hold the type, |
949 | | // with a special suffix. |
950 | | |
951 | | // To ensure compatibility with many codes that rely on the BASE_TYPE_UTYPE value to identify union type fields. |
952 | 9.70k | Type union_type(type.enum_def->underlying_type); |
953 | 9.70k | union_type.base_type = BASE_TYPE_UTYPE; |
954 | 9.70k | ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),union_type, &typefield)); |
955 | | |
956 | 27.4k | } else if (IsVector(type) && type.element == BASE_TYPE_UNION) { |
957 | 1.90k | advanced_features_ |= reflection::AdvancedUnionFeatures; |
958 | | // Only cpp, js and ts supports the union vector feature so far. |
959 | 1.90k | if (!SupportsAdvancedUnionFeatures()) { |
960 | 0 | return Error( |
961 | 0 | "Vectors of unions are not yet supported in at least one of " |
962 | 0 | "the specified programming languages."); |
963 | 0 | } |
964 | | // For vector of union fields, add a second auto-generated vector field to |
965 | | // hold the types, with a special suffix. |
966 | 1.90k | Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def); |
967 | 1.90k | union_vector.element = BASE_TYPE_UTYPE; |
968 | 1.90k | ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), union_vector, |
969 | 1.90k | &typefield)); |
970 | 1.90k | } |
971 | | |
972 | 37.1k | FieldDef *field; |
973 | 37.1k | ECHECK(AddField(struct_def, name, type, &field)); |
974 | | |
975 | 37.1k | if (typefield) { |
976 | | // We preserve the relation between the typefield |
977 | | // and field, so we can easily map it in the code |
978 | | // generators. |
979 | 11.6k | typefield->sibling_union_field = field; |
980 | 11.6k | field->sibling_union_field = typefield; |
981 | 11.6k | } |
982 | | |
983 | 37.1k | if (token_ == '=') { |
984 | 5.11k | NEXT(); |
985 | 5.11k | ECHECK(ParseSingleValue(&field->name, field->value, true)); |
986 | 3.76k | if (IsStruct(type) || (struct_def.fixed && field->value.constant != "0")) |
987 | 16 | return Error( |
988 | 16 | "default values are not supported for struct fields, table fields, " |
989 | 16 | "or in structs."); |
990 | 3.75k | if (IsString(type) || IsVector(type)) { |
991 | 154 | advanced_features_ |= reflection::DefaultVectorsAndStrings; |
992 | 154 | if (field->value.constant != "0" && !SupportsDefaultVectorsAndStrings()) { |
993 | 0 | return Error( |
994 | 0 | "Default values for strings and vectors are not supported in one " |
995 | 0 | "of the specified programming languages"); |
996 | 0 | } |
997 | 154 | } |
998 | | |
999 | 3.75k | if (IsVector(type) && field->value.constant != "0" && |
1000 | 3.75k | field->value.constant != "[]") { |
1001 | 0 | return Error("The only supported default for vectors is `[]`."); |
1002 | 0 | } |
1003 | 3.75k | } |
1004 | | |
1005 | | // Append .0 if the value has not it (skip hex and scientific floats). |
1006 | | // This suffix needed for generated C++ code. |
1007 | 35.7k | if (IsFloat(type.base_type)) { |
1008 | 795 | auto &text = field->value.constant; |
1009 | 795 | FLATBUFFERS_ASSERT(false == text.empty()); |
1010 | 795 | auto s = text.c_str(); |
1011 | 989 | while (*s == ' ') s++; |
1012 | 795 | if (*s == '-' || *s == '+') s++; |
1013 | | // 1) A float constants (nan, inf, pi, etc) is a kind of identifier. |
1014 | | // 2) A float number needn't ".0" at the end if it has exponent. |
1015 | 795 | if ((false == IsIdentifierStart(*s)) && |
1016 | 795 | (std::string::npos == field->value.constant.find_first_of(".eEpP"))) { |
1017 | 524 | field->value.constant += ".0"; |
1018 | 524 | } |
1019 | 795 | } |
1020 | | |
1021 | 35.7k | field->doc_comment = dc; |
1022 | 35.7k | ECHECK(ParseMetaData(&field->attributes)); |
1023 | 35.7k | field->deprecated = field->attributes.Lookup("deprecated") != nullptr; |
1024 | 35.7k | auto hash_name = field->attributes.Lookup("hash"); |
1025 | 35.7k | if (hash_name) { |
1026 | 504 | switch ((IsVector(type)) ? type.element : type.base_type) { |
1027 | 52 | case BASE_TYPE_SHORT: |
1028 | 59 | case BASE_TYPE_USHORT: { |
1029 | 59 | if (FindHashFunction16(hash_name->constant.c_str()) == nullptr) |
1030 | 57 | return Error("Unknown hashing algorithm for 16 bit types: " + |
1031 | 57 | hash_name->constant); |
1032 | 2 | break; |
1033 | 59 | } |
1034 | 136 | case BASE_TYPE_INT: |
1035 | 193 | case BASE_TYPE_UINT: { |
1036 | 193 | if (FindHashFunction32(hash_name->constant.c_str()) == nullptr) |
1037 | 72 | return Error("Unknown hashing algorithm for 32 bit types: " + |
1038 | 72 | hash_name->constant); |
1039 | 121 | break; |
1040 | 193 | } |
1041 | 206 | case BASE_TYPE_LONG: |
1042 | 248 | case BASE_TYPE_ULONG: { |
1043 | 248 | if (FindHashFunction64(hash_name->constant.c_str()) == nullptr) |
1044 | 87 | return Error("Unknown hashing algorithm for 64 bit types: " + |
1045 | 87 | hash_name->constant); |
1046 | 161 | break; |
1047 | 248 | } |
1048 | 161 | default: |
1049 | 4 | return Error( |
1050 | 4 | "only short, ushort, int, uint, long and ulong data types support " |
1051 | 4 | "hashing."); |
1052 | 504 | } |
1053 | 504 | } |
1054 | | |
1055 | 35.5k | if (field->attributes.Lookup("vector64") != nullptr) { |
1056 | 240 | if (!IsVector(type)) { |
1057 | 1 | return Error("`vector64` attribute can only be applied on vectors."); |
1058 | 1 | } |
1059 | | |
1060 | | // Upgrade the type to be a BASE_TYPE_VECTOR64, since the attributes are |
1061 | | // parsed after the type. |
1062 | 239 | const BaseType element_base_type = type.element; |
1063 | 239 | type = Type(BASE_TYPE_VECTOR64, type.struct_def, type.enum_def); |
1064 | 239 | type.element = element_base_type; |
1065 | | |
1066 | | // Since the field was already added to the parent object, update the type |
1067 | | // in place. |
1068 | 239 | field->value.type = type; |
1069 | | |
1070 | | // 64-bit vectors imply the offset64 attribute. |
1071 | 239 | field->offset64 = true; |
1072 | 239 | } |
1073 | | |
1074 | | // Record that this field uses 64-bit offsets. |
1075 | 35.5k | if (field->attributes.Lookup("offset64") != nullptr) { |
1076 | | // TODO(derekbailey): would be nice to have this be a recommendation or hint |
1077 | | // instead of a warning. |
1078 | 278 | if (type.base_type == BASE_TYPE_VECTOR64) { |
1079 | 1 | Warning("attribute `vector64` implies `offset64` and isn't required."); |
1080 | 1 | } |
1081 | | |
1082 | 278 | field->offset64 = true; |
1083 | 278 | } |
1084 | | |
1085 | | // Check for common conditions with Offset64 fields. |
1086 | 35.5k | if (field->offset64) { |
1087 | | // TODO(derekbailey): this is where we can disable string support for |
1088 | | // offset64, as that is not a hard requirement to have. |
1089 | 516 | if (!IsString(type) && !IsVector(type)) { |
1090 | 5 | return Error( |
1091 | 5 | "only string and vectors can have `offset64` attribute applied"); |
1092 | 5 | } |
1093 | | |
1094 | | // If this is a Vector, only scalar and scalar-like (structs) items are |
1095 | | // allowed. |
1096 | | // TODO(derekbailey): allow vector of strings, just require that the strings |
1097 | | // are Offset64<string>. |
1098 | 511 | if (IsVector(type) && |
1099 | 511 | !((IsScalar(type.element) && !IsEnum(type.VectorType())) || |
1100 | 461 | IsStruct(type.VectorType()))) { |
1101 | 7 | return Error("only vectors of scalars are allowed to be 64-bit."); |
1102 | 7 | } |
1103 | | |
1104 | | // Lastly, check if it is supported by the specified generated languages. Do |
1105 | | // this last so the above checks can inform the user of schema errors to fix |
1106 | | // first. |
1107 | 504 | if (!Supports64BitOffsets()) { |
1108 | 0 | return Error( |
1109 | 0 | "fields using 64-bit offsets are not yet supported in at least one " |
1110 | 0 | "of the specified programming languages."); |
1111 | 0 | } |
1112 | 504 | } |
1113 | | |
1114 | | // For historical convenience reasons, string keys are assumed required. |
1115 | | // Scalars are kDefault unless otherwise specified. |
1116 | | // Nonscalars are kOptional unless required; |
1117 | 35.4k | field->key = field->attributes.Lookup("key") != nullptr; |
1118 | 35.4k | const bool required = field->attributes.Lookup("required") != nullptr || |
1119 | 35.4k | (IsString(type) && field->key); |
1120 | 35.4k | const bool default_str_or_vec = |
1121 | 35.4k | ((IsString(type) || IsVector(type)) && field->value.constant != "0"); |
1122 | 35.4k | const bool optional = IsScalar(type.base_type) |
1123 | 35.4k | ? (field->value.constant == "null") |
1124 | 35.4k | : !(required || default_str_or_vec); |
1125 | 35.4k | if (required && optional) { |
1126 | 0 | return Error("Fields cannot be both optional and required."); |
1127 | 0 | } |
1128 | 35.4k | field->presence = FieldDef::MakeFieldPresence(optional, required); |
1129 | | |
1130 | 35.4k | if (required && (struct_def.fixed || IsScalar(type.base_type))) { |
1131 | 2 | return Error("only non-scalar fields in tables may be 'required'"); |
1132 | 2 | } |
1133 | 35.4k | if (field->key) { |
1134 | 1.15k | if (struct_def.has_key) return Error("only one field may be set as 'key'"); |
1135 | 1.14k | struct_def.has_key = true; |
1136 | 1.14k | auto is_valid = |
1137 | 1.14k | IsScalar(type.base_type) || IsString(type) || IsStruct(type); |
1138 | 1.14k | if (IsArray(type)) { |
1139 | 4 | is_valid |= |
1140 | 4 | IsScalar(type.VectorType().base_type) || IsStruct(type.VectorType()); |
1141 | 4 | } |
1142 | 1.14k | if (!is_valid) { |
1143 | 5 | return Error( |
1144 | 5 | "'key' field must be string, scalar type or fixed size array of " |
1145 | 5 | "scalars"); |
1146 | 5 | } |
1147 | 1.14k | } |
1148 | | |
1149 | 35.4k | if (field->IsScalarOptional()) { |
1150 | 856 | advanced_features_ |= reflection::OptionalScalars; |
1151 | 856 | if (type.enum_def && type.enum_def->Lookup("null")) { |
1152 | 1 | FLATBUFFERS_ASSERT(IsInteger(type.base_type)); |
1153 | 1 | return Error( |
1154 | 1 | "the default 'null' is reserved for declaring optional scalar " |
1155 | 1 | "fields, it conflicts with declaration of enum '" + |
1156 | 1 | type.enum_def->name + "'."); |
1157 | 1 | } |
1158 | 855 | if (field->attributes.Lookup("key")) { |
1159 | 1 | return Error( |
1160 | 1 | "only a non-optional scalar field can be used as a 'key' field"); |
1161 | 1 | } |
1162 | 854 | if (!SupportsOptionalScalars()) { |
1163 | 0 | return Error( |
1164 | 0 | "Optional scalars are not yet supported in at least one of " |
1165 | 0 | "the specified programming languages."); |
1166 | 0 | } |
1167 | 854 | } |
1168 | | |
1169 | 35.4k | if (type.enum_def) { |
1170 | | // Verify the enum's type and default value. |
1171 | 13.4k | const std::string &constant = field->value.constant; |
1172 | 13.4k | if (type.base_type == BASE_TYPE_UNION) { |
1173 | 9.69k | if (constant != "0") { return Error("Union defaults must be NONE"); } |
1174 | 9.69k | } else if (IsVector(type)) { |
1175 | 1.90k | if (constant != "0" && constant != "[]") { |
1176 | 0 | return Error("Vector defaults may only be `[]`."); |
1177 | 0 | } |
1178 | 1.90k | } else if (IsArray(type)) { |
1179 | 10 | if (constant != "0") { |
1180 | 0 | return Error("Array defaults are not supported yet."); |
1181 | 0 | } |
1182 | 1.80k | } else { |
1183 | 1.80k | if (!IsInteger(type.base_type)) { |
1184 | 0 | return Error("Enums must have integer base types"); |
1185 | 0 | } |
1186 | | // Optional and bitflags enums may have default constants that are not |
1187 | | // their specified variants. |
1188 | 1.80k | if (!field->IsOptional() && |
1189 | 1.80k | type.enum_def->attributes.Lookup("bit_flags") == nullptr) { |
1190 | 1.61k | if (type.enum_def->FindByValue(constant) == nullptr) { |
1191 | 223 | return Error("default value of `" + constant + "` for " + "field `" + |
1192 | 223 | name + "` is not part of enum `" + type.enum_def->name + |
1193 | 223 | "`."); |
1194 | 223 | } |
1195 | 1.61k | } |
1196 | 1.80k | } |
1197 | 13.4k | } |
1198 | | |
1199 | 35.2k | if (field->deprecated && struct_def.fixed) |
1200 | 1 | return Error("can't deprecate fields in a struct"); |
1201 | | |
1202 | 35.2k | auto cpp_type = field->attributes.Lookup("cpp_type"); |
1203 | 35.2k | if (cpp_type) { |
1204 | 2 | if (!hash_name) |
1205 | 1 | return Error("cpp_type can only be used with a hashed field"); |
1206 | | /// forcing cpp_ptr_type to 'naked' if unset |
1207 | 1 | auto cpp_ptr_type = field->attributes.Lookup("cpp_ptr_type"); |
1208 | 1 | if (!cpp_ptr_type) { |
1209 | 1 | auto val = new Value(); |
1210 | 1 | val->type = cpp_type->type; |
1211 | 1 | val->constant = "naked"; |
1212 | 1 | field->attributes.Add("cpp_ptr_type", val); |
1213 | 1 | } |
1214 | 1 | } |
1215 | | |
1216 | 35.2k | field->shared = field->attributes.Lookup("shared") != nullptr; |
1217 | 35.2k | if (field->shared && field->value.type.base_type != BASE_TYPE_STRING) |
1218 | 4 | return Error("shared can only be defined on strings"); |
1219 | | |
1220 | 35.2k | auto field_native_custom_alloc = |
1221 | 35.2k | field->attributes.Lookup("native_custom_alloc"); |
1222 | 35.2k | if (field_native_custom_alloc) |
1223 | 1 | return Error( |
1224 | 1 | "native_custom_alloc can only be used with a table or struct " |
1225 | 1 | "definition"); |
1226 | | |
1227 | 35.2k | field->native_inline = field->attributes.Lookup("native_inline") != nullptr; |
1228 | 35.2k | if (field->native_inline && !IsStruct(field->value.type) && |
1229 | 35.2k | !IsVectorOfStruct(field->value.type) && |
1230 | 35.2k | !IsVectorOfTable(field->value.type)) |
1231 | 6 | return Error( |
1232 | 6 | "'native_inline' can only be defined on structs, vector of structs or " |
1233 | 6 | "vector of tables"); |
1234 | | |
1235 | 35.2k | auto nested = field->attributes.Lookup("nested_flatbuffer"); |
1236 | 35.2k | if (nested) { |
1237 | 1 | if (nested->type.base_type != BASE_TYPE_STRING) |
1238 | 1 | return Error( |
1239 | 1 | "nested_flatbuffer attribute must be a string (the root type)"); |
1240 | 0 | if (!IsVector(type.base_type) || type.element != BASE_TYPE_UCHAR) |
1241 | 0 | return Error( |
1242 | 0 | "nested_flatbuffer attribute may only apply to a vector of ubyte"); |
1243 | | // This will cause an error if the root type of the nested flatbuffer |
1244 | | // wasn't defined elsewhere. |
1245 | 0 | field->nested_flatbuffer = LookupCreateStruct(nested->constant); |
1246 | 0 | } |
1247 | | |
1248 | 35.2k | if (field->attributes.Lookup("flexbuffer")) { |
1249 | 4.28k | field->flexbuffer = true; |
1250 | 4.28k | uses_flexbuffers_ = true; |
1251 | 4.28k | if (type.base_type != BASE_TYPE_VECTOR || type.element != BASE_TYPE_UCHAR) |
1252 | 6 | return Error("flexbuffer attribute may only apply to a vector of ubyte"); |
1253 | 4.28k | } |
1254 | | |
1255 | 35.2k | if (typefield) { |
1256 | 11.5k | if (!IsScalar(typefield->value.type.base_type)) { |
1257 | | // this is a union vector field |
1258 | 1.90k | typefield->presence = field->presence; |
1259 | 1.90k | } |
1260 | | // If this field is a union, and it has a manually assigned id, |
1261 | | // the automatically added type field should have an id as well (of N - 1). |
1262 | 11.5k | auto attr = field->attributes.Lookup("id"); |
1263 | 11.5k | if (attr) { |
1264 | 4.22k | const auto &id_str = attr->constant; |
1265 | 4.22k | voffset_t id = 0; |
1266 | 4.22k | const auto done = !atot(id_str.c_str(), *this, &id).Check(); |
1267 | 4.22k | if (done && id > 0) { |
1268 | 4.22k | auto val = new Value(); |
1269 | 4.22k | val->type = attr->type; |
1270 | 4.22k | val->constant = NumToString(id - 1); |
1271 | 4.22k | typefield->attributes.Add("id", val); |
1272 | 4.22k | } else { |
1273 | 5 | return Error( |
1274 | 5 | "a union type effectively adds two fields with non-negative ids, " |
1275 | 5 | "its id must be that of the second field (the first field is " |
1276 | 5 | "the type field and not explicitly declared in the schema);\n" |
1277 | 5 | "field: " + |
1278 | 5 | field->name + ", id: " + id_str); |
1279 | 5 | } |
1280 | 4.22k | } |
1281 | | // if this field is a union that is deprecated, |
1282 | | // the automatically added type field should be deprecated as well |
1283 | 11.5k | if (field->deprecated) { typefield->deprecated = true; } |
1284 | 11.5k | } |
1285 | | |
1286 | 35.2k | EXPECT(';'); |
1287 | 34.3k | return NoError(); |
1288 | 35.2k | } |
1289 | | |
1290 | 14.8k | CheckedError Parser::ParseString(Value &val, bool use_string_pooling) { |
1291 | 14.8k | auto s = attribute_; |
1292 | 14.8k | EXPECT(kTokenStringConstant); |
1293 | 14.8k | if (use_string_pooling) { |
1294 | 2.61k | val.constant = NumToString(builder_.CreateSharedString(s).o); |
1295 | 12.2k | } else { |
1296 | 12.2k | val.constant = NumToString(builder_.CreateString(s).o); |
1297 | 12.2k | } |
1298 | 14.8k | return NoError(); |
1299 | 14.8k | } |
1300 | | |
1301 | 737k | CheckedError Parser::ParseComma() { |
1302 | 737k | if (!opts.protobuf_ascii_alike) EXPECT(','); |
1303 | 732k | return NoError(); |
1304 | 737k | } |
1305 | | |
1306 | | CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field, |
1307 | | size_t parent_fieldn, |
1308 | | const StructDef *parent_struct_def, |
1309 | 592k | size_t count, bool inside_vector) { |
1310 | 592k | switch (val.type.base_type) { |
1311 | 305 | case BASE_TYPE_UNION: { |
1312 | 305 | FLATBUFFERS_ASSERT(field); |
1313 | 305 | std::string constant; |
1314 | 305 | Vector<uint8_t> *vector_of_union_types = nullptr; |
1315 | | // Find corresponding type field we may have already parsed. |
1316 | 305 | for (auto elem = field_stack_.rbegin() + count; |
1317 | 380 | elem != field_stack_.rbegin() + parent_fieldn + count; ++elem) { |
1318 | 346 | auto &type = elem->second->value.type; |
1319 | 346 | if (type.enum_def == val.type.enum_def) { |
1320 | 346 | if (inside_vector) { |
1321 | 260 | if (IsVector(type) && type.element == BASE_TYPE_UTYPE) { |
1322 | | // Vector of union type field. |
1323 | 185 | uoffset_t offset; |
1324 | 185 | ECHECK(atot(elem->first.constant.c_str(), *this, &offset)); |
1325 | 185 | vector_of_union_types = reinterpret_cast<Vector<uint8_t> *>( |
1326 | 185 | builder_.GetCurrentBufferPointer() + builder_.GetSize() - |
1327 | 185 | offset); |
1328 | 185 | break; |
1329 | 185 | } |
1330 | 260 | } else { |
1331 | 86 | if (type.base_type == BASE_TYPE_UTYPE) { |
1332 | | // Union type field. |
1333 | 86 | constant = elem->first.constant; |
1334 | 86 | break; |
1335 | 86 | } |
1336 | 86 | } |
1337 | 346 | } |
1338 | 346 | } |
1339 | 305 | if (constant.empty() && !inside_vector) { |
1340 | | // We haven't seen the type field yet. Sadly a lot of JSON writers |
1341 | | // output these in alphabetical order, meaning it comes after this |
1342 | | // value. So we scan past the value to find it, then come back here. |
1343 | | // We currently don't do this for vectors of unions because the |
1344 | | // scanning/serialization logic would get very complicated. |
1345 | 35 | auto type_name = field->name + UnionTypeFieldSuffix(); |
1346 | 35 | FLATBUFFERS_ASSERT(parent_struct_def); |
1347 | 35 | auto type_field = parent_struct_def->fields.Lookup(type_name); |
1348 | 35 | FLATBUFFERS_ASSERT(type_field); // Guaranteed by ParseField(). |
1349 | | // Remember where we are in the source file, so we can come back here. |
1350 | 35 | auto backup = *static_cast<ParserState *>(this); |
1351 | 35 | ECHECK(SkipAnyJsonValue()); // The table. |
1352 | 33 | ECHECK(ParseComma()); |
1353 | 31 | auto next_name = attribute_; |
1354 | 31 | if (Is(kTokenStringConstant)) { |
1355 | 2 | NEXT(); |
1356 | 29 | } else { |
1357 | 29 | EXPECT(kTokenIdentifier); |
1358 | 28 | } |
1359 | 29 | if (next_name == type_name) { |
1360 | 17 | EXPECT(':'); |
1361 | 16 | ParseDepthGuard depth_guard(this); |
1362 | 16 | ECHECK(depth_guard.Check()); |
1363 | 16 | Value type_val = type_field->value; |
1364 | 16 | ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr, 0)); |
1365 | 15 | constant = type_val.constant; |
1366 | | // Got the information we needed, now rewind: |
1367 | 15 | *static_cast<ParserState *>(this) = backup; |
1368 | 15 | } |
1369 | 29 | } |
1370 | 297 | if (constant.empty() && !vector_of_union_types) { |
1371 | 14 | return Error("missing type field for this union value: " + field->name); |
1372 | 14 | } |
1373 | 283 | uint8_t enum_idx; |
1374 | 283 | if (vector_of_union_types) { |
1375 | 185 | if (vector_of_union_types->size() <= count) |
1376 | 5 | return Error( |
1377 | 5 | "union types vector smaller than union values vector for: " + |
1378 | 5 | field->name); |
1379 | 180 | enum_idx = vector_of_union_types->Get(static_cast<uoffset_t>(count)); |
1380 | 180 | } else { |
1381 | 98 | ECHECK(atot(constant.c_str(), *this, &enum_idx)); |
1382 | 93 | } |
1383 | 273 | auto enum_val = val.type.enum_def->ReverseLookup(enum_idx, true); |
1384 | 273 | if (!enum_val) return Error("illegal type id for: " + field->name); |
1385 | 257 | if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) { |
1386 | 257 | ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant, |
1387 | 257 | nullptr)); |
1388 | 98 | if (enum_val->union_type.struct_def->fixed) { |
1389 | | // All BASE_TYPE_UNION values are offsets, so turn this into one. |
1390 | 0 | SerializeStruct(*enum_val->union_type.struct_def, val); |
1391 | 0 | builder_.ClearOffsets(); |
1392 | 0 | val.constant = NumToString(builder_.GetSize()); |
1393 | 0 | } |
1394 | 98 | } else if (IsString(enum_val->union_type)) { |
1395 | 0 | ECHECK(ParseString(val, field->shared)); |
1396 | 0 | } else { |
1397 | 0 | FLATBUFFERS_ASSERT(false); |
1398 | 0 | } |
1399 | 98 | break; |
1400 | 257 | } |
1401 | 243k | case BASE_TYPE_STRUCT: |
1402 | 243k | ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr)); |
1403 | 239k | break; |
1404 | 14.8k | case BASE_TYPE_STRING: { |
1405 | 14.8k | ECHECK(ParseString(val, field->shared)); |
1406 | 14.8k | break; |
1407 | 14.8k | } |
1408 | 14.7k | case BASE_TYPE_VECTOR64: |
1409 | 67.8k | case BASE_TYPE_VECTOR: { |
1410 | 67.8k | uoffset_t off; |
1411 | 67.8k | ECHECK(ParseVector(val.type, &off, field, parent_fieldn)); |
1412 | 62.2k | val.constant = NumToString(off); |
1413 | 62.2k | break; |
1414 | 67.8k | } |
1415 | 7.00k | case BASE_TYPE_ARRAY: { |
1416 | 7.00k | ECHECK(ParseArray(val)); |
1417 | 6.79k | break; |
1418 | 7.00k | } |
1419 | 20.9k | case BASE_TYPE_INT: |
1420 | 27.5k | case BASE_TYPE_UINT: |
1421 | 67.5k | case BASE_TYPE_LONG: |
1422 | 96.2k | case BASE_TYPE_ULONG: { |
1423 | 96.2k | if (field && field->attributes.Lookup("hash") && |
1424 | 96.2k | (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) { |
1425 | 2.94k | ECHECK(ParseHash(val, field)); |
1426 | 93.3k | } else { |
1427 | 93.3k | ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false)); |
1428 | 93.2k | } |
1429 | 96.1k | break; |
1430 | 96.2k | } |
1431 | 162k | default: |
1432 | 162k | ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false)); |
1433 | 161k | break; |
1434 | 592k | } |
1435 | 581k | return NoError(); |
1436 | 592k | } |
1437 | | |
1438 | 53.0k | void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) { |
1439 | 53.0k | SerializeStruct(builder_, struct_def, val); |
1440 | 53.0k | } |
1441 | | |
1442 | | void Parser::SerializeStruct(FlatBufferBuilder &builder, |
1443 | 53.0k | const StructDef &struct_def, const Value &val) { |
1444 | 53.0k | FLATBUFFERS_ASSERT(val.constant.length() == struct_def.bytesize); |
1445 | 53.0k | builder.Align(struct_def.minalign); |
1446 | 53.0k | builder.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()), |
1447 | 53.0k | struct_def.bytesize); |
1448 | 53.0k | builder.AddStructOffset(val.offset, builder.GetSize()); |
1449 | 53.0k | } |
1450 | | |
1451 | | template<typename F> |
1452 | | CheckedError Parser::ParseTableDelimiters(size_t &fieldn, |
1453 | 296k | const StructDef *struct_def, F body) { |
1454 | | // We allow tables both as JSON object{ .. } with field names |
1455 | | // or vector[..] with all fields in order |
1456 | 296k | char terminator = '}'; |
1457 | 296k | bool is_nested_vector = struct_def && Is('['); |
1458 | 296k | if (is_nested_vector) { |
1459 | 188k | NEXT(); |
1460 | 188k | terminator = ']'; |
1461 | 188k | } else { |
1462 | 108k | EXPECT('{'); |
1463 | 108k | } |
1464 | 603k | for (;;) { |
1465 | 603k | if ((!opts.strict_json || !fieldn) && Is(terminator)) break; |
1466 | 544k | std::string name; |
1467 | 544k | if (is_nested_vector) { |
1468 | 267k | if (fieldn >= struct_def->fields.vec.size()) { |
1469 | 42 | return Error("too many unnamed fields in nested array"); |
1470 | 42 | } |
1471 | 267k | name = struct_def->fields.vec[fieldn]->name; |
1472 | 277k | } else { |
1473 | 277k | name = attribute_; |
1474 | 277k | if (Is(kTokenStringConstant)) { |
1475 | 37.4k | NEXT(); |
1476 | 239k | } else { |
1477 | 239k | EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); |
1478 | 239k | } |
1479 | 277k | if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':'); |
1480 | 277k | } |
1481 | 544k | ECHECK(body(name, fieldn, struct_def)); |
1482 | 534k | if (Is(terminator)) break; |
1483 | 310k | ECHECK(ParseComma()); |
1484 | 307k | } |
1485 | 282k | NEXT(); |
1486 | 282k | if (is_nested_vector && fieldn != struct_def->fields.vec.size()) { |
1487 | 67 | return Error("wrong number of unnamed fields in table vector"); |
1488 | 67 | } |
1489 | 282k | return NoError(); |
1490 | 282k | } idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseTableDelimiters<flatbuffers::Parser::ParseTable(flatbuffers::StructDef const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, unsigned int*)::$_0>(unsigned long&, flatbuffers::StructDef const*, flatbuffers::Parser::ParseTable(flatbuffers::StructDef const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, unsigned int*)::$_0) Line | Count | Source | 1453 | 253k | const StructDef *struct_def, F body) { | 1454 | | // We allow tables both as JSON object{ .. } with field names | 1455 | | // or vector[..] with all fields in order | 1456 | 253k | char terminator = '}'; | 1457 | 253k | bool is_nested_vector = struct_def && Is('['); | 1458 | 253k | if (is_nested_vector) { | 1459 | 188k | NEXT(); | 1460 | 188k | terminator = ']'; | 1461 | 188k | } else { | 1462 | 64.9k | EXPECT('{'); | 1463 | 64.6k | } | 1464 | 336k | for (;;) { | 1465 | 336k | if ((!opts.strict_json || !fieldn) && Is(terminator)) break; | 1466 | 280k | std::string name; | 1467 | 280k | if (is_nested_vector) { | 1468 | 267k | if (fieldn >= struct_def->fields.vec.size()) { | 1469 | 42 | return Error("too many unnamed fields in nested array"); | 1470 | 42 | } | 1471 | 267k | name = struct_def->fields.vec[fieldn]->name; | 1472 | 267k | } else { | 1473 | 12.7k | name = attribute_; | 1474 | 12.7k | if (Is(kTokenStringConstant)) { | 1475 | 2.42k | NEXT(); | 1476 | 10.3k | } else { | 1477 | 10.3k | EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); | 1478 | 10.1k | } | 1479 | 12.5k | if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':'); | 1480 | 12.5k | } | 1481 | 279k | ECHECK(body(name, fieldn, struct_def)); | 1482 | 270k | if (Is(terminator)) break; | 1483 | 86.7k | ECHECK(ParseComma()); | 1484 | 83.6k | } | 1485 | 240k | NEXT(); | 1486 | 240k | if (is_nested_vector && fieldn != struct_def->fields.vec.size()) { | 1487 | 67 | return Error("wrong number of unnamed fields in table vector"); | 1488 | 67 | } | 1489 | 240k | return NoError(); | 1490 | 240k | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseTableDelimiters<flatbuffers::Parser::SkipAnyJsonValue()::$_0>(unsigned long&, flatbuffers::StructDef const*, flatbuffers::Parser::SkipAnyJsonValue()::$_0) Line | Count | Source | 1453 | 883 | const StructDef *struct_def, F body) { | 1454 | | // We allow tables both as JSON object{ .. } with field names | 1455 | | // or vector[..] with all fields in order | 1456 | 883 | char terminator = '}'; | 1457 | 883 | bool is_nested_vector = struct_def && Is('['); | 1458 | 883 | if (is_nested_vector) { | 1459 | 0 | NEXT(); | 1460 | 0 | terminator = ']'; | 1461 | 883 | } else { | 1462 | 883 | EXPECT('{'); | 1463 | 882 | } | 1464 | 1.73k | for (;;) { | 1465 | 1.73k | if ((!opts.strict_json || !fieldn) && Is(terminator)) break; | 1466 | 1.22k | std::string name; | 1467 | 1.22k | if (is_nested_vector) { | 1468 | 0 | if (fieldn >= struct_def->fields.vec.size()) { | 1469 | 0 | return Error("too many unnamed fields in nested array"); | 1470 | 0 | } | 1471 | 0 | name = struct_def->fields.vec[fieldn]->name; | 1472 | 1.22k | } else { | 1473 | 1.22k | name = attribute_; | 1474 | 1.22k | if (Is(kTokenStringConstant)) { | 1475 | 436 | NEXT(); | 1476 | 786 | } else { | 1477 | 786 | EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); | 1478 | 757 | } | 1479 | 1.19k | if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':'); | 1480 | 1.17k | } | 1481 | 1.17k | ECHECK(body(name, fieldn, struct_def)); | 1482 | 1.07k | if (Is(terminator)) break; | 1483 | 854 | ECHECK(ParseComma()); | 1484 | 850 | } | 1485 | 735 | NEXT(); | 1486 | 734 | if (is_nested_vector && fieldn != struct_def->fields.vec.size()) { | 1487 | 0 | return Error("wrong number of unnamed fields in table vector"); | 1488 | 0 | } | 1489 | 734 | return NoError(); | 1490 | 734 | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseTableDelimiters<flatbuffers::Parser::ParseFlexBufferValue(flexbuffers::Builder*)::$_0>(unsigned long&, flatbuffers::StructDef const*, flatbuffers::Parser::ParseFlexBufferValue(flexbuffers::Builder*)::$_0) Line | Count | Source | 1453 | 43.0k | const StructDef *struct_def, F body) { | 1454 | | // We allow tables both as JSON object{ .. } with field names | 1455 | | // or vector[..] with all fields in order | 1456 | 43.0k | char terminator = '}'; | 1457 | 43.0k | bool is_nested_vector = struct_def && Is('['); | 1458 | 43.0k | if (is_nested_vector) { | 1459 | 0 | NEXT(); | 1460 | 0 | terminator = ']'; | 1461 | 43.0k | } else { | 1462 | 43.0k | EXPECT('{'); | 1463 | 43.0k | } | 1464 | 265k | for (;;) { | 1465 | 265k | if ((!opts.strict_json || !fieldn) && Is(terminator)) break; | 1466 | 263k | std::string name; | 1467 | 263k | if (is_nested_vector) { | 1468 | 0 | if (fieldn >= struct_def->fields.vec.size()) { | 1469 | 0 | return Error("too many unnamed fields in nested array"); | 1470 | 0 | } | 1471 | 0 | name = struct_def->fields.vec[fieldn]->name; | 1472 | 263k | } else { | 1473 | 263k | name = attribute_; | 1474 | 263k | if (Is(kTokenStringConstant)) { | 1475 | 34.6k | NEXT(); | 1476 | 228k | } else { | 1477 | 228k | EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); | 1478 | 228k | } | 1479 | 263k | if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':'); | 1480 | 263k | } | 1481 | 263k | ECHECK(body(name, fieldn, struct_def)); | 1482 | 262k | if (Is(terminator)) break; | 1483 | 222k | ECHECK(ParseComma()); | 1484 | 222k | } | 1485 | 41.9k | NEXT(); | 1486 | 41.9k | if (is_nested_vector && fieldn != struct_def->fields.vec.size()) { | 1487 | 0 | return Error("wrong number of unnamed fields in table vector"); | 1488 | 0 | } | 1489 | 41.9k | return NoError(); | 1490 | 41.9k | } |
|
1491 | | |
1492 | | CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, |
1493 | 253k | uoffset_t *ovalue) { |
1494 | 253k | ParseDepthGuard depth_guard(this); |
1495 | 253k | ECHECK(depth_guard.Check()); |
1496 | | |
1497 | 253k | size_t fieldn_outer = 0; |
1498 | 253k | auto err = ParseTableDelimiters( |
1499 | 253k | fieldn_outer, &struct_def, |
1500 | 253k | [&](const std::string &name, size_t &fieldn, |
1501 | 279k | const StructDef *struct_def_inner) -> CheckedError { |
1502 | 279k | if (name == "$schema") { |
1503 | 241 | ECHECK(Expect(kTokenStringConstant)); |
1504 | 237 | return NoError(); |
1505 | 241 | } |
1506 | 279k | auto field = struct_def_inner->fields.Lookup(name); |
1507 | 279k | if (!field) { |
1508 | 2.46k | if (!opts.skip_unexpected_fields_in_json) { |
1509 | 25 | return Error("unknown field: " + name); |
1510 | 2.44k | } else { |
1511 | 2.44k | ECHECK(SkipAnyJsonValue()); |
1512 | 2.24k | } |
1513 | 277k | } else { |
1514 | 277k | if (IsIdent("null") && !IsScalar(field->value.type.base_type)) { |
1515 | 67 | ECHECK(Next()); // Ignore this field. |
1516 | 277k | } else { |
1517 | 277k | Value val = field->value; |
1518 | 277k | if (field->flexbuffer) { |
1519 | 6.83k | flexbuffers::Builder builder(1024, |
1520 | 6.83k | flexbuffers::BUILDER_FLAG_SHARE_ALL); |
1521 | 6.83k | ECHECK(ParseFlexBufferValue(&builder)); |
1522 | 4.05k | builder.Finish(); |
1523 | | // Force alignment for nested flexbuffer |
1524 | 4.05k | builder_.ForceVectorAlignment(builder.GetSize(), sizeof(uint8_t), |
1525 | 4.05k | sizeof(largest_scalar_t)); |
1526 | 4.05k | auto off = builder_.CreateVector(builder.GetBuffer()); |
1527 | 4.05k | val.constant = NumToString(off.o); |
1528 | 270k | } else if (field->nested_flatbuffer) { |
1529 | 0 | ECHECK( |
1530 | 0 | ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner)); |
1531 | 270k | } else { |
1532 | 270k | ECHECK(ParseAnyValue(val, field, fieldn, struct_def_inner, 0)); |
1533 | 264k | } |
1534 | | // Hardcoded insertion-sort with error-check. |
1535 | | // If fields are specified in order, then this loop exits |
1536 | | // immediately. |
1537 | 268k | auto elem = field_stack_.rbegin(); |
1538 | 268k | for (; elem != field_stack_.rbegin() + fieldn; ++elem) { |
1539 | 79.7k | auto existing_field = elem->second; |
1540 | 79.7k | if (existing_field == field) |
1541 | 71 | return Error("field set more than once: " + field->name); |
1542 | 79.6k | if (existing_field->value.offset < field->value.offset) break; |
1543 | 79.6k | } |
1544 | | // Note: elem points to before the insertion point, thus .base() |
1545 | | // points to the correct spot. |
1546 | 268k | field_stack_.insert(elem.base(), std::make_pair(val, field)); |
1547 | 268k | fieldn++; |
1548 | 268k | } |
1549 | 277k | } |
1550 | 270k | return NoError(); |
1551 | 279k | }); |
1552 | 253k | ECHECK(err); |
1553 | | |
1554 | | // Check if all required fields are parsed. |
1555 | 240k | for (auto field_it = struct_def.fields.vec.begin(); |
1556 | 612k | field_it != struct_def.fields.vec.end(); ++field_it) { |
1557 | 372k | auto required_field = *field_it; |
1558 | 372k | if (!required_field->IsRequired()) { continue; } |
1559 | 6.12k | bool found = false; |
1560 | 6.12k | for (auto pf_it = field_stack_.end() - fieldn_outer; |
1561 | 11.6k | pf_it != field_stack_.end(); ++pf_it) { |
1562 | 11.6k | auto parsed_field = pf_it->second; |
1563 | 11.6k | if (parsed_field == required_field) { |
1564 | 6.12k | found = true; |
1565 | 6.12k | break; |
1566 | 6.12k | } |
1567 | 11.6k | } |
1568 | 6.12k | if (!found) { |
1569 | 3 | return Error("required field is missing: " + required_field->name + |
1570 | 3 | " in " + struct_def.name); |
1571 | 3 | } |
1572 | 6.12k | } |
1573 | | |
1574 | 240k | if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size()) |
1575 | 1 | return Error("struct: wrong number of initializers: " + struct_def.name); |
1576 | | |
1577 | 240k | auto start = struct_def.fixed ? builder_.StartStruct(struct_def.minalign) |
1578 | 240k | : builder_.StartTable(); |
1579 | | |
1580 | 972k | for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; size; |
1581 | 732k | size /= 2) { |
1582 | | // Go through elements in reverse, since we're building the data backwards. |
1583 | | // TODO(derekbailey): this doesn't work when there are Offset64 fields, as |
1584 | | // those have to be built first. So this needs to be changed to iterate over |
1585 | | // Offset64 then Offset32 fields. |
1586 | 732k | for (auto it = field_stack_.rbegin(); |
1587 | 1.47M | it != field_stack_.rbegin() + fieldn_outer; ++it) { |
1588 | 743k | auto &field_value = it->first; |
1589 | 743k | auto field = it->second; |
1590 | 743k | if (!struct_def.sortbysize || |
1591 | 743k | size == SizeOf(field_value.type.base_type)) { |
1592 | 263k | switch (field_value.type.base_type) { |
1593 | | // clang-format off |
1594 | 0 | #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ |
1595 | 182k | case BASE_TYPE_ ## ENUM: \ |
1596 | 182k | builder_.Pad(field->padding); \ |
1597 | 182k | if (struct_def.fixed) { \ |
1598 | 64.5k | CTYPE val; \ |
1599 | 64.5k | ECHECK(atot(field_value.constant.c_str(), *this, &val)); \ |
1600 | 64.5k | builder_.PushElement(val); \ |
1601 | 117k | } else { \ |
1602 | 117k | if (field->IsScalarOptional()) { \ |
1603 | 37.4k | if (field_value.constant != "null") { \ |
1604 | 33.4k | CTYPE val; \ |
1605 | 33.4k | ECHECK(atot(field_value.constant.c_str(), *this, &val)); \ |
1606 | 33.4k | builder_.AddElement(field_value.offset, val); \ |
1607 | 33.4k | } \ |
1608 | 80.4k | } else { \ |
1609 | 80.4k | CTYPE val, valdef; \ |
1610 | 80.4k | ECHECK(atot(field_value.constant.c_str(), *this, &val)); \ |
1611 | 80.4k | ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \ |
1612 | 80.4k | builder_.AddElement(field_value.offset, val, valdef); \ |
1613 | 80.4k | } \ |
1614 | 117k | } \ |
1615 | 182k | break; |
1616 | 182k | FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) |
1617 | 13.0k | #undef FLATBUFFERS_TD |
1618 | 13.0k | #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ |
1619 | 74.1k | case BASE_TYPE_ ## ENUM: \ |
1620 | 74.1k | builder_.Pad(field->padding); \ |
1621 | 74.1k | if (IsStruct(field->value.type)) { \ |
1622 | 0 | SerializeStruct(*field->value.type.struct_def, field_value); \ |
1623 | 74.1k | } else { \ |
1624 | | /* Special case for fields that use 64-bit addressing */ \ |
1625 | 74.1k | if(field->offset64) { \ |
1626 | 23.6k | Offset64<void> offset; \ |
1627 | 23.6k | ECHECK(atot(field_value.constant.c_str(), *this, &offset)); \ |
1628 | 23.6k | builder_.AddOffset(field_value.offset, offset); \ |
1629 | 50.5k | } else { \ |
1630 | 50.5k | CTYPE val; \ |
1631 | 50.5k | ECHECK(atot(field_value.constant.c_str(), *this, &val)); \ |
1632 | 50.5k | builder_.AddOffset(field_value.offset, val); \ |
1633 | 50.5k | } \ |
1634 | 74.1k | } \ |
1635 | 74.1k | break; |
1636 | 74.1k | FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD) |
1637 | 15 | #undef FLATBUFFERS_TD |
1638 | 6.63k | case BASE_TYPE_ARRAY: |
1639 | 6.63k | builder_.Pad(field->padding); |
1640 | 6.63k | builder_.PushBytes( |
1641 | 6.63k | reinterpret_cast<const uint8_t*>(field_value.constant.c_str()), |
1642 | 6.63k | InlineSize(field_value.type)); |
1643 | 6.63k | break; |
1644 | | // clang-format on |
1645 | 263k | } |
1646 | 263k | } |
1647 | 743k | } |
1648 | 732k | } |
1649 | 503k | for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back(); |
1650 | | |
1651 | 239k | if (struct_def.fixed) { |
1652 | 65.1k | builder_.ClearOffsets(); |
1653 | 65.1k | builder_.EndStruct(); |
1654 | 65.1k | FLATBUFFERS_ASSERT(value); |
1655 | | // Temporarily store this struct in the value string, since it is to |
1656 | | // be serialized in-place elsewhere. |
1657 | 65.1k | value->assign( |
1658 | 65.1k | reinterpret_cast<const char *>(builder_.GetCurrentBufferPointer()), |
1659 | 65.1k | struct_def.bytesize); |
1660 | 65.1k | builder_.PopBytes(struct_def.bytesize); |
1661 | 65.1k | FLATBUFFERS_ASSERT(!ovalue); |
1662 | 174k | } else { |
1663 | 174k | auto val = builder_.EndTable(start); |
1664 | 174k | if (ovalue) *ovalue = val; |
1665 | 174k | if (value) *value = NumToString(val); |
1666 | 174k | } |
1667 | 239k | return NoError(); |
1668 | 239k | } |
1669 | | |
1670 | | template<typename F> |
1671 | 83.3k | CheckedError Parser::ParseVectorDelimiters(size_t &count, F body) { |
1672 | 83.3k | EXPECT('['); |
1673 | 508k | for (;;) { |
1674 | 508k | if ((!opts.strict_json || !count) && Is(']')) break; |
1675 | 476k | ECHECK(body(count)); |
1676 | 471k | count++; |
1677 | 471k | if (Is(']')) break; |
1678 | 427k | ECHECK(ParseComma()); |
1679 | 425k | } |
1680 | 76.5k | NEXT(); |
1681 | 76.5k | return NoError(); |
1682 | 76.5k | } idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseVectorDelimiters<flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_0>(unsigned long&, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_0) Line | Count | Source | 1671 | 67.8k | CheckedError Parser::ParseVectorDelimiters(size_t &count, F body) { | 1672 | 67.8k | EXPECT('['); | 1673 | 350k | for (;;) { | 1674 | 350k | if ((!opts.strict_json || !count) && Is(']')) break; | 1675 | 321k | ECHECK(body(count)); | 1676 | 317k | count++; | 1677 | 317k | if (Is(']')) break; | 1678 | 284k | ECHECK(ParseComma()); | 1679 | 282k | } | 1680 | 62.3k | NEXT(); | 1681 | 62.2k | return NoError(); | 1682 | 62.3k | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseVectorDelimiters<flatbuffers::Parser::ParseArray(flatbuffers::Value&)::$_0>(unsigned long&, flatbuffers::Parser::ParseArray(flatbuffers::Value&)::$_0) Line | Count | Source | 1671 | 7.00k | CheckedError Parser::ParseVectorDelimiters(size_t &count, F body) { | 1672 | 7.00k | EXPECT('['); | 1673 | 17.0k | for (;;) { | 1674 | 17.0k | if ((!opts.strict_json || !count) && Is(']')) break; | 1675 | 16.7k | ECHECK(body(count)); | 1676 | 16.6k | count++; | 1677 | 16.6k | if (Is(']')) break; | 1678 | 10.0k | ECHECK(ParseComma()); | 1679 | 10.0k | } | 1680 | 6.84k | NEXT(); | 1681 | 6.84k | return NoError(); | 1682 | 6.84k | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseVectorDelimiters<flatbuffers::Parser::SkipAnyJsonValue()::$_1>(unsigned long&, flatbuffers::Parser::SkipAnyJsonValue()::$_1) Line | Count | Source | 1671 | 1.45k | CheckedError Parser::ParseVectorDelimiters(size_t &count, F body) { | 1672 | 1.45k | EXPECT('['); | 1673 | 5.19k | for (;;) { | 1674 | 5.19k | if ((!opts.strict_json || !count) && Is(']')) break; | 1675 | 4.90k | ECHECK(body(count)); | 1676 | 4.68k | count++; | 1677 | 4.68k | if (Is(']')) break; | 1678 | 3.79k | ECHECK(ParseComma()); | 1679 | 3.74k | } | 1680 | 1.18k | NEXT(); | 1681 | 1.18k | return NoError(); | 1682 | 1.18k | } |
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseVectorDelimiters<flatbuffers::Parser::ParseFlexBufferValue(flexbuffers::Builder*)::$_1>(unsigned long&, flatbuffers::Parser::ParseFlexBufferValue(flexbuffers::Builder*)::$_1) Line | Count | Source | 1671 | 7.08k | CheckedError Parser::ParseVectorDelimiters(size_t &count, F body) { | 1672 | 7.08k | EXPECT('['); | 1673 | 135k | for (;;) { | 1674 | 135k | if ((!opts.strict_json || !count) && Is(']')) break; | 1675 | 133k | ECHECK(body(count)); | 1676 | 132k | count++; | 1677 | 132k | if (Is(']')) break; | 1678 | 129k | ECHECK(ParseComma()); | 1679 | 128k | } | 1680 | 6.19k | NEXT(); | 1681 | 6.18k | return NoError(); | 1682 | 6.19k | } |
|
1683 | | |
1684 | | CheckedError Parser::ParseAlignAttribute(const std::string &align_constant, |
1685 | 11.2k | size_t min_align, size_t *align) { |
1686 | | // Use uint8_t to avoid problems with size_t==`unsigned long` on LP64. |
1687 | 11.2k | uint8_t align_value; |
1688 | 11.2k | if (StringToNumber(align_constant.c_str(), &align_value) && |
1689 | 11.2k | VerifyAlignmentRequirements(static_cast<size_t>(align_value), |
1690 | 11.1k | min_align)) { |
1691 | 11.1k | *align = align_value; |
1692 | 11.1k | return NoError(); |
1693 | 11.1k | } |
1694 | 101 | return Error("unexpected force_align value '" + align_constant + |
1695 | 101 | "', alignment must be a power of two integer ranging from the " |
1696 | 101 | "type\'s natural alignment " + |
1697 | 101 | NumToString(min_align) + " to " + |
1698 | 101 | NumToString(FLATBUFFERS_MAX_ALIGNMENT)); |
1699 | 11.2k | } |
1700 | | |
1701 | | CheckedError Parser::ParseVector(const Type &vector_type, uoffset_t *ovalue, |
1702 | 67.8k | FieldDef *field, size_t fieldn) { |
1703 | 67.8k | Type type = vector_type.VectorType(); |
1704 | 67.8k | size_t count = 0; |
1705 | 321k | auto err = ParseVectorDelimiters(count, [&](size_t &) -> CheckedError { |
1706 | 321k | Value val; |
1707 | 321k | val.type = type; |
1708 | 321k | ECHECK(ParseAnyValue(val, field, fieldn, nullptr, count, true)); |
1709 | 317k | field_stack_.push_back(std::make_pair(val, nullptr)); |
1710 | 317k | return NoError(); |
1711 | 321k | }); |
1712 | 67.8k | ECHECK(err); |
1713 | | |
1714 | 62.2k | const size_t alignment = InlineAlignment(type); |
1715 | 62.2k | const size_t len = count * InlineSize(type) / InlineAlignment(type); |
1716 | 62.2k | const size_t elemsize = InlineAlignment(type); |
1717 | 62.2k | const auto force_align = field->attributes.Lookup("force_align"); |
1718 | 62.2k | if (force_align) { |
1719 | 10.8k | size_t align; |
1720 | 10.8k | ECHECK(ParseAlignAttribute(force_align->constant, 1, &align)); |
1721 | 10.8k | if (align > 1) { builder_.ForceVectorAlignment(len, elemsize, align); } |
1722 | 10.8k | } |
1723 | | |
1724 | | // TODO Fix using element alignment as size (`elemsize`)! |
1725 | 62.2k | if (vector_type.base_type == BASE_TYPE_VECTOR64) { |
1726 | | // TODO(derekbailey): this requires a 64-bit builder. |
1727 | | // builder_.StartVector<Offset64, uoffset64_t>(len, elemsize, alignment); |
1728 | 14.7k | builder_.StartVector(len, elemsize, alignment); |
1729 | 47.5k | } else { |
1730 | 47.5k | builder_.StartVector(len, elemsize, alignment); |
1731 | 47.5k | } |
1732 | 281k | for (size_t i = 0; i < count; i++) { |
1733 | | // start at the back, since we're building the data backwards. |
1734 | 219k | auto &val = field_stack_.back().first; |
1735 | 219k | switch (val.type.base_type) { |
1736 | | // clang-format off |
1737 | 0 | #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE,...) \ |
1738 | 219k | case BASE_TYPE_ ## ENUM: \ |
1739 | 219k | if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \ |
1740 | 219k | else { \ |
1741 | 166k | CTYPE elem; \ |
1742 | 166k | ECHECK(atot(val.constant.c_str(), *this, &elem)); \ |
1743 | 166k | builder_.PushElement(elem); \ |
1744 | 166k | } \ |
1745 | 219k | break; |
1746 | 219k | FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) |
1747 | 219k | #undef FLATBUFFERS_TD |
1748 | | // clang-format on |
1749 | 219k | } |
1750 | 219k | field_stack_.pop_back(); |
1751 | 219k | } |
1752 | | |
1753 | 62.2k | builder_.ClearOffsets(); |
1754 | 62.2k | if (vector_type.base_type == BASE_TYPE_VECTOR64) { |
1755 | 14.7k | *ovalue = builder_.EndVector<uoffset64_t>(count); |
1756 | 47.4k | } else { |
1757 | 47.4k | *ovalue = builder_.EndVector(count); |
1758 | 47.4k | } |
1759 | | |
1760 | 62.2k | if (type.base_type == BASE_TYPE_STRUCT && type.struct_def->has_key) { |
1761 | | // We should sort this vector. Find the key first. |
1762 | 6.13k | const FieldDef *key = nullptr; |
1763 | 6.13k | for (auto it = type.struct_def->fields.vec.begin(); |
1764 | 11.7k | it != type.struct_def->fields.vec.end(); ++it) { |
1765 | 11.7k | if ((*it)->key) { |
1766 | 6.13k | key = (*it); |
1767 | 6.13k | break; |
1768 | 6.13k | } |
1769 | 11.7k | } |
1770 | 6.13k | FLATBUFFERS_ASSERT(key); |
1771 | | // Now sort it. |
1772 | | // We can't use std::sort because for structs the size is not known at |
1773 | | // compile time, and for tables our iterators dereference offsets, so can't |
1774 | | // be used to swap elements. |
1775 | | // And we can't use C qsort either, since that would force use to use |
1776 | | // globals, making parsing thread-unsafe. |
1777 | | // So for now, we use SimpleQsort above. |
1778 | | // TODO: replace with something better, preferably not recursive. |
1779 | | |
1780 | 6.13k | if (type.struct_def->fixed) { |
1781 | 72 | const voffset_t offset = key->value.offset; |
1782 | 72 | const size_t struct_size = type.struct_def->bytesize; |
1783 | 72 | auto v = |
1784 | 72 | reinterpret_cast<VectorOfAny *>(builder_.GetCurrentBufferPointer()); |
1785 | 72 | SimpleQsort<uint8_t>( |
1786 | 72 | v->Data(), v->Data() + v->size() * type.struct_def->bytesize, |
1787 | 72 | type.struct_def->bytesize, |
1788 | 85.9k | [offset, key](const uint8_t *a, const uint8_t *b) -> bool { |
1789 | 85.9k | return CompareSerializedScalars(a + offset, b + offset, *key); |
1790 | 85.9k | }, |
1791 | 3.16k | [struct_size](uint8_t *a, uint8_t *b) { |
1792 | | // FIXME: faster? |
1793 | 14.8k | for (size_t i = 0; i < struct_size; i++) { std::swap(a[i], b[i]); } |
1794 | 3.16k | }); |
1795 | 6.05k | } else { |
1796 | 6.05k | auto v = reinterpret_cast<Vector<Offset<Table>> *>( |
1797 | 6.05k | builder_.GetCurrentBufferPointer()); |
1798 | | // Here also can't use std::sort. We do have an iterator type for it, |
1799 | | // but it is non-standard as it will dereference the offsets, and thus |
1800 | | // can't be used to swap elements. |
1801 | 6.05k | if (key->value.type.base_type == BASE_TYPE_STRING) { |
1802 | 5.14k | SimpleQsort<Offset<Table>>( |
1803 | 5.14k | v->data(), v->data() + v->size(), 1, |
1804 | 109k | [key](const Offset<Table> *_a, const Offset<Table> *_b) -> bool { |
1805 | 109k | return CompareTablesByStringKey(_a, _b, *key); |
1806 | 109k | }, |
1807 | 5.14k | SwapSerializedTables); |
1808 | 5.14k | } else { |
1809 | 914 | SimpleQsort<Offset<Table>>( |
1810 | 914 | v->data(), v->data() + v->size(), 1, |
1811 | 88.6M | [key](const Offset<Table> *_a, const Offset<Table> *_b) -> bool { |
1812 | 88.6M | return CompareTablesByScalarKey(_a, _b, *key); |
1813 | 88.6M | }, |
1814 | 914 | SwapSerializedTables); |
1815 | 914 | } |
1816 | 6.05k | } |
1817 | 6.13k | } |
1818 | 62.2k | return NoError(); |
1819 | 62.2k | } |
1820 | | |
1821 | 7.00k | CheckedError Parser::ParseArray(Value &array) { |
1822 | 7.00k | std::vector<Value> stack; |
1823 | 7.00k | FlatBufferBuilder builder; |
1824 | 7.00k | const auto &type = array.type.VectorType(); |
1825 | 7.00k | auto length = array.type.fixed_length; |
1826 | 7.00k | size_t count = 0; |
1827 | 16.7k | auto err = ParseVectorDelimiters(count, [&](size_t &) -> CheckedError { |
1828 | 16.7k | stack.emplace_back(Value()); |
1829 | 16.7k | auto &val = stack.back(); |
1830 | 16.7k | val.type = type; |
1831 | 16.7k | if (IsStruct(type)) { |
1832 | 79 | ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr)); |
1833 | 16.6k | } else { |
1834 | 16.6k | ECHECK(ParseSingleValue(nullptr, val, false)); |
1835 | 16.6k | } |
1836 | 16.6k | return NoError(); |
1837 | 16.7k | }); |
1838 | 7.00k | ECHECK(err); |
1839 | 6.84k | if (length != count) return Error("Fixed-length array size is incorrect."); |
1840 | | |
1841 | 14.6k | for (auto it = stack.rbegin(); it != stack.rend(); ++it) { |
1842 | 7.82k | auto &val = *it; |
1843 | | // clang-format off |
1844 | 7.82k | switch (val.type.base_type) { |
1845 | 0 | #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ |
1846 | 7.78k | case BASE_TYPE_ ## ENUM: \ |
1847 | 7.82k | if (IsStruct(val.type)) { \ |
1848 | 0 | SerializeStruct(builder, *val.type.struct_def, val); \ |
1849 | 7.82k | } else { \ |
1850 | 7.82k | CTYPE elem; \ |
1851 | 7.82k | ECHECK(atot(val.constant.c_str(), *this, &elem)); \ |
1852 | 7.78k | builder.PushElement(elem); \ |
1853 | 7.78k | } \ |
1854 | 7.78k | break; |
1855 | 7.82k | FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) |
1856 | 0 | #undef FLATBUFFERS_TD |
1857 | 0 | default: FLATBUFFERS_ASSERT(0); |
1858 | 7.82k | } |
1859 | | // clang-format on |
1860 | 7.82k | } |
1861 | | |
1862 | 6.79k | array.constant.assign( |
1863 | 6.79k | reinterpret_cast<const char *>(builder.GetCurrentBufferPointer()), |
1864 | 6.79k | InlineSize(array.type)); |
1865 | 6.79k | return NoError(); |
1866 | 6.83k | } |
1867 | | |
1868 | | CheckedError Parser::ParseNestedFlatbuffer(Value &val, FieldDef *field, |
1869 | | size_t fieldn, |
1870 | 0 | const StructDef *parent_struct_def) { |
1871 | 0 | if (token_ == '[') { // backwards compat for 'legacy' ubyte buffers |
1872 | 0 | if (opts.json_nested_legacy_flatbuffers) { |
1873 | 0 | ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def, 0)); |
1874 | 0 | } else { |
1875 | 0 | return Error( |
1876 | 0 | "cannot parse nested_flatbuffer as bytes unless" |
1877 | 0 | " --json-nested-bytes is set"); |
1878 | 0 | } |
1879 | 0 | } else { |
1880 | 0 | auto cursor_at_value_begin = cursor_; |
1881 | 0 | ECHECK(SkipAnyJsonValue()); |
1882 | 0 | std::string substring(cursor_at_value_begin - 1, cursor_ - 1); |
1883 | | |
1884 | | // Create and initialize new parser |
1885 | 0 | Parser nested_parser; |
1886 | 0 | FLATBUFFERS_ASSERT(field->nested_flatbuffer); |
1887 | 0 | nested_parser.root_struct_def_ = field->nested_flatbuffer; |
1888 | 0 | nested_parser.enums_ = enums_; |
1889 | 0 | nested_parser.opts = opts; |
1890 | 0 | nested_parser.uses_flexbuffers_ = uses_flexbuffers_; |
1891 | 0 | nested_parser.parse_depth_counter_ = parse_depth_counter_; |
1892 | | // Parse JSON substring into new flatbuffer builder using nested_parser |
1893 | 0 | bool ok = nested_parser.Parse(substring.c_str(), nullptr, nullptr); |
1894 | | |
1895 | | // Clean nested_parser to avoid deleting the elements in |
1896 | | // the SymbolTables on destruction |
1897 | 0 | nested_parser.enums_.dict.clear(); |
1898 | 0 | nested_parser.enums_.vec.clear(); |
1899 | |
|
1900 | 0 | if (!ok) { ECHECK(Error(nested_parser.error_)); } |
1901 | | // Force alignment for nested flatbuffer |
1902 | 0 | builder_.ForceVectorAlignment( |
1903 | 0 | nested_parser.builder_.GetSize(), sizeof(uint8_t), |
1904 | 0 | nested_parser.builder_.GetBufferMinAlignment()); |
1905 | |
|
1906 | 0 | auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(), |
1907 | 0 | nested_parser.builder_.GetSize()); |
1908 | 0 | val.constant = NumToString(off.o); |
1909 | 0 | } |
1910 | 0 | return NoError(); |
1911 | 0 | } |
1912 | | |
1913 | 624k | CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) { |
1914 | 624k | if (Is('(')) { |
1915 | 14.3k | NEXT(); |
1916 | 21.4k | for (;;) { |
1917 | 21.4k | auto name = attribute_; |
1918 | 21.4k | if (false == (Is(kTokenIdentifier) || Is(kTokenStringConstant))) |
1919 | 60 | return Error("attribute name must be either identifier or string: " + |
1920 | 60 | name); |
1921 | 21.4k | if (known_attributes_.find(name) == known_attributes_.end()) |
1922 | 150 | return Error("user define attributes must be declared before use: " + |
1923 | 150 | name); |
1924 | 21.2k | NEXT(); |
1925 | 21.2k | auto e = new Value(); |
1926 | 21.2k | if (attributes->Add(name, e)) Warning("attribute already found: " + name); |
1927 | 21.2k | if (Is(':')) { |
1928 | 7.96k | NEXT(); |
1929 | 7.95k | ECHECK(ParseSingleValue(&name, *e, true)); |
1930 | 7.87k | } |
1931 | 21.1k | if (Is(')')) { |
1932 | 13.8k | NEXT(); |
1933 | 13.8k | break; |
1934 | 13.8k | } |
1935 | 7.32k | EXPECT(','); |
1936 | 7.11k | } |
1937 | 14.3k | } |
1938 | 623k | return NoError(); |
1939 | 624k | } |
1940 | | |
1941 | | CheckedError Parser::ParseEnumFromString(const Type &type, |
1942 | 1.61k | std::string *result) { |
1943 | 1.61k | const auto base_type = |
1944 | 1.61k | type.enum_def ? type.enum_def->underlying_type.base_type : type.base_type; |
1945 | 1.61k | if (!IsInteger(base_type)) return Error("not a valid value for this field"); |
1946 | 1.61k | uint64_t u64 = 0; |
1947 | 5.45k | for (size_t pos = 0; pos != std::string::npos;) { |
1948 | 4.05k | const auto delim = attribute_.find_first_of(' ', pos); |
1949 | 4.05k | const auto last = (std::string::npos == delim); |
1950 | 4.05k | auto word = attribute_.substr(pos, !last ? delim - pos : std::string::npos); |
1951 | 4.05k | pos = !last ? delim + 1 : std::string::npos; |
1952 | 4.05k | const EnumVal *ev = nullptr; |
1953 | 4.05k | if (type.enum_def) { |
1954 | 3.87k | ev = type.enum_def->Lookup(word); |
1955 | 3.87k | } else { |
1956 | 176 | auto dot = word.find_first_of('.'); |
1957 | 176 | if (std::string::npos == dot) |
1958 | 47 | return Error("enum values need to be qualified by an enum type"); |
1959 | 129 | auto enum_def_str = word.substr(0, dot); |
1960 | 129 | const auto enum_def = LookupEnum(enum_def_str); |
1961 | 129 | if (!enum_def) return Error("unknown enum: " + enum_def_str); |
1962 | 73 | auto enum_val_str = word.substr(dot + 1); |
1963 | 73 | ev = enum_def->Lookup(enum_val_str); |
1964 | 73 | } |
1965 | 3.95k | if (!ev) return Error("unknown enum value: " + word); |
1966 | 3.83k | u64 |= ev->GetAsUInt64(); |
1967 | 3.83k | } |
1968 | 1.39k | *result = IsUnsigned(base_type) ? NumToString(u64) |
1969 | 1.39k | : NumToString(static_cast<int64_t>(u64)); |
1970 | 1.39k | return NoError(); |
1971 | 1.61k | } |
1972 | | |
1973 | 2.94k | CheckedError Parser::ParseHash(Value &e, FieldDef *field) { |
1974 | 2.94k | FLATBUFFERS_ASSERT(field); |
1975 | 2.94k | Value *hash_name = field->attributes.Lookup("hash"); |
1976 | 2.94k | switch (e.type.base_type) { |
1977 | 0 | case BASE_TYPE_SHORT: { |
1978 | 0 | auto hash = FindHashFunction16(hash_name->constant.c_str()); |
1979 | 0 | int16_t hashed_value = static_cast<int16_t>(hash(attribute_.c_str())); |
1980 | 0 | e.constant = NumToString(hashed_value); |
1981 | 0 | break; |
1982 | 0 | } |
1983 | 0 | case BASE_TYPE_USHORT: { |
1984 | 0 | auto hash = FindHashFunction16(hash_name->constant.c_str()); |
1985 | 0 | uint16_t hashed_value = hash(attribute_.c_str()); |
1986 | 0 | e.constant = NumToString(hashed_value); |
1987 | 0 | break; |
1988 | 0 | } |
1989 | 727 | case BASE_TYPE_INT: { |
1990 | 727 | auto hash = FindHashFunction32(hash_name->constant.c_str()); |
1991 | 727 | int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str())); |
1992 | 727 | e.constant = NumToString(hashed_value); |
1993 | 727 | break; |
1994 | 0 | } |
1995 | 772 | case BASE_TYPE_UINT: { |
1996 | 772 | auto hash = FindHashFunction32(hash_name->constant.c_str()); |
1997 | 772 | uint32_t hashed_value = hash(attribute_.c_str()); |
1998 | 772 | e.constant = NumToString(hashed_value); |
1999 | 772 | break; |
2000 | 0 | } |
2001 | 980 | case BASE_TYPE_LONG: { |
2002 | 980 | auto hash = FindHashFunction64(hash_name->constant.c_str()); |
2003 | 980 | int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str())); |
2004 | 980 | e.constant = NumToString(hashed_value); |
2005 | 980 | break; |
2006 | 0 | } |
2007 | 465 | case BASE_TYPE_ULONG: { |
2008 | 465 | auto hash = FindHashFunction64(hash_name->constant.c_str()); |
2009 | 465 | uint64_t hashed_value = hash(attribute_.c_str()); |
2010 | 465 | e.constant = NumToString(hashed_value); |
2011 | 465 | break; |
2012 | 0 | } |
2013 | 0 | default: FLATBUFFERS_ASSERT(0); |
2014 | 2.94k | } |
2015 | 2.94k | NEXT(); |
2016 | 2.92k | return NoError(); |
2017 | 2.94k | } |
2018 | | |
2019 | 282 | CheckedError Parser::TokenError() { |
2020 | 282 | return Error("cannot parse value starting with: " + TokenToStringId(token_)); |
2021 | 282 | } |
2022 | | |
2023 | 3.02k | CheckedError Parser::ParseFunction(const std::string *name, Value &e) { |
2024 | 3.02k | ParseDepthGuard depth_guard(this); |
2025 | 3.02k | ECHECK(depth_guard.Check()); |
2026 | | |
2027 | | // Copy name, attribute will be changed on NEXT(). |
2028 | 3.02k | const auto functionname = attribute_; |
2029 | 3.02k | if (!IsFloat(e.type.base_type)) { |
2030 | 23 | return Error(functionname + ": type of argument mismatch, expecting: " + |
2031 | 23 | TypeName(BASE_TYPE_DOUBLE) + |
2032 | 23 | ", found: " + TypeName(e.type.base_type) + |
2033 | 23 | ", name: " + (name ? *name : "") + ", value: " + e.constant); |
2034 | 23 | } |
2035 | 3.00k | NEXT(); |
2036 | 3.00k | EXPECT('('); |
2037 | 3.00k | ECHECK(ParseSingleValue(name, e, false)); |
2038 | 2.78k | EXPECT(')'); |
2039 | | // calculate with double precision |
2040 | 2.75k | double x, y = 0.0; |
2041 | 2.75k | ECHECK(atot(e.constant.c_str(), *this, &x)); |
2042 | | // clang-format off |
2043 | 2.75k | auto func_match = false; |
2044 | 2.75k | #define FLATBUFFERS_FN_DOUBLE(name, op) \ |
2045 | 22.0k | if (!func_match && functionname == name) { y = op; func_match = true; } |
2046 | 2.75k | FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180); |
2047 | 2.75k | FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180); |
2048 | 2.75k | FLATBUFFERS_FN_DOUBLE("sin", sin(x)); |
2049 | 2.75k | FLATBUFFERS_FN_DOUBLE("cos", cos(x)); |
2050 | 2.75k | FLATBUFFERS_FN_DOUBLE("tan", tan(x)); |
2051 | 2.75k | FLATBUFFERS_FN_DOUBLE("asin", asin(x)); |
2052 | 2.75k | FLATBUFFERS_FN_DOUBLE("acos", acos(x)); |
2053 | 2.75k | FLATBUFFERS_FN_DOUBLE("atan", atan(x)); |
2054 | | // TODO(wvo): add more useful conversion functions here. |
2055 | 2.75k | #undef FLATBUFFERS_FN_DOUBLE |
2056 | | // clang-format on |
2057 | 2.75k | if (true != func_match) { |
2058 | 36 | return Error(std::string("Unknown conversion function: ") + functionname + |
2059 | 36 | ", field name: " + (name ? *name : "") + |
2060 | 36 | ", value: " + e.constant); |
2061 | 36 | } |
2062 | 2.71k | e.constant = NumToString(y); |
2063 | 2.71k | return NoError(); |
2064 | 2.75k | } |
2065 | | |
2066 | | CheckedError Parser::TryTypedValue(const std::string *name, int dtoken, |
2067 | | bool check, Value &e, BaseType req, |
2068 | 278k | bool *destmatch) { |
2069 | 278k | FLATBUFFERS_ASSERT(*destmatch == false && dtoken == token_); |
2070 | 278k | *destmatch = true; |
2071 | 278k | e.constant = attribute_; |
2072 | | // Check token match |
2073 | 278k | if (!check) { |
2074 | 7.94k | if (e.type.base_type == BASE_TYPE_NONE) { |
2075 | 7.93k | e.type.base_type = req; |
2076 | 7.93k | } else { |
2077 | 5 | return Error(std::string("type mismatch: expecting: ") + |
2078 | 5 | TypeName(e.type.base_type) + ", found: " + TypeName(req) + |
2079 | 5 | ", name: " + (name ? *name : "") + ", value: " + e.constant); |
2080 | 5 | } |
2081 | 7.94k | } |
2082 | | // The exponent suffix of hexadecimal float-point number is mandatory. |
2083 | | // A hex-integer constant is forbidden as an initializer of float number. |
2084 | 278k | if ((kTokenFloatConstant != dtoken) && IsFloat(e.type.base_type)) { |
2085 | 59.4k | const auto &s = e.constant; |
2086 | 59.4k | const auto k = s.find_first_of("0123456789."); |
2087 | 59.4k | if ((std::string::npos != k) && (s.length() > (k + 1)) && |
2088 | 59.4k | (s[k] == '0' && is_alpha_char(s[k + 1], 'X')) && |
2089 | 59.4k | (std::string::npos == s.find_first_of("pP", k + 2))) { |
2090 | 6 | return Error( |
2091 | 6 | "invalid number, the exponent suffix of hexadecimal " |
2092 | 6 | "floating-point literals is mandatory: \"" + |
2093 | 6 | s + "\""); |
2094 | 6 | } |
2095 | 59.4k | } |
2096 | 278k | NEXT(); |
2097 | 278k | return NoError(); |
2098 | 278k | } |
2099 | | |
2100 | | CheckedError Parser::ParseSingleValue(const std::string *name, Value &e, |
2101 | 288k | bool check_now) { |
2102 | 288k | if (token_ == '+' || token_ == '-') { |
2103 | 1.46k | const char sign = static_cast<char>(token_); |
2104 | | // Get an indentifier: NAN, INF, or function name like cos/sin/deg. |
2105 | 1.46k | NEXT(); |
2106 | 1.46k | if (token_ != kTokenIdentifier) return Error("constant name expected"); |
2107 | 1.46k | attribute_.insert(size_t(0), size_t(1), sign); |
2108 | 1.46k | } |
2109 | | |
2110 | 288k | const auto in_type = e.type.base_type; |
2111 | 288k | const auto is_tok_ident = (token_ == kTokenIdentifier); |
2112 | 288k | const auto is_tok_string = (token_ == kTokenStringConstant); |
2113 | | |
2114 | | // First see if this could be a conversion function. |
2115 | 288k | if (is_tok_ident && *cursor_ == '(') { return ParseFunction(name, e); } |
2116 | | |
2117 | | // clang-format off |
2118 | 285k | auto match = false; |
2119 | | |
2120 | 285k | #define IF_ECHECK_(force, dtoken, check, req) \ |
2121 | 616k | if (!match && ((dtoken) == token_) && ((check) || flatbuffers::IsConstTrue(force))) \ |
2122 | 616k | ECHECK(TryTypedValue(name, dtoken, check, e, req, &match)) |
2123 | 331k | #define TRY_ECHECK(dtoken, check, req) IF_ECHECK_(false, dtoken, check, req) |
2124 | 285k | #define FORCE_ECHECK(dtoken, check, req) IF_ECHECK_(true, dtoken, check, req) |
2125 | | // clang-format on |
2126 | | |
2127 | 285k | if (is_tok_ident || is_tok_string) { |
2128 | 23.2k | const auto kTokenStringOrIdent = token_; |
2129 | | // The string type is a most probable type, check it first. |
2130 | 23.2k | TRY_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING, |
2131 | 23.2k | BASE_TYPE_STRING); |
2132 | | |
2133 | | // avoid escaped and non-ascii in the string |
2134 | 23.2k | if (!match && is_tok_string && IsScalar(in_type) && |
2135 | 23.2k | !attr_is_trivial_ascii_string_) { |
2136 | 4 | return Error( |
2137 | 4 | std::string("type mismatch or invalid value, an initializer of " |
2138 | 4 | "non-string field must be trivial ASCII string: type: ") + |
2139 | 4 | TypeName(in_type) + ", name: " + (name ? *name : "") + |
2140 | 4 | ", value: " + attribute_); |
2141 | 4 | } |
2142 | | |
2143 | | // A boolean as true/false. Boolean as Integer check below. |
2144 | 23.2k | if (!match && IsBool(in_type)) { |
2145 | 7.96k | auto is_true = attribute_ == "true"; |
2146 | 7.96k | if (is_true || attribute_ == "false") { |
2147 | 402 | attribute_ = is_true ? "1" : "0"; |
2148 | | // accepts both kTokenStringConstant and kTokenIdentifier |
2149 | 402 | TRY_ECHECK(kTokenStringOrIdent, IsBool(in_type), BASE_TYPE_BOOL); |
2150 | 399 | } |
2151 | 7.96k | } |
2152 | | // Check for optional scalars. |
2153 | 23.2k | if (!match && IsScalar(in_type) && attribute_ == "null") { |
2154 | 4.99k | e.constant = "null"; |
2155 | 4.99k | NEXT(); |
2156 | 4.99k | match = true; |
2157 | 4.99k | } |
2158 | | // Check if this could be a string/identifier enum value. |
2159 | | // Enum can have only true integer base type. |
2160 | 23.2k | if (!match && IsInteger(in_type) && !IsBool(in_type) && |
2161 | 23.2k | IsIdentifierStart(*attribute_.c_str())) { |
2162 | 1.61k | ECHECK(ParseEnumFromString(e.type, &e.constant)); |
2163 | 1.39k | NEXT(); |
2164 | 1.39k | match = true; |
2165 | 1.39k | } |
2166 | | // Parse a float/integer number from the string. |
2167 | | // A "scalar-in-string" value needs extra checks. |
2168 | 23.0k | if (!match && is_tok_string && IsScalar(in_type)) { |
2169 | | // Strip trailing whitespaces from attribute_. |
2170 | 9.18k | auto last_non_ws = attribute_.find_last_not_of(' '); |
2171 | 9.18k | if (std::string::npos != last_non_ws) attribute_.resize(last_non_ws + 1); |
2172 | 9.18k | if (IsFloat(e.type.base_type)) { |
2173 | | // The functions strtod() and strtof() accept both 'nan' and |
2174 | | // 'nan(number)' literals. While 'nan(number)' is rejected by the parser |
2175 | | // as an unsupported function if is_tok_ident is true. |
2176 | 708 | if (attribute_.find_last_of(')') != std::string::npos) { |
2177 | 13 | return Error("invalid number: " + attribute_); |
2178 | 13 | } |
2179 | 708 | } |
2180 | 9.18k | } |
2181 | | // Float numbers or nan, inf, pi, etc. |
2182 | 23.0k | TRY_ECHECK(kTokenStringOrIdent, IsFloat(in_type), BASE_TYPE_FLOAT); |
2183 | | // An integer constant in string. |
2184 | 23.0k | TRY_ECHECK(kTokenStringOrIdent, IsInteger(in_type), BASE_TYPE_INT); |
2185 | | // Unknown tokens will be interpreted as string type. |
2186 | | // An attribute value may be a scalar or string constant. |
2187 | 23.0k | FORCE_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING, |
2188 | 23.0k | BASE_TYPE_STRING); |
2189 | 261k | } else { |
2190 | | // Try a float number. |
2191 | 261k | TRY_ECHECK(kTokenFloatConstant, IsFloat(in_type), BASE_TYPE_FLOAT); |
2192 | | // Integer token can init any scalar (integer of float). |
2193 | 261k | FORCE_ECHECK(kTokenIntegerConstant, IsScalar(in_type), BASE_TYPE_INT); |
2194 | 261k | } |
2195 | | // Match empty vectors for default-empty-vectors. |
2196 | 284k | if (!match && IsVector(e.type) && token_ == '[') { |
2197 | 72 | NEXT(); |
2198 | 71 | if (token_ != ']') { return Error("Expected `]` in vector default"); } |
2199 | 69 | NEXT(); |
2200 | 68 | match = true; |
2201 | 68 | e.constant = "[]"; |
2202 | 68 | } |
2203 | | |
2204 | 284k | #undef FORCE_ECHECK |
2205 | 284k | #undef TRY_ECHECK |
2206 | 284k | #undef IF_ECHECK_ |
2207 | | |
2208 | 284k | if (!match) { |
2209 | 270 | std::string msg; |
2210 | 270 | msg += "Cannot assign token starting with '" + TokenToStringId(token_) + |
2211 | 270 | "' to value of <" + std::string(TypeName(in_type)) + "> type."; |
2212 | 270 | return Error(msg); |
2213 | 270 | } |
2214 | 284k | const auto match_type = e.type.base_type; // may differ from in_type |
2215 | | // The check_now flag must be true when parse a fbs-schema. |
2216 | | // This flag forces to check default scalar values or metadata of field. |
2217 | | // For JSON parser the flag should be false. |
2218 | | // If it is set for JSON each value will be checked twice (see ParseTable). |
2219 | | // Special case 'null' since atot can't handle that. |
2220 | 284k | if (check_now && IsScalar(match_type) && e.constant != "null") { |
2221 | | // clang-format off |
2222 | 10.4k | switch (match_type) { |
2223 | 0 | #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ |
2224 | 9.36k | case BASE_TYPE_ ## ENUM: {\ |
2225 | 9.36k | CTYPE val; \ |
2226 | 10.4k | ECHECK(atot(e.constant.c_str(), *this, &val)); \ |
2227 | 9.36k | SingleValueRepack(e, val); \ |
2228 | 9.36k | break; } |
2229 | 10.4k | FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) |
2230 | 0 | #undef FLATBUFFERS_TD |
2231 | 0 | default: break; |
2232 | 10.4k | } |
2233 | | // clang-format on |
2234 | 10.4k | } |
2235 | 283k | return NoError(); |
2236 | 284k | } |
2237 | | |
2238 | | StructDef *Parser::LookupCreateStruct(const std::string &name, |
2239 | 445k | bool create_if_new, bool definition) { |
2240 | 445k | std::string qualified_name = current_namespace_->GetFullyQualifiedName(name); |
2241 | | // See if it exists pre-declared by an unqualified use. |
2242 | 445k | auto struct_def = LookupStruct(name); |
2243 | 445k | if (struct_def && struct_def->predecl) { |
2244 | 218k | if (definition) { |
2245 | | // Make sure it has the current namespace, and is registered under its |
2246 | | // qualified name. |
2247 | 2.11k | struct_def->defined_namespace = current_namespace_; |
2248 | 2.11k | structs_.Move(name, qualified_name); |
2249 | 2.11k | } |
2250 | 218k | return struct_def; |
2251 | 218k | } |
2252 | | // See if it exists pre-declared by an qualified use. |
2253 | 227k | struct_def = LookupStruct(qualified_name); |
2254 | 227k | if (struct_def && struct_def->predecl) { |
2255 | 74 | if (definition) { |
2256 | | // Make sure it has the current namespace. |
2257 | 6 | struct_def->defined_namespace = current_namespace_; |
2258 | 6 | } |
2259 | 74 | return struct_def; |
2260 | 74 | } |
2261 | 227k | if (!definition && !struct_def) { |
2262 | 200k | struct_def = LookupStructThruParentNamespaces(name); |
2263 | 200k | } |
2264 | 227k | if (!struct_def && create_if_new) { |
2265 | 184k | struct_def = new StructDef(); |
2266 | 184k | if (definition) { |
2267 | 21.7k | structs_.Add(qualified_name, struct_def); |
2268 | 21.7k | struct_def->name = name; |
2269 | 21.7k | struct_def->defined_namespace = current_namespace_; |
2270 | 162k | } else { |
2271 | | // Not a definition. |
2272 | | // Rather than failing, we create a "pre declared" StructDef, due to |
2273 | | // circular references, and check for errors at the end of parsing. |
2274 | | // It is defined in the current namespace, as the best guess what the |
2275 | | // final namespace will be. |
2276 | 162k | structs_.Add(name, struct_def); |
2277 | 162k | struct_def->name = name; |
2278 | 162k | struct_def->defined_namespace = current_namespace_; |
2279 | 162k | struct_def->original_location.reset( |
2280 | 162k | new std::string(file_being_parsed_ + ":" + NumToString(line_))); |
2281 | 162k | } |
2282 | 184k | } |
2283 | 227k | return struct_def; |
2284 | 227k | } |
2285 | | |
2286 | 0 | const EnumVal *EnumDef::MinValue() const { |
2287 | 0 | return vals.vec.empty() ? nullptr : vals.vec.front(); |
2288 | 0 | } |
2289 | 0 | const EnumVal *EnumDef::MaxValue() const { |
2290 | 0 | return vals.vec.empty() ? nullptr : vals.vec.back(); |
2291 | 0 | } |
2292 | | |
2293 | 0 | uint64_t EnumDef::Distance(const EnumVal *v1, const EnumVal *v2) const { |
2294 | 0 | return IsUInt64() ? EnumDistanceImpl(v1->GetAsUInt64(), v2->GetAsUInt64()) |
2295 | 0 | : EnumDistanceImpl(v1->GetAsInt64(), v2->GetAsInt64()); |
2296 | 0 | } |
2297 | | |
2298 | 0 | std::string EnumDef::AllFlags() const { |
2299 | 0 | FLATBUFFERS_ASSERT(attributes.Lookup("bit_flags")); |
2300 | 0 | uint64_t u64 = 0; |
2301 | 0 | for (auto it = Vals().begin(); it != Vals().end(); ++it) { |
2302 | 0 | u64 |= (*it)->GetAsUInt64(); |
2303 | 0 | } |
2304 | 0 | return IsUInt64() ? NumToString(u64) : NumToString(static_cast<int64_t>(u64)); |
2305 | 0 | } |
2306 | | |
2307 | | EnumVal *EnumDef::ReverseLookup(int64_t enum_idx, |
2308 | 1.88k | bool skip_union_default) const { |
2309 | 1.88k | auto skip_first = static_cast<int>(is_union && skip_union_default); |
2310 | 2.78k | for (auto it = Vals().begin() + skip_first; it != Vals().end(); ++it) { |
2311 | 2.54k | if ((*it)->GetAsInt64() == enum_idx) { return *it; } |
2312 | 2.54k | } |
2313 | 239 | return nullptr; |
2314 | 1.88k | } |
2315 | | |
2316 | 1.61k | EnumVal *EnumDef::FindByValue(const std::string &constant) const { |
2317 | 1.61k | int64_t i64; |
2318 | 1.61k | auto done = false; |
2319 | 1.61k | if (IsUInt64()) { |
2320 | 343 | uint64_t u64; // avoid reinterpret_cast of pointers |
2321 | 343 | done = StringToNumber(constant.c_str(), &u64); |
2322 | 343 | i64 = static_cast<int64_t>(u64); |
2323 | 1.27k | } else { |
2324 | 1.27k | done = StringToNumber(constant.c_str(), &i64); |
2325 | 1.27k | } |
2326 | 1.61k | FLATBUFFERS_ASSERT(done); |
2327 | 1.61k | if (!done) return nullptr; |
2328 | 1.61k | return ReverseLookup(i64, false); |
2329 | 1.61k | } |
2330 | | |
2331 | 30.0k | void EnumDef::SortByValue() { |
2332 | 30.0k | auto &v = vals.vec; |
2333 | 30.0k | if (IsUInt64()) |
2334 | 2.05M | std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) { |
2335 | 2.05M | if (e1->GetAsUInt64() == e2->GetAsUInt64()) { |
2336 | 325k | return e1->name < e2->name; |
2337 | 325k | } |
2338 | 1.73M | return e1->GetAsUInt64() < e2->GetAsUInt64(); |
2339 | 2.05M | }); |
2340 | 17.4k | else |
2341 | 1.97M | std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) { |
2342 | 1.97M | if (e1->GetAsInt64() == e2->GetAsInt64()) { return e1->name < e2->name; } |
2343 | 1.69M | return e1->GetAsInt64() < e2->GetAsInt64(); |
2344 | 1.97M | }); |
2345 | 30.0k | } |
2346 | | |
2347 | 0 | void EnumDef::RemoveDuplicates() { |
2348 | | // This method depends form SymbolTable implementation! |
2349 | | // 1) vals.vec - owner (raw pointer) |
2350 | | // 2) vals.dict - access map |
2351 | 0 | auto first = vals.vec.begin(); |
2352 | 0 | auto last = vals.vec.end(); |
2353 | 0 | if (first == last) return; |
2354 | 0 | auto result = first; |
2355 | 0 | while (++first != last) { |
2356 | 0 | if ((*result)->value != (*first)->value) { |
2357 | 0 | *(++result) = *first; |
2358 | 0 | } else { |
2359 | 0 | auto ev = *first; |
2360 | 0 | for (auto it = vals.dict.begin(); it != vals.dict.end(); ++it) { |
2361 | 0 | if (it->second == ev) it->second = *result; // reassign |
2362 | 0 | } |
2363 | 0 | delete ev; // delete enum value |
2364 | 0 | *first = nullptr; |
2365 | 0 | } |
2366 | 0 | } |
2367 | 0 | vals.vec.erase(++result, last); |
2368 | 0 | } |
2369 | | |
2370 | 2.09k | template<typename T> void EnumDef::ChangeEnumValue(EnumVal *ev, T new_value) { |
2371 | 2.09k | ev->value = static_cast<int64_t>(new_value); |
2372 | 2.09k | } |
2373 | | |
2374 | | namespace EnumHelper { |
2375 | | template<BaseType E> struct EnumValType { |
2376 | | typedef int64_t type; |
2377 | | }; |
2378 | | template<> struct EnumValType<BASE_TYPE_ULONG> { |
2379 | | typedef uint64_t type; |
2380 | | }; |
2381 | | } // namespace EnumHelper |
2382 | | |
2383 | | struct EnumValBuilder { |
2384 | 541k | EnumVal *CreateEnumerator(const std::string &ev_name) { |
2385 | 541k | FLATBUFFERS_ASSERT(!temp); |
2386 | 541k | auto first = enum_def.vals.vec.empty(); |
2387 | 541k | user_value = first; |
2388 | 541k | temp = new EnumVal(ev_name, first ? 0 : enum_def.vals.vec.back()->value); |
2389 | 541k | return temp; |
2390 | 541k | } |
2391 | | |
2392 | 0 | EnumVal *CreateEnumerator(const std::string &ev_name, int64_t val) { |
2393 | 0 | FLATBUFFERS_ASSERT(!temp); |
2394 | 0 | user_value = true; |
2395 | 0 | temp = new EnumVal(ev_name, val); |
2396 | 0 | return temp; |
2397 | 0 | } |
2398 | | |
2399 | 541k | FLATBUFFERS_CHECKED_ERROR AcceptEnumerator(const std::string &name) { |
2400 | 541k | FLATBUFFERS_ASSERT(temp); |
2401 | 541k | ECHECK(ValidateValue(&temp->value, false == user_value)); |
2402 | 540k | FLATBUFFERS_ASSERT((temp->union_type.enum_def == nullptr) || |
2403 | 540k | (temp->union_type.enum_def == &enum_def)); |
2404 | 540k | auto not_unique = enum_def.vals.Add(name, temp); |
2405 | 540k | temp = nullptr; |
2406 | 540k | if (not_unique) return parser.Error("enum value already exists: " + name); |
2407 | 540k | return NoError(); |
2408 | 540k | } |
2409 | | |
2410 | 541k | FLATBUFFERS_CHECKED_ERROR AcceptEnumerator() { |
2411 | 541k | return AcceptEnumerator(temp->name); |
2412 | 541k | } |
2413 | | |
2414 | 143k | FLATBUFFERS_CHECKED_ERROR AssignEnumeratorValue(const std::string &value) { |
2415 | 143k | user_value = true; |
2416 | 143k | auto fit = false; |
2417 | 143k | if (enum_def.IsUInt64()) { |
2418 | 73.4k | uint64_t u64; |
2419 | 73.4k | fit = StringToNumber(value.c_str(), &u64); |
2420 | 73.4k | temp->value = static_cast<int64_t>(u64); // well-defined since C++20. |
2421 | 73.4k | } else { |
2422 | 70.0k | int64_t i64; |
2423 | 70.0k | fit = StringToNumber(value.c_str(), &i64); |
2424 | 70.0k | temp->value = i64; |
2425 | 70.0k | } |
2426 | 143k | if (!fit) return parser.Error("enum value does not fit, \"" + value + "\""); |
2427 | 143k | return NoError(); |
2428 | 143k | } |
2429 | | |
2430 | | template<BaseType E, typename CTYPE> |
2431 | 541k | inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) { |
2432 | 541k | typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t |
2433 | 541k | static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType"); |
2434 | 541k | const auto v = static_cast<T>(*ev); |
2435 | 541k | auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)()); |
2436 | 541k | auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)()); |
2437 | 541k | if (v < dn || v > (up - m)) { |
2438 | 932 | return parser.Error("enum value does not fit, \"" + NumToString(v) + |
2439 | 932 | (m ? " + 1\"" : "\"") + " out of " + |
2440 | 932 | TypeToIntervalString<CTYPE>()); |
2441 | 932 | } |
2442 | 540k | *ev = static_cast<int64_t>(v + m); // well-defined since C++20. |
2443 | 540k | return NoError(); |
2444 | 541k | } Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)0, unsigned char>(long*, int) flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)1, unsigned char>(long*, int) Line | Count | Source | 2431 | 62.1k | inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) { | 2432 | 62.1k | typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t | 2433 | 62.1k | static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType"); | 2434 | 62.1k | const auto v = static_cast<T>(*ev); | 2435 | 62.1k | auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)()); | 2436 | 62.1k | auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)()); | 2437 | 62.1k | if (v < dn || v > (up - m)) { | 2438 | 171 | return parser.Error("enum value does not fit, \"" + NumToString(v) + | 2439 | 171 | (m ? " + 1\"" : "\"") + " out of " + | 2440 | 171 | TypeToIntervalString<CTYPE>()); | 2441 | 171 | } | 2442 | 62.0k | *ev = static_cast<int64_t>(v + m); // well-defined since C++20. | 2443 | 62.0k | return NoError(); | 2444 | 62.1k | } |
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)2, unsigned char>(long*, int) flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)3, signed char>(long*, int) Line | Count | Source | 2431 | 1.01k | inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) { | 2432 | 1.01k | typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t | 2433 | 1.01k | static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType"); | 2434 | 1.01k | const auto v = static_cast<T>(*ev); | 2435 | 1.01k | auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)()); | 2436 | 1.01k | auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)()); | 2437 | 1.01k | if (v < dn || v > (up - m)) { | 2438 | 157 | return parser.Error("enum value does not fit, \"" + NumToString(v) + | 2439 | 157 | (m ? " + 1\"" : "\"") + " out of " + | 2440 | 157 | TypeToIntervalString<CTYPE>()); | 2441 | 157 | } | 2442 | 858 | *ev = static_cast<int64_t>(v + m); // well-defined since C++20. | 2443 | 858 | return NoError(); | 2444 | 1.01k | } |
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)4, unsigned char>(long*, int) Line | Count | Source | 2431 | 2.19k | inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) { | 2432 | 2.19k | typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t | 2433 | 2.19k | static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType"); | 2434 | 2.19k | const auto v = static_cast<T>(*ev); | 2435 | 2.19k | auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)()); | 2436 | 2.19k | auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)()); | 2437 | 2.19k | if (v < dn || v > (up - m)) { | 2438 | 129 | return parser.Error("enum value does not fit, \"" + NumToString(v) + | 2439 | 129 | (m ? " + 1\"" : "\"") + " out of " + | 2440 | 129 | TypeToIntervalString<CTYPE>()); | 2441 | 129 | } | 2442 | 2.06k | *ev = static_cast<int64_t>(v + m); // well-defined since C++20. | 2443 | 2.06k | return NoError(); | 2444 | 2.19k | } |
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)5, short>(long*, int) Line | Count | Source | 2431 | 2.96k | inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) { | 2432 | 2.96k | typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t | 2433 | 2.96k | static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType"); | 2434 | 2.96k | const auto v = static_cast<T>(*ev); | 2435 | 2.96k | auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)()); | 2436 | 2.96k | auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)()); | 2437 | 2.96k | if (v < dn || v > (up - m)) { | 2438 | 131 | return parser.Error("enum value does not fit, \"" + NumToString(v) + | 2439 | 131 | (m ? " + 1\"" : "\"") + " out of " + | 2440 | 131 | TypeToIntervalString<CTYPE>()); | 2441 | 131 | } | 2442 | 2.83k | *ev = static_cast<int64_t>(v + m); // well-defined since C++20. | 2443 | 2.83k | return NoError(); | 2444 | 2.96k | } |
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)6, unsigned short>(long*, int) Line | Count | Source | 2431 | 36.4k | inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) { | 2432 | 36.4k | typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t | 2433 | 36.4k | static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType"); | 2434 | 36.4k | const auto v = static_cast<T>(*ev); | 2435 | 36.4k | auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)()); | 2436 | 36.4k | auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)()); | 2437 | 36.4k | if (v < dn || v > (up - m)) { | 2438 | 83 | return parser.Error("enum value does not fit, \"" + NumToString(v) + | 2439 | 83 | (m ? " + 1\"" : "\"") + " out of " + | 2440 | 83 | TypeToIntervalString<CTYPE>()); | 2441 | 83 | } | 2442 | 36.3k | *ev = static_cast<int64_t>(v + m); // well-defined since C++20. | 2443 | 36.3k | return NoError(); | 2444 | 36.4k | } |
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)7, int>(long*, int) Line | Count | Source | 2431 | 17.6k | inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) { | 2432 | 17.6k | typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t | 2433 | 17.6k | static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType"); | 2434 | 17.6k | const auto v = static_cast<T>(*ev); | 2435 | 17.6k | auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)()); | 2436 | 17.6k | auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)()); | 2437 | 17.6k | if (v < dn || v > (up - m)) { | 2438 | 118 | return parser.Error("enum value does not fit, \"" + NumToString(v) + | 2439 | 118 | (m ? " + 1\"" : "\"") + " out of " + | 2440 | 118 | TypeToIntervalString<CTYPE>()); | 2441 | 118 | } | 2442 | 17.4k | *ev = static_cast<int64_t>(v + m); // well-defined since C++20. | 2443 | 17.4k | return NoError(); | 2444 | 17.6k | } |
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)8, unsigned int>(long*, int) Line | Count | Source | 2431 | 125k | inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) { | 2432 | 125k | typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t | 2433 | 125k | static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType"); | 2434 | 125k | const auto v = static_cast<T>(*ev); | 2435 | 125k | auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)()); | 2436 | 125k | auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)()); | 2437 | 125k | if (v < dn || v > (up - m)) { | 2438 | 141 | return parser.Error("enum value does not fit, \"" + NumToString(v) + | 2439 | 141 | (m ? " + 1\"" : "\"") + " out of " + | 2440 | 141 | TypeToIntervalString<CTYPE>()); | 2441 | 141 | } | 2442 | 125k | *ev = static_cast<int64_t>(v + m); // well-defined since C++20. | 2443 | 125k | return NoError(); | 2444 | 125k | } |
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)9, long>(long*, int) Line | Count | Source | 2431 | 28.0k | inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) { | 2432 | 28.0k | typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t | 2433 | 28.0k | static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType"); | 2434 | 28.0k | const auto v = static_cast<T>(*ev); | 2435 | 28.0k | auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)()); | 2436 | 28.0k | auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)()); | 2437 | 28.0k | if (v < dn || v > (up - m)) { | 2438 | 1 | return parser.Error("enum value does not fit, \"" + NumToString(v) + | 2439 | 1 | (m ? " + 1\"" : "\"") + " out of " + | 2440 | 1 | TypeToIntervalString<CTYPE>()); | 2441 | 1 | } | 2442 | 28.0k | *ev = static_cast<int64_t>(v + m); // well-defined since C++20. | 2443 | 28.0k | return NoError(); | 2444 | 28.0k | } |
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)10, unsigned long>(long*, int) Line | Count | Source | 2431 | 265k | inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) { | 2432 | 265k | typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t | 2433 | 265k | static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType"); | 2434 | 265k | const auto v = static_cast<T>(*ev); | 2435 | 265k | auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)()); | 2436 | 265k | auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)()); | 2437 | 265k | if (v < dn || v > (up - m)) { | 2438 | 1 | return parser.Error("enum value does not fit, \"" + NumToString(v) + | 2439 | 1 | (m ? " + 1\"" : "\"") + " out of " + | 2440 | 1 | TypeToIntervalString<CTYPE>()); | 2441 | 1 | } | 2442 | 265k | *ev = static_cast<int64_t>(v + m); // well-defined since C++20. | 2443 | 265k | return NoError(); | 2444 | 265k | } |
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)11, float>(long*, int) Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)12, double>(long*, int) |
2445 | | |
2446 | 541k | FLATBUFFERS_CHECKED_ERROR ValidateValue(int64_t *ev, bool next) { |
2447 | | // clang-format off |
2448 | 541k | switch (enum_def.underlying_type.base_type) { |
2449 | 0 | #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ |
2450 | 541k | case BASE_TYPE_##ENUM: { \ |
2451 | 541k | if (!IsInteger(BASE_TYPE_##ENUM)) break; \ |
2452 | 541k | return ValidateImpl<BASE_TYPE_##ENUM, CTYPE>(ev, next ? 1 : 0); \ |
2453 | 541k | } |
2454 | 541k | FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) |
2455 | 0 | #undef FLATBUFFERS_TD |
2456 | 0 | default: break; |
2457 | 541k | } |
2458 | | // clang-format on |
2459 | 0 | return parser.Error("fatal: invalid enum underlying type"); |
2460 | 541k | } |
2461 | | |
2462 | | EnumValBuilder(Parser &_parser, EnumDef &_enum_def) |
2463 | 32.3k | : parser(_parser), |
2464 | 32.3k | enum_def(_enum_def), |
2465 | 32.3k | temp(nullptr), |
2466 | 32.3k | user_value(false) {} |
2467 | | |
2468 | 32.3k | ~EnumValBuilder() { delete temp; } |
2469 | | |
2470 | | Parser &parser; |
2471 | | EnumDef &enum_def; |
2472 | | EnumVal *temp; |
2473 | | bool user_value; |
2474 | | }; |
2475 | | |
2476 | | CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest, |
2477 | 33.1k | const char *filename) { |
2478 | 33.1k | std::vector<std::string> enum_comment = doc_comment_; |
2479 | 33.1k | NEXT(); |
2480 | 33.1k | std::string enum_name = attribute_; |
2481 | 33.1k | EXPECT(kTokenIdentifier); |
2482 | 33.1k | EnumDef *enum_def; |
2483 | 33.1k | ECHECK(StartEnum(enum_name, is_union, &enum_def)); |
2484 | 33.0k | if (filename != nullptr && !opts.project_root.empty()) { |
2485 | 0 | enum_def->declaration_file = |
2486 | 0 | &GetPooledString(FilePath(opts.project_root, filename, opts.binary_schema_absolute_paths)); |
2487 | 0 | } |
2488 | 33.0k | enum_def->doc_comment = enum_comment; |
2489 | 33.0k | if (!opts.proto_mode) { |
2490 | | // Give specialized error message, since this type spec used to |
2491 | | // be optional in the first FlatBuffers release. |
2492 | 33.0k | bool explicit_underlying_type = false; |
2493 | 33.0k | if (!Is(':')) { |
2494 | | // Enum is forced to have an explicit underlying type in declaration. |
2495 | 7.90k | if (!is_union) { |
2496 | 140 | return Error( |
2497 | 140 | "must specify the underlying integer type for this" |
2498 | 140 | " enum (e.g. \': short\', which was the default)."); |
2499 | 140 | } |
2500 | 25.1k | } else { |
2501 | | // Union underlying type is only supported for cpp |
2502 | 25.1k | if (is_union && !SupportsUnionUnderlyingType()) { |
2503 | 0 | return Error( |
2504 | 0 | "Underlying type for union is not yet supported in at least one of " |
2505 | 0 | "the specified programming languages."); |
2506 | 0 | } |
2507 | 25.1k | NEXT(); |
2508 | 25.1k | explicit_underlying_type = true; |
2509 | 25.1k | } |
2510 | | |
2511 | 32.9k | if (explicit_underlying_type) { |
2512 | | // Specify the integer type underlying this enum. |
2513 | 25.1k | ECHECK(ParseType(enum_def->underlying_type)); |
2514 | 24.9k | if (!IsInteger(enum_def->underlying_type.base_type) || IsBool(enum_def->underlying_type.base_type)) { |
2515 | 167 | return Error("underlying " + std::string(is_union ? "union" : "enum") + "type must be integral"); |
2516 | 167 | } |
2517 | | |
2518 | | // Make this type refer back to the enum it was derived from. |
2519 | 24.7k | enum_def->underlying_type.enum_def = enum_def; |
2520 | 24.7k | } |
2521 | | |
2522 | 32.9k | } |
2523 | 32.5k | ECHECK(ParseMetaData(&enum_def->attributes)); |
2524 | 32.3k | const auto underlying_type = enum_def->underlying_type.base_type; |
2525 | 32.3k | if (enum_def->attributes.Lookup("bit_flags") && |
2526 | 32.3k | !IsUnsigned(underlying_type)) { |
2527 | | // todo: Convert to the Error in the future? |
2528 | 249 | Warning("underlying type of bit_flags enum must be unsigned"); |
2529 | 249 | } |
2530 | 32.3k | if (enum_def->attributes.Lookup("force_align")) { |
2531 | 1 | return Error("`force_align` is not a valid attribute for Enums. "); |
2532 | 1 | } |
2533 | 32.3k | EnumValBuilder evb(*this, *enum_def); |
2534 | 32.3k | EXPECT('{'); |
2535 | | // A lot of code generatos expect that an enum is not-empty. |
2536 | 32.1k | if ((is_union || Is('}')) && !opts.proto_mode) { |
2537 | 17.8k | evb.CreateEnumerator("NONE"); |
2538 | 17.8k | ECHECK(evb.AcceptEnumerator()); |
2539 | 17.8k | } |
2540 | 32.1k | std::set<std::pair<BaseType, StructDef *>> union_types; |
2541 | 527k | while (!Is('}')) { |
2542 | 524k | if (opts.proto_mode && attribute_ == "option") { |
2543 | 0 | ECHECK(ParseProtoOption()); |
2544 | 524k | } else { |
2545 | 524k | auto &ev = *evb.CreateEnumerator(attribute_); |
2546 | 524k | auto full_name = ev.name; |
2547 | 524k | ev.doc_comment = doc_comment_; |
2548 | 524k | EXPECT(kTokenIdentifier); |
2549 | 523k | if (is_union) { |
2550 | 360k | ECHECK(ParseNamespacing(&full_name, &ev.name)); |
2551 | 360k | if (opts.union_value_namespacing) { |
2552 | | // Since we can't namespace the actual enum identifiers, turn |
2553 | | // namespace parts into part of the identifier. |
2554 | 360k | ev.name = full_name; |
2555 | 360k | std::replace(ev.name.begin(), ev.name.end(), '.', '_'); |
2556 | 360k | } |
2557 | 360k | if (Is(':')) { |
2558 | 3.48k | NEXT(); |
2559 | 3.48k | ECHECK(ParseType(ev.union_type)); |
2560 | 3.47k | if (ev.union_type.base_type != BASE_TYPE_STRUCT && |
2561 | 3.47k | ev.union_type.base_type != BASE_TYPE_STRING) |
2562 | 27 | return Error("union value type may only be table/struct/string"); |
2563 | 356k | } else { |
2564 | 356k | ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name)); |
2565 | 356k | } |
2566 | 360k | if (!enum_def->uses_multiple_type_instances) { |
2567 | 357k | auto ins = union_types.insert(std::make_pair( |
2568 | 357k | ev.union_type.base_type, ev.union_type.struct_def)); |
2569 | 357k | enum_def->uses_multiple_type_instances = (false == ins.second); |
2570 | 357k | } |
2571 | 360k | } |
2572 | | |
2573 | 523k | if (Is('=')) { |
2574 | 143k | NEXT(); |
2575 | 143k | ECHECK(evb.AssignEnumeratorValue(attribute_)); |
2576 | 143k | EXPECT(kTokenIntegerConstant); |
2577 | 143k | } |
2578 | | |
2579 | 523k | if (opts.proto_mode && Is('[')) { |
2580 | 0 | NEXT(); |
2581 | | // ignore attributes on enums. |
2582 | 0 | while (token_ != ']') NEXT(); |
2583 | 0 | NEXT(); |
2584 | 523k | } else { |
2585 | | // parse attributes in fbs schema |
2586 | 523k | ECHECK(ParseMetaData(&ev.attributes)); |
2587 | 523k | } |
2588 | | |
2589 | 523k | ECHECK(evb.AcceptEnumerator()); |
2590 | 522k | } |
2591 | 522k | if (!Is(opts.proto_mode ? ';' : ',')) break; |
2592 | 495k | NEXT(); |
2593 | 495k | } |
2594 | 30.8k | EXPECT('}'); |
2595 | | |
2596 | | // At this point, the enum can be empty if input is invalid proto-file. |
2597 | 30.1k | if (!enum_def->size()) |
2598 | 0 | return Error("incomplete enum declaration, values not found"); |
2599 | | |
2600 | 30.1k | if (enum_def->attributes.Lookup("bit_flags")) { |
2601 | 501 | const auto base_width = static_cast<uint64_t>(8 * SizeOf(underlying_type)); |
2602 | 2.59k | for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end(); |
2603 | 2.19k | ++it) { |
2604 | 2.19k | auto ev = *it; |
2605 | 2.19k | const auto u = ev->GetAsUInt64(); |
2606 | | // Stop manipulations with the sign. |
2607 | 2.19k | if (!IsUnsigned(underlying_type) && u == (base_width - 1)) |
2608 | 2 | return Error("underlying type of bit_flags enum must be unsigned"); |
2609 | 2.18k | if (u >= base_width) |
2610 | 97 | return Error("bit flag out of range of underlying integral type"); |
2611 | 2.09k | enum_def->ChangeEnumValue(ev, 1ULL << u); |
2612 | 2.09k | } |
2613 | 501 | } |
2614 | | |
2615 | 30.0k | enum_def->SortByValue(); // Must be sorted to use MinValue/MaxValue. |
2616 | | |
2617 | | // Ensure enum value uniqueness. |
2618 | 30.0k | auto prev_it = enum_def->Vals().begin(); |
2619 | 465k | for (auto it = prev_it + 1; it != enum_def->Vals().end(); ++it) { |
2620 | 438k | auto prev_ev = *prev_it; |
2621 | 438k | auto ev = *it; |
2622 | 438k | if (prev_ev->GetAsUInt64() == ev->GetAsUInt64()) |
2623 | 2.89k | return Error("all enum values must be unique: " + prev_ev->name + |
2624 | 2.89k | " and " + ev->name + " are both " + |
2625 | 2.89k | NumToString(ev->GetAsInt64())); |
2626 | 438k | } |
2627 | | |
2628 | 27.1k | if (dest) *dest = enum_def; |
2629 | 27.1k | const auto qualified_name = |
2630 | 27.1k | current_namespace_->GetFullyQualifiedName(enum_def->name); |
2631 | 27.1k | if (types_.Add(qualified_name, new Type(BASE_TYPE_UNION, nullptr, enum_def))) |
2632 | 1 | return Error("datatype already exists: " + qualified_name); |
2633 | 27.1k | return NoError(); |
2634 | 27.1k | } |
2635 | | |
2636 | 23.9k | CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) { |
2637 | 23.9k | auto &struct_def = *LookupCreateStruct(name, true, true); |
2638 | 23.9k | if (!struct_def.predecl) |
2639 | 7 | return Error("datatype already exists: " + |
2640 | 7 | current_namespace_->GetFullyQualifiedName(name)); |
2641 | 23.8k | struct_def.predecl = false; |
2642 | 23.8k | struct_def.name = name; |
2643 | 23.8k | struct_def.file = file_being_parsed_; |
2644 | | // Move this struct to the back of the vector just in case it was predeclared, |
2645 | | // to preserve declaration order. |
2646 | 23.8k | *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = |
2647 | 23.8k | &struct_def; |
2648 | 23.8k | *dest = &struct_def; |
2649 | 23.8k | return NoError(); |
2650 | 23.9k | } |
2651 | | |
2652 | | CheckedError Parser::CheckClash(std::vector<FieldDef *> &fields, |
2653 | | StructDef *struct_def, const char *suffix, |
2654 | 118k | BaseType basetype) { |
2655 | 118k | auto len = strlen(suffix); |
2656 | 303k | for (auto it = fields.begin(); it != fields.end(); ++it) { |
2657 | 184k | auto &fname = (*it)->name; |
2658 | 184k | if (fname.length() > len && |
2659 | 184k | fname.compare(fname.length() - len, len, suffix) == 0 && |
2660 | 184k | (*it)->value.type.base_type != BASE_TYPE_UTYPE) { |
2661 | 2.53k | auto field = |
2662 | 2.53k | struct_def->fields.Lookup(fname.substr(0, fname.length() - len)); |
2663 | 2.53k | if (field && field->value.type.base_type == basetype) |
2664 | 11 | return Error("Field " + fname + |
2665 | 11 | " would clash with generated functions for field " + |
2666 | 11 | field->name); |
2667 | 2.53k | } |
2668 | 184k | } |
2669 | 118k | return NoError(); |
2670 | 118k | } |
2671 | | |
2672 | 0 | std::vector<IncludedFile> Parser::GetIncludedFiles() const { |
2673 | 0 | const auto it = files_included_per_file_.find(file_being_parsed_); |
2674 | 0 | if (it == files_included_per_file_.end()) { return {}; } |
2675 | | |
2676 | 0 | return { it->second.cbegin(), it->second.cend() }; |
2677 | 0 | } |
2678 | | |
2679 | 0 | bool Parser::SupportsOptionalScalars(const flatbuffers::IDLOptions &opts) { |
2680 | 0 | static FLATBUFFERS_CONSTEXPR unsigned long supported_langs = |
2681 | 0 | IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster | |
2682 | 0 | IDLOptions::kKotlin | IDLOptions::kKotlinKmp | IDLOptions::kCpp | |
2683 | 0 | IDLOptions::kJava | IDLOptions::kCSharp | IDLOptions::kTs | |
2684 | 0 | IDLOptions::kBinary | IDLOptions::kGo | IDLOptions::kPython | |
2685 | 0 | IDLOptions::kJson | |
2686 | 0 | IDLOptions::kNim; |
2687 | 0 | unsigned long langs = opts.lang_to_generate; |
2688 | 0 | return (langs > 0 && langs < IDLOptions::kMAX) && !(langs & ~supported_langs); |
2689 | 0 | } |
2690 | 854 | bool Parser::SupportsOptionalScalars() const { |
2691 | | // Check in general if a language isn't specified. |
2692 | 854 | return opts.lang_to_generate == 0 || SupportsOptionalScalars(opts); |
2693 | 854 | } |
2694 | | |
2695 | 136 | bool Parser::SupportsDefaultVectorsAndStrings() const { |
2696 | 136 | static FLATBUFFERS_CONSTEXPR unsigned long supported_langs = |
2697 | 136 | IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kNim; |
2698 | 136 | return !(opts.lang_to_generate & ~supported_langs); |
2699 | 136 | } |
2700 | | |
2701 | 1.90k | bool Parser::SupportsAdvancedUnionFeatures() const { |
2702 | 1.90k | return (opts.lang_to_generate & |
2703 | 1.90k | ~(IDLOptions::kCpp | IDLOptions::kTs | IDLOptions::kPhp | |
2704 | 1.90k | IDLOptions::kJava | IDLOptions::kCSharp | IDLOptions::kKotlin | |
2705 | 1.90k | IDLOptions::kBinary | IDLOptions::kSwift | IDLOptions::kNim | |
2706 | 1.90k | IDLOptions::kJson | IDLOptions::kKotlinKmp)) == 0; |
2707 | 1.90k | } |
2708 | | |
2709 | 530 | bool Parser::SupportsAdvancedArrayFeatures() const { |
2710 | 530 | return (opts.lang_to_generate & |
2711 | 530 | ~(IDLOptions::kCpp | IDLOptions::kPython | IDLOptions::kJava | |
2712 | 530 | IDLOptions::kCSharp | IDLOptions::kJsonSchema | IDLOptions::kJson | |
2713 | 530 | IDLOptions::kBinary | IDLOptions::kRust | IDLOptions::kTs)) == 0; |
2714 | 530 | } |
2715 | | |
2716 | 504 | bool Parser::Supports64BitOffsets() const { |
2717 | 504 | return (opts.lang_to_generate & |
2718 | 504 | ~(IDLOptions::kCpp | IDLOptions::kJson | IDLOptions::kBinary)) == 0; |
2719 | 504 | } |
2720 | | |
2721 | 10.1k | bool Parser::SupportsUnionUnderlyingType() const { |
2722 | 10.1k | return (opts.lang_to_generate & ~(IDLOptions::kCpp | IDLOptions::kTs | |
2723 | 10.1k | IDLOptions::kBinary)) == 0; |
2724 | 10.1k | } |
2725 | | |
2726 | 5.76k | Namespace *Parser::UniqueNamespace(Namespace *ns) { |
2727 | 34.8k | for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) { |
2728 | 30.0k | if (ns->components == (*it)->components) { |
2729 | 1.04k | delete ns; |
2730 | 1.04k | return *it; |
2731 | 1.04k | } |
2732 | 30.0k | } |
2733 | 4.72k | namespaces_.push_back(ns); |
2734 | 4.72k | return ns; |
2735 | 5.76k | } |
2736 | | |
2737 | 0 | std::string Parser::UnqualifiedName(const std::string &full_qualified_name) { |
2738 | 0 | Namespace *ns = new Namespace(); |
2739 | |
|
2740 | 0 | std::size_t current, previous = 0; |
2741 | 0 | current = full_qualified_name.find('.'); |
2742 | 0 | while (current != std::string::npos) { |
2743 | 0 | ns->components.push_back( |
2744 | 0 | full_qualified_name.substr(previous, current - previous)); |
2745 | 0 | previous = current + 1; |
2746 | 0 | current = full_qualified_name.find('.', previous); |
2747 | 0 | } |
2748 | 0 | current_namespace_ = UniqueNamespace(ns); |
2749 | 0 | return full_qualified_name.substr(previous, current - previous); |
2750 | 0 | } |
2751 | | |
2752 | 25.5k | CheckedError Parser::ParseDecl(const char *filename) { |
2753 | 25.5k | std::vector<std::string> dc = doc_comment_; |
2754 | 25.5k | bool fixed = IsIdent("struct"); |
2755 | 25.5k | if (!fixed && !IsIdent("table")) return Error("declaration expected"); |
2756 | 23.9k | NEXT(); |
2757 | 23.9k | std::string name = attribute_; |
2758 | 23.9k | EXPECT(kTokenIdentifier); |
2759 | 23.9k | StructDef *struct_def; |
2760 | 23.9k | ECHECK(StartStruct(name, &struct_def)); |
2761 | 23.8k | struct_def->doc_comment = dc; |
2762 | 23.8k | struct_def->fixed = fixed; |
2763 | 23.8k | if (filename && !opts.project_root.empty()) { |
2764 | 0 | struct_def->declaration_file = |
2765 | 0 | &GetPooledString(FilePath(opts.project_root, filename, opts.binary_schema_absolute_paths)); |
2766 | 0 | } |
2767 | 23.8k | ECHECK(ParseMetaData(&struct_def->attributes)); |
2768 | 23.6k | struct_def->sortbysize = |
2769 | 23.6k | struct_def->attributes.Lookup("original_order") == nullptr && !fixed; |
2770 | 23.6k | EXPECT('{'); |
2771 | 57.8k | while (token_ != '}') ECHECK(ParseField(*struct_def)); |
2772 | 20.1k | if (fixed) { |
2773 | 1.09k | const auto force_align = struct_def->attributes.Lookup("force_align"); |
2774 | 1.09k | if (force_align) { |
2775 | 425 | size_t align; |
2776 | 425 | ECHECK(ParseAlignAttribute(force_align->constant, struct_def->minalign, |
2777 | 425 | &align)); |
2778 | 327 | struct_def->minalign = align; |
2779 | 327 | } |
2780 | 992 | if (!struct_def->bytesize) return Error("size 0 structs not allowed"); |
2781 | 992 | } |
2782 | 20.0k | struct_def->PadLastField(struct_def->minalign); |
2783 | | // Check if this is a table that has manual id assignments |
2784 | 20.0k | auto &fields = struct_def->fields.vec; |
2785 | 20.0k | if (!fixed && fields.size()) { |
2786 | 13.6k | size_t num_id_fields = 0; |
2787 | 52.9k | for (auto it = fields.begin(); it != fields.end(); ++it) { |
2788 | 39.2k | if ((*it)->attributes.Lookup("id")) num_id_fields++; |
2789 | 39.2k | } |
2790 | | // If any fields have ids.. |
2791 | 13.6k | if (num_id_fields || opts.require_explicit_ids) { |
2792 | | // Then all fields must have them. |
2793 | 371 | if (num_id_fields != fields.size()) { |
2794 | 2 | if (opts.require_explicit_ids) { |
2795 | 0 | return Error( |
2796 | 0 | "all fields must have an 'id' attribute when " |
2797 | 0 | "--require-explicit-ids is used"); |
2798 | 2 | } else { |
2799 | 2 | return Error( |
2800 | 2 | "either all fields or no fields must have an 'id' attribute"); |
2801 | 2 | } |
2802 | 2 | } |
2803 | | // Simply sort by id, then the fields are the same as if no ids had |
2804 | | // been specified. |
2805 | 369 | std::sort(fields.begin(), fields.end(), compareFieldDefs); |
2806 | | // Verify we have a contiguous set, and reassign vtable offsets. |
2807 | 369 | FLATBUFFERS_ASSERT(fields.size() <= |
2808 | 369 | flatbuffers::numeric_limits<voffset_t>::max()); |
2809 | 789 | for (voffset_t i = 0; i < static_cast<voffset_t>(fields.size()); i++) { |
2810 | 762 | auto &field = *fields[i]; |
2811 | 762 | const auto &id_str = field.attributes.Lookup("id")->constant; |
2812 | | |
2813 | | // Metadata values have a dynamic type, they can be `float`, 'int', or |
2814 | | // 'string`. |
2815 | | // The FieldIndexToOffset(i) expects the voffset_t so `id` is limited by |
2816 | | // this type. |
2817 | 762 | voffset_t id = 0; |
2818 | 762 | const auto done = !atot(id_str.c_str(), *this, &id).Check(); |
2819 | 762 | if (!done) |
2820 | 46 | return Error("field id\'s must be non-negative number, field: " + |
2821 | 46 | field.name + ", id: " + id_str); |
2822 | 716 | if (i != id) |
2823 | 296 | return Error("field id\'s must be consecutive from 0, id " + |
2824 | 296 | NumToString(i) + " missing or set twice, field: " + |
2825 | 296 | field.name + ", id: " + id_str); |
2826 | 420 | field.value.offset = FieldIndexToOffset(i); |
2827 | 420 | } |
2828 | 369 | } |
2829 | 13.6k | } |
2830 | | |
2831 | 19.7k | ECHECK( |
2832 | 19.7k | CheckClash(fields, struct_def, UnionTypeFieldSuffix(), BASE_TYPE_UNION)); |
2833 | 19.7k | ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION)); |
2834 | 19.7k | ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR)); |
2835 | 19.7k | ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR)); |
2836 | 19.7k | ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING)); |
2837 | 19.7k | ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING)); |
2838 | 19.7k | EXPECT('}'); |
2839 | 19.7k | const auto qualified_name = |
2840 | 19.7k | current_namespace_->GetFullyQualifiedName(struct_def->name); |
2841 | 19.7k | if (types_.Add(qualified_name, |
2842 | 19.7k | new Type(BASE_TYPE_STRUCT, struct_def, nullptr))) |
2843 | 3 | return Error("datatype already exists: " + qualified_name); |
2844 | 19.7k | return NoError(); |
2845 | 19.7k | } |
2846 | | |
2847 | 2.10k | CheckedError Parser::ParseService(const char *filename) { |
2848 | 2.10k | std::vector<std::string> service_comment = doc_comment_; |
2849 | 2.10k | NEXT(); |
2850 | 2.09k | auto service_name = attribute_; |
2851 | 2.09k | EXPECT(kTokenIdentifier); |
2852 | 2.09k | auto &service_def = *new ServiceDef(); |
2853 | 2.09k | service_def.name = service_name; |
2854 | 2.09k | service_def.file = file_being_parsed_; |
2855 | 2.09k | service_def.doc_comment = service_comment; |
2856 | 2.09k | service_def.defined_namespace = current_namespace_; |
2857 | 2.09k | if (filename != nullptr && !opts.project_root.empty()) { |
2858 | 0 | service_def.declaration_file = |
2859 | 0 | &GetPooledString(FilePath(opts.project_root, filename, opts.binary_schema_absolute_paths)); |
2860 | 0 | } |
2861 | 2.09k | if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name), |
2862 | 2.09k | &service_def)) |
2863 | 2 | return Error("service already exists: " + service_name); |
2864 | 2.09k | ECHECK(ParseMetaData(&service_def.attributes)); |
2865 | 2.09k | EXPECT('{'); |
2866 | 6.59k | do { |
2867 | 6.59k | std::vector<std::string> doc_comment = doc_comment_; |
2868 | 6.59k | auto rpc_name = attribute_; |
2869 | 6.59k | EXPECT(kTokenIdentifier); |
2870 | 6.54k | EXPECT('('); |
2871 | 6.51k | Type reqtype, resptype; |
2872 | 6.51k | ECHECK(ParseTypeIdent(reqtype)); |
2873 | 6.51k | EXPECT(')'); |
2874 | 6.49k | EXPECT(':'); |
2875 | 6.49k | ECHECK(ParseTypeIdent(resptype)); |
2876 | 6.48k | if (reqtype.base_type != BASE_TYPE_STRUCT || reqtype.struct_def->fixed || |
2877 | 6.48k | resptype.base_type != BASE_TYPE_STRUCT || resptype.struct_def->fixed) |
2878 | 9 | return Error("rpc request and response types must be tables"); |
2879 | 6.47k | auto &rpc = *new RPCCall(); |
2880 | 6.47k | rpc.name = rpc_name; |
2881 | 6.47k | rpc.request = reqtype.struct_def; |
2882 | 6.47k | rpc.response = resptype.struct_def; |
2883 | 6.47k | rpc.doc_comment = doc_comment; |
2884 | 6.47k | if (service_def.calls.Add(rpc_name, &rpc)) |
2885 | 15 | return Error("rpc already exists: " + rpc_name); |
2886 | 6.46k | ECHECK(ParseMetaData(&rpc.attributes)); |
2887 | 6.44k | EXPECT(';'); |
2888 | 6.28k | } while (token_ != '}'); |
2889 | 1.61k | NEXT(); |
2890 | 1.61k | return NoError(); |
2891 | 1.61k | } |
2892 | | |
2893 | 9.38k | bool Parser::SetRootType(const char *name) { |
2894 | 9.38k | root_struct_def_ = LookupStruct(name); |
2895 | 9.38k | if (!root_struct_def_) |
2896 | 174 | root_struct_def_ = |
2897 | 174 | LookupStruct(current_namespace_->GetFullyQualifiedName(name)); |
2898 | 9.38k | return root_struct_def_ != nullptr; |
2899 | 9.38k | } |
2900 | | |
2901 | 0 | void Parser::MarkGenerated() { |
2902 | | // This function marks all existing definitions as having already |
2903 | | // been generated, which signals no code for included files should be |
2904 | | // generated. |
2905 | 0 | for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { |
2906 | 0 | (*it)->generated = true; |
2907 | 0 | } |
2908 | 0 | for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) { |
2909 | 0 | if (!(*it)->predecl) { (*it)->generated = true; } |
2910 | 0 | } |
2911 | 0 | for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) { |
2912 | 0 | (*it)->generated = true; |
2913 | 0 | } |
2914 | 0 | } |
2915 | | |
2916 | 5.82k | CheckedError Parser::ParseNamespace() { |
2917 | 5.82k | NEXT(); |
2918 | 5.82k | auto ns = new Namespace(); |
2919 | 5.82k | namespaces_.push_back(ns); // Store it here to not leak upon error. |
2920 | 5.82k | if (token_ != ';') { |
2921 | 42.3k | for (;;) { |
2922 | 42.3k | ns->components.push_back(attribute_); |
2923 | 42.3k | EXPECT(kTokenIdentifier); |
2924 | 42.2k | if (Is('.')) NEXT() else break; |
2925 | 42.2k | } |
2926 | 5.50k | } |
2927 | 5.76k | namespaces_.pop_back(); |
2928 | 5.76k | current_namespace_ = UniqueNamespace(ns); |
2929 | 5.76k | EXPECT(';'); |
2930 | 5.64k | return NoError(); |
2931 | 5.76k | } |
2932 | | |
2933 | | // Best effort parsing of .proto declarations, with the aim to turn them |
2934 | | // in the closest corresponding FlatBuffer equivalent. |
2935 | | // We parse everything as identifiers instead of keywords, since we don't |
2936 | | // want protobuf keywords to become invalid identifiers in FlatBuffers. |
2937 | 0 | CheckedError Parser::ParseProtoDecl() { |
2938 | 0 | bool isextend = IsIdent("extend"); |
2939 | 0 | if (IsIdent("package")) { |
2940 | | // These are identical in syntax to FlatBuffer's namespace decl. |
2941 | 0 | ECHECK(ParseNamespace()); |
2942 | 0 | } else if (IsIdent("message") || isextend) { |
2943 | 0 | std::vector<std::string> struct_comment = doc_comment_; |
2944 | 0 | NEXT(); |
2945 | 0 | StructDef *struct_def = nullptr; |
2946 | 0 | Namespace *parent_namespace = nullptr; |
2947 | 0 | if (isextend) { |
2948 | 0 | if (Is('.')) NEXT(); // qualified names may start with a . ? |
2949 | 0 | auto id = attribute_; |
2950 | 0 | EXPECT(kTokenIdentifier); |
2951 | 0 | ECHECK(ParseNamespacing(&id, nullptr)); |
2952 | 0 | struct_def = LookupCreateStruct(id, false); |
2953 | 0 | if (!struct_def) |
2954 | 0 | return Error("cannot extend unknown message type: " + id); |
2955 | 0 | } else { |
2956 | 0 | std::string name = attribute_; |
2957 | 0 | EXPECT(kTokenIdentifier); |
2958 | 0 | ECHECK(StartStruct(name, &struct_def)); |
2959 | | // Since message definitions can be nested, we create a new namespace. |
2960 | 0 | auto ns = new Namespace(); |
2961 | | // Copy of current namespace. |
2962 | 0 | *ns = *current_namespace_; |
2963 | | // But with current message name. |
2964 | 0 | ns->components.push_back(name); |
2965 | 0 | ns->from_table++; |
2966 | 0 | parent_namespace = current_namespace_; |
2967 | 0 | current_namespace_ = UniqueNamespace(ns); |
2968 | 0 | } |
2969 | 0 | struct_def->doc_comment = struct_comment; |
2970 | 0 | ECHECK(ParseProtoFields(struct_def, isextend, false)); |
2971 | 0 | if (!isextend) { current_namespace_ = parent_namespace; } |
2972 | 0 | if (Is(';')) NEXT(); |
2973 | 0 | } else if (IsIdent("enum")) { |
2974 | | // These are almost the same, just with different terminator: |
2975 | 0 | EnumDef *enum_def; |
2976 | 0 | ECHECK(ParseEnum(false, &enum_def, nullptr)); |
2977 | 0 | if (Is(';')) NEXT(); |
2978 | | // Temp: remove any duplicates, as .fbs files can't handle them. |
2979 | 0 | enum_def->RemoveDuplicates(); |
2980 | 0 | } else if (IsIdent("syntax")) { // Skip these. |
2981 | 0 | NEXT(); |
2982 | 0 | EXPECT('='); |
2983 | 0 | EXPECT(kTokenStringConstant); |
2984 | 0 | EXPECT(';'); |
2985 | 0 | } else if (IsIdent("option")) { // Skip these. |
2986 | 0 | ECHECK(ParseProtoOption()); |
2987 | 0 | EXPECT(';'); |
2988 | 0 | } else if (IsIdent("service")) { // Skip these. |
2989 | 0 | NEXT(); |
2990 | 0 | EXPECT(kTokenIdentifier); |
2991 | 0 | ECHECK(ParseProtoCurliesOrIdent()); |
2992 | 0 | } else { |
2993 | 0 | return Error("don\'t know how to parse .proto declaration starting with " + |
2994 | 0 | TokenToStringId(token_)); |
2995 | 0 | } |
2996 | 0 | return NoError(); |
2997 | 0 | } |
2998 | | |
2999 | | CheckedError Parser::StartEnum(const std::string &name, bool is_union, |
3000 | 33.1k | EnumDef **dest) { |
3001 | 33.1k | auto &enum_def = *new EnumDef(); |
3002 | 33.1k | enum_def.name = name; |
3003 | 33.1k | enum_def.file = file_being_parsed_; |
3004 | 33.1k | enum_def.doc_comment = doc_comment_; |
3005 | 33.1k | enum_def.is_union = is_union; |
3006 | 33.1k | enum_def.defined_namespace = current_namespace_; |
3007 | 33.1k | const auto qualified_name = current_namespace_->GetFullyQualifiedName(name); |
3008 | 33.1k | if (enums_.Add(qualified_name, &enum_def)) |
3009 | 55 | return Error("enum already exists: " + qualified_name); |
3010 | 33.0k | enum_def.underlying_type.base_type = |
3011 | 33.0k | is_union ? BASE_TYPE_UTYPE : BASE_TYPE_INT; |
3012 | 33.0k | enum_def.underlying_type.enum_def = &enum_def; |
3013 | 33.0k | if (dest) *dest = &enum_def; |
3014 | 33.0k | return NoError(); |
3015 | 33.1k | } |
3016 | | |
3017 | | CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend, |
3018 | 0 | bool inside_oneof) { |
3019 | 0 | EXPECT('{'); |
3020 | 0 | while (token_ != '}') { |
3021 | 0 | if (IsIdent("message") || IsIdent("extend") || IsIdent("enum")) { |
3022 | | // Nested declarations. |
3023 | 0 | ECHECK(ParseProtoDecl()); |
3024 | 0 | } else if (IsIdent("extensions")) { // Skip these. |
3025 | 0 | NEXT(); |
3026 | 0 | EXPECT(kTokenIntegerConstant); |
3027 | 0 | if (Is(kTokenIdentifier)) { |
3028 | 0 | NEXT(); // to |
3029 | 0 | NEXT(); // num |
3030 | 0 | } |
3031 | 0 | EXPECT(';'); |
3032 | 0 | } else if (IsIdent("option")) { // Skip these. |
3033 | 0 | ECHECK(ParseProtoOption()); |
3034 | 0 | EXPECT(';'); |
3035 | 0 | } else if (IsIdent("reserved")) { // Skip these. |
3036 | | /** |
3037 | | * Reserved proto ids can be comma seperated (e.g. 1,2,4,5;) |
3038 | | * or range based (e.g. 9 to 11;) |
3039 | | * or combination of them (e.g. 1,2,9 to 11,4,5;) |
3040 | | * It will be ended by a semicolon. |
3041 | | */ |
3042 | 0 | NEXT(); |
3043 | 0 | bool range = false; |
3044 | 0 | voffset_t from = 0; |
3045 | |
|
3046 | 0 | while (!Is(';')) { |
3047 | 0 | if (token_ == kTokenIntegerConstant) { |
3048 | 0 | voffset_t attribute = 0; |
3049 | 0 | bool done = StringToNumber(attribute_.c_str(), &attribute); |
3050 | 0 | if (!done) |
3051 | 0 | return Error("Protobuf has non positive number in reserved ids"); |
3052 | | |
3053 | 0 | if (range) { |
3054 | 0 | for (voffset_t id = from + 1; id <= attribute; id++) |
3055 | 0 | struct_def->reserved_ids.push_back(id); |
3056 | |
|
3057 | 0 | range = false; |
3058 | 0 | } else { |
3059 | 0 | struct_def->reserved_ids.push_back(attribute); |
3060 | 0 | } |
3061 | |
|
3062 | 0 | from = attribute; |
3063 | 0 | } |
3064 | | |
3065 | 0 | if (attribute_ == "to") range = true; |
3066 | |
|
3067 | 0 | NEXT(); |
3068 | 0 | } // A variety of formats, just skip. |
3069 | | |
3070 | 0 | NEXT(); |
3071 | 0 | } else if (IsIdent("map")) { |
3072 | 0 | ECHECK(ParseProtoMapField(struct_def)); |
3073 | 0 | } else { |
3074 | 0 | std::vector<std::string> field_comment = doc_comment_; |
3075 | | // Parse the qualifier. |
3076 | 0 | bool required = false; |
3077 | 0 | bool repeated = false; |
3078 | 0 | bool oneof = false; |
3079 | 0 | if (!inside_oneof) { |
3080 | 0 | if (IsIdent("optional")) { |
3081 | | // This is the default. |
3082 | 0 | NEXT(); |
3083 | 0 | } else if (IsIdent("required")) { |
3084 | 0 | required = true; |
3085 | 0 | NEXT(); |
3086 | 0 | } else if (IsIdent("repeated")) { |
3087 | 0 | repeated = true; |
3088 | 0 | NEXT(); |
3089 | 0 | } else if (IsIdent("oneof")) { |
3090 | 0 | oneof = true; |
3091 | 0 | NEXT(); |
3092 | 0 | } else { |
3093 | | // can't error, proto3 allows decls without any of the above. |
3094 | 0 | } |
3095 | 0 | } |
3096 | 0 | StructDef *anonymous_struct = nullptr; |
3097 | 0 | EnumDef *oneof_union = nullptr; |
3098 | 0 | Type type; |
3099 | 0 | if (IsIdent("group") || oneof) { |
3100 | 0 | if (!oneof) NEXT(); |
3101 | 0 | if (oneof && opts.proto_oneof_union) { |
3102 | 0 | auto name = ConvertCase(attribute_, Case::kUpperCamel) + "Union"; |
3103 | 0 | ECHECK(StartEnum(name, true, &oneof_union)); |
3104 | 0 | type = Type(BASE_TYPE_UNION, nullptr, oneof_union); |
3105 | 0 | } else { |
3106 | 0 | auto name = "Anonymous" + NumToString(anonymous_counter_++); |
3107 | 0 | ECHECK(StartStruct(name, &anonymous_struct)); |
3108 | 0 | type = Type(BASE_TYPE_STRUCT, anonymous_struct); |
3109 | 0 | } |
3110 | 0 | } else { |
3111 | 0 | ECHECK(ParseTypeFromProtoType(&type)); |
3112 | 0 | } |
3113 | | // Repeated elements get mapped to a vector. |
3114 | 0 | if (repeated) { |
3115 | 0 | type.element = type.base_type; |
3116 | 0 | type.base_type = BASE_TYPE_VECTOR; |
3117 | 0 | if (type.element == BASE_TYPE_VECTOR) { |
3118 | | // We have a vector or vectors, which FlatBuffers doesn't support. |
3119 | | // For now make it a vector of string (since the source is likely |
3120 | | // "repeated bytes"). |
3121 | | // TODO(wvo): A better solution would be to wrap this in a table. |
3122 | 0 | type.element = BASE_TYPE_STRING; |
3123 | 0 | } |
3124 | 0 | } |
3125 | 0 | std::string name = attribute_; |
3126 | 0 | EXPECT(kTokenIdentifier); |
3127 | 0 | std::string proto_field_id; |
3128 | 0 | if (!oneof) { |
3129 | | // Parse the field id. Since we're just translating schemas, not |
3130 | | // any kind of binary compatibility, we can safely ignore these, and |
3131 | | // assign our own. |
3132 | 0 | EXPECT('='); |
3133 | 0 | proto_field_id = attribute_; |
3134 | 0 | EXPECT(kTokenIntegerConstant); |
3135 | 0 | } |
3136 | 0 | FieldDef *field = nullptr; |
3137 | 0 | if (isextend) { |
3138 | | // We allow a field to be re-defined when extending. |
3139 | | // TODO: are there situations where that is problematic? |
3140 | 0 | field = struct_def->fields.Lookup(name); |
3141 | 0 | } |
3142 | 0 | if (!field) ECHECK(AddField(*struct_def, name, type, &field)); |
3143 | 0 | field->doc_comment = field_comment; |
3144 | 0 | if (!proto_field_id.empty() || oneof) { |
3145 | 0 | auto val = new Value(); |
3146 | 0 | val->constant = proto_field_id; |
3147 | 0 | field->attributes.Add("id", val); |
3148 | 0 | } |
3149 | 0 | if (!IsScalar(type.base_type) && required) { |
3150 | 0 | field->presence = FieldDef::kRequired; |
3151 | 0 | } |
3152 | | // See if there's a default specified. |
3153 | 0 | if (Is('[')) { |
3154 | 0 | NEXT(); |
3155 | 0 | for (;;) { |
3156 | 0 | auto key = attribute_; |
3157 | 0 | ECHECK(ParseProtoKey()); |
3158 | 0 | EXPECT('='); |
3159 | 0 | auto val = attribute_; |
3160 | 0 | ECHECK(ParseProtoCurliesOrIdent()); |
3161 | 0 | if (key == "default") { |
3162 | | // Temp: skip non-numeric and non-boolean defaults (enums). |
3163 | 0 | auto numeric = strpbrk(val.c_str(), "0123456789-+."); |
3164 | 0 | if (IsFloat(type.base_type) && |
3165 | 0 | (val == "inf" || val == "+inf" || val == "-inf")) { |
3166 | | // Prefer to be explicit with +inf. |
3167 | 0 | field->value.constant = val == "inf" ? "+inf" : val; |
3168 | 0 | } else if (IsScalar(type.base_type) && numeric == val.c_str()) { |
3169 | 0 | field->value.constant = val; |
3170 | 0 | } else if (val == "true") { |
3171 | 0 | field->value.constant = val; |
3172 | 0 | } // "false" is default, no need to handle explicitly. |
3173 | 0 | } else if (key == "deprecated") { |
3174 | 0 | field->deprecated = val == "true"; |
3175 | 0 | } |
3176 | 0 | if (!Is(',')) break; |
3177 | 0 | NEXT(); |
3178 | 0 | } |
3179 | 0 | EXPECT(']'); |
3180 | 0 | } |
3181 | 0 | if (anonymous_struct) { |
3182 | 0 | ECHECK(ParseProtoFields(anonymous_struct, false, oneof)); |
3183 | 0 | if (Is(';')) NEXT(); |
3184 | 0 | } else if (oneof_union) { |
3185 | | // Parse into a temporary StructDef, then transfer fields into an |
3186 | | // EnumDef describing the oneof as a union. |
3187 | 0 | StructDef oneof_struct; |
3188 | 0 | ECHECK(ParseProtoFields(&oneof_struct, false, oneof)); |
3189 | 0 | if (Is(';')) NEXT(); |
3190 | 0 | for (auto field_it = oneof_struct.fields.vec.begin(); |
3191 | 0 | field_it != oneof_struct.fields.vec.end(); ++field_it) { |
3192 | 0 | const auto &oneof_field = **field_it; |
3193 | 0 | const auto &oneof_type = oneof_field.value.type; |
3194 | 0 | if (oneof_type.base_type != BASE_TYPE_STRUCT || |
3195 | 0 | !oneof_type.struct_def || oneof_type.struct_def->fixed) |
3196 | 0 | return Error("oneof '" + name + |
3197 | 0 | "' cannot be mapped to a union because member '" + |
3198 | 0 | oneof_field.name + "' is not a table type."); |
3199 | 0 | EnumValBuilder evb(*this, *oneof_union); |
3200 | 0 | auto ev = evb.CreateEnumerator(oneof_type.struct_def->name); |
3201 | 0 | ev->union_type = oneof_type; |
3202 | 0 | ev->doc_comment = oneof_field.doc_comment; |
3203 | 0 | ECHECK(evb.AcceptEnumerator(oneof_field.name)); |
3204 | 0 | } |
3205 | 0 | } else { |
3206 | 0 | EXPECT(';'); |
3207 | 0 | } |
3208 | 0 | } |
3209 | 0 | } |
3210 | 0 | NEXT(); |
3211 | 0 | return NoError(); |
3212 | 0 | } |
3213 | | |
3214 | 0 | CheckedError Parser::ParseProtoMapField(StructDef *struct_def) { |
3215 | 0 | NEXT(); |
3216 | 0 | EXPECT('<'); |
3217 | 0 | Type key_type; |
3218 | 0 | ECHECK(ParseType(key_type)); |
3219 | 0 | EXPECT(','); |
3220 | 0 | Type value_type; |
3221 | 0 | ECHECK(ParseType(value_type)); |
3222 | 0 | EXPECT('>'); |
3223 | 0 | auto field_name = attribute_; |
3224 | 0 | NEXT(); |
3225 | 0 | EXPECT('='); |
3226 | 0 | std::string proto_field_id = attribute_; |
3227 | 0 | EXPECT(kTokenIntegerConstant); |
3228 | 0 | EXPECT(';'); |
3229 | |
|
3230 | 0 | auto entry_table_name = ConvertCase(field_name, Case::kUpperCamel) + "Entry"; |
3231 | 0 | StructDef *entry_table; |
3232 | 0 | ECHECK(StartStruct(entry_table_name, &entry_table)); |
3233 | 0 | entry_table->has_key = true; |
3234 | 0 | FieldDef *key_field; |
3235 | 0 | ECHECK(AddField(*entry_table, "key", key_type, &key_field)); |
3236 | 0 | key_field->key = true; |
3237 | 0 | FieldDef *value_field; |
3238 | 0 | ECHECK(AddField(*entry_table, "value", value_type, &value_field)); |
3239 | |
|
3240 | 0 | Type field_type; |
3241 | 0 | field_type.base_type = BASE_TYPE_VECTOR; |
3242 | 0 | field_type.element = BASE_TYPE_STRUCT; |
3243 | 0 | field_type.struct_def = entry_table; |
3244 | 0 | FieldDef *field; |
3245 | 0 | ECHECK(AddField(*struct_def, field_name, field_type, &field)); |
3246 | 0 | if (!proto_field_id.empty()) { |
3247 | 0 | auto val = new Value(); |
3248 | 0 | val->constant = proto_field_id; |
3249 | 0 | field->attributes.Add("id", val); |
3250 | 0 | } |
3251 | |
|
3252 | 0 | return NoError(); |
3253 | 0 | } |
3254 | | |
3255 | 0 | CheckedError Parser::ParseProtoKey() { |
3256 | 0 | if (token_ == '(') { |
3257 | 0 | NEXT(); |
3258 | | // Skip "(a.b)" style custom attributes. |
3259 | 0 | while (token_ == '.' || token_ == kTokenIdentifier) NEXT(); |
3260 | 0 | EXPECT(')'); |
3261 | 0 | while (Is('.')) { |
3262 | 0 | NEXT(); |
3263 | 0 | EXPECT(kTokenIdentifier); |
3264 | 0 | } |
3265 | 0 | } else { |
3266 | 0 | EXPECT(kTokenIdentifier); |
3267 | 0 | } |
3268 | 0 | return NoError(); |
3269 | 0 | } |
3270 | | |
3271 | 0 | CheckedError Parser::ParseProtoCurliesOrIdent() { |
3272 | 0 | if (Is('{')) { |
3273 | 0 | NEXT(); |
3274 | 0 | for (int nesting = 1; nesting;) { |
3275 | 0 | if (token_ == '{') |
3276 | 0 | nesting++; |
3277 | 0 | else if (token_ == '}') |
3278 | 0 | nesting--; |
3279 | 0 | NEXT(); |
3280 | 0 | } |
3281 | 0 | } else { |
3282 | 0 | NEXT(); // Any single token. |
3283 | 0 | } |
3284 | 0 | return NoError(); |
3285 | 0 | } |
3286 | | |
3287 | 0 | CheckedError Parser::ParseProtoOption() { |
3288 | 0 | NEXT(); |
3289 | 0 | ECHECK(ParseProtoKey()); |
3290 | 0 | EXPECT('='); |
3291 | 0 | ECHECK(ParseProtoCurliesOrIdent()); |
3292 | 0 | return NoError(); |
3293 | 0 | } |
3294 | | |
3295 | | // Parse a protobuf type, and map it to the corresponding FlatBuffer one. |
3296 | 0 | CheckedError Parser::ParseTypeFromProtoType(Type *type) { |
3297 | 0 | struct type_lookup { |
3298 | 0 | const char *proto_type; |
3299 | 0 | BaseType fb_type, element; |
3300 | 0 | }; |
3301 | 0 | static type_lookup lookup[] = { |
3302 | 0 | { "float", BASE_TYPE_FLOAT, BASE_TYPE_NONE }, |
3303 | 0 | { "double", BASE_TYPE_DOUBLE, BASE_TYPE_NONE }, |
3304 | 0 | { "int32", BASE_TYPE_INT, BASE_TYPE_NONE }, |
3305 | 0 | { "int64", BASE_TYPE_LONG, BASE_TYPE_NONE }, |
3306 | 0 | { "uint32", BASE_TYPE_UINT, BASE_TYPE_NONE }, |
3307 | 0 | { "uint64", BASE_TYPE_ULONG, BASE_TYPE_NONE }, |
3308 | 0 | { "sint32", BASE_TYPE_INT, BASE_TYPE_NONE }, |
3309 | 0 | { "sint64", BASE_TYPE_LONG, BASE_TYPE_NONE }, |
3310 | 0 | { "fixed32", BASE_TYPE_UINT, BASE_TYPE_NONE }, |
3311 | 0 | { "fixed64", BASE_TYPE_ULONG, BASE_TYPE_NONE }, |
3312 | 0 | { "sfixed32", BASE_TYPE_INT, BASE_TYPE_NONE }, |
3313 | 0 | { "sfixed64", BASE_TYPE_LONG, BASE_TYPE_NONE }, |
3314 | 0 | { "bool", BASE_TYPE_BOOL, BASE_TYPE_NONE }, |
3315 | 0 | { "string", BASE_TYPE_STRING, BASE_TYPE_NONE }, |
3316 | 0 | { "bytes", BASE_TYPE_VECTOR, BASE_TYPE_UCHAR }, |
3317 | 0 | { nullptr, BASE_TYPE_NONE, BASE_TYPE_NONE } |
3318 | 0 | }; |
3319 | 0 | for (auto tl = lookup; tl->proto_type; tl++) { |
3320 | 0 | if (attribute_ == tl->proto_type) { |
3321 | 0 | type->base_type = tl->fb_type; |
3322 | 0 | type->element = tl->element; |
3323 | 0 | NEXT(); |
3324 | 0 | return NoError(); |
3325 | 0 | } |
3326 | 0 | } |
3327 | 0 | if (Is('.')) NEXT(); // qualified names may start with a . ? |
3328 | 0 | ECHECK(ParseTypeIdent(*type)); |
3329 | 0 | return NoError(); |
3330 | 0 | } |
3331 | | |
3332 | 8.55k | CheckedError Parser::SkipAnyJsonValue() { |
3333 | 8.55k | ParseDepthGuard depth_guard(this); |
3334 | 8.55k | ECHECK(depth_guard.Check()); |
3335 | | |
3336 | 8.55k | switch (token_) { |
3337 | 883 | case '{': { |
3338 | 883 | size_t fieldn_outer = 0; |
3339 | 883 | return ParseTableDelimiters(fieldn_outer, nullptr, |
3340 | 883 | [&](const std::string &, size_t &fieldn, |
3341 | 1.17k | const StructDef *) -> CheckedError { |
3342 | 1.17k | ECHECK(SkipAnyJsonValue()); |
3343 | 1.07k | fieldn++; |
3344 | 1.07k | return NoError(); |
3345 | 1.17k | }); |
3346 | 0 | } |
3347 | 1.45k | case '[': { |
3348 | 1.45k | size_t count = 0; |
3349 | 1.45k | return ParseVectorDelimiters( |
3350 | 4.90k | count, [&](size_t &) -> CheckedError { return SkipAnyJsonValue(); }); |
3351 | 0 | } |
3352 | 508 | case kTokenStringConstant: |
3353 | 4.45k | case kTokenIntegerConstant: |
3354 | 5.33k | case kTokenFloatConstant: NEXT(); break; |
3355 | 886 | default: |
3356 | 886 | if (IsIdent("true") || IsIdent("false") || IsIdent("null") || |
3357 | 886 | IsIdent("inf")) { |
3358 | 799 | NEXT(); |
3359 | 798 | } else |
3360 | 87 | return TokenError(); |
3361 | 8.55k | } |
3362 | 6.12k | return NoError(); |
3363 | 8.55k | } |
3364 | | |
3365 | | CheckedError Parser::ParseFlexBufferNumericConstant( |
3366 | 3.24k | flexbuffers::Builder *builder) { |
3367 | 3.24k | double d; |
3368 | 3.24k | if (!StringToNumber(attribute_.c_str(), &d)) |
3369 | 13 | return Error("unexpected floating-point constant: " + attribute_); |
3370 | 3.23k | builder->Double(d); |
3371 | 3.23k | return NoError(); |
3372 | 3.24k | } |
3373 | | |
3374 | 403k | CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) { |
3375 | 403k | ParseDepthGuard depth_guard(this); |
3376 | 403k | ECHECK(depth_guard.Check()); |
3377 | | |
3378 | 403k | switch (token_) { |
3379 | 43.0k | case '{': { |
3380 | 43.0k | auto start = builder->StartMap(); |
3381 | 43.0k | size_t fieldn_outer = 0; |
3382 | 43.0k | auto err = |
3383 | 43.0k | ParseTableDelimiters(fieldn_outer, nullptr, |
3384 | 43.0k | [&](const std::string &name, size_t &fieldn, |
3385 | 263k | const StructDef *) -> CheckedError { |
3386 | 263k | builder->Key(name); |
3387 | 263k | ECHECK(ParseFlexBufferValue(builder)); |
3388 | 262k | fieldn++; |
3389 | 262k | return NoError(); |
3390 | 263k | }); |
3391 | 43.0k | ECHECK(err); |
3392 | 41.9k | builder->EndMap(start); |
3393 | 41.9k | if (builder->HasDuplicateKeys()) |
3394 | 1.90k | return Error("FlexBuffers map has duplicate keys"); |
3395 | 40.0k | break; |
3396 | 41.9k | } |
3397 | 40.0k | case '[': { |
3398 | 7.08k | auto start = builder->StartVector(); |
3399 | 7.08k | size_t count = 0; |
3400 | 7.08k | ECHECK(ParseVectorDelimiters(count, [&](size_t &) -> CheckedError { |
3401 | 7.08k | return ParseFlexBufferValue(builder); |
3402 | 7.08k | })); |
3403 | 6.18k | builder->EndVector(start, false, false); |
3404 | 6.18k | break; |
3405 | 7.08k | } |
3406 | 5.61k | case kTokenStringConstant: |
3407 | 5.61k | builder->String(attribute_); |
3408 | 5.61k | EXPECT(kTokenStringConstant); |
3409 | 5.58k | break; |
3410 | 307k | case kTokenIntegerConstant: |
3411 | 307k | builder->Int(StringToInt(attribute_.c_str())); |
3412 | 307k | EXPECT(kTokenIntegerConstant); |
3413 | 307k | break; |
3414 | 35.0k | case kTokenFloatConstant: { |
3415 | 35.0k | double d; |
3416 | 35.0k | StringToNumber(attribute_.c_str(), &d); |
3417 | 35.0k | builder->Double(d); |
3418 | 35.0k | EXPECT(kTokenFloatConstant); |
3419 | 35.0k | break; |
3420 | 35.0k | } |
3421 | 327 | case '-': |
3422 | 844 | case '+': { |
3423 | | // `[-+]?(nan|inf|infinity)`, see ParseSingleValue(). |
3424 | 844 | const auto sign = static_cast<char>(token_); |
3425 | 844 | NEXT(); |
3426 | 844 | if (token_ != kTokenIdentifier) |
3427 | 0 | return Error("floating-point constant expected"); |
3428 | 844 | attribute_.insert(size_t(0), size_t(1), sign); |
3429 | 844 | ECHECK(ParseFlexBufferNumericConstant(builder)); |
3430 | 831 | NEXT(); |
3431 | 830 | break; |
3432 | 831 | } |
3433 | 4.06k | default: |
3434 | 4.06k | if (IsIdent("true")) { |
3435 | 571 | builder->Bool(true); |
3436 | 571 | NEXT(); |
3437 | 3.49k | } else if (IsIdent("false")) { |
3438 | 320 | builder->Bool(false); |
3439 | 320 | NEXT(); |
3440 | 3.17k | } else if (IsIdent("null")) { |
3441 | 583 | builder->Null(); |
3442 | 583 | NEXT(); |
3443 | 2.59k | } else if (IsIdent("inf") || IsIdent("infinity") || IsIdent("nan")) { |
3444 | 2.40k | ECHECK(ParseFlexBufferNumericConstant(builder)); |
3445 | 2.40k | NEXT(); |
3446 | 2.39k | } else |
3447 | 195 | return TokenError(); |
3448 | 403k | } |
3449 | 399k | return NoError(); |
3450 | 403k | } |
3451 | | |
3452 | | bool Parser::ParseFlexBuffer(const char *source, const char *source_filename, |
3453 | 0 | flexbuffers::Builder *builder) { |
3454 | 0 | const auto initial_depth = parse_depth_counter_; |
3455 | 0 | (void)initial_depth; |
3456 | 0 | auto ok = !StartParseFile(source, source_filename).Check() && |
3457 | 0 | !ParseFlexBufferValue(builder).Check(); |
3458 | 0 | if (ok) builder->Finish(); |
3459 | 0 | FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_); |
3460 | 0 | return ok; |
3461 | 0 | } |
3462 | | |
3463 | | bool Parser::Parse(const char *source, const char **include_paths, |
3464 | 27.3k | const char *source_filename) { |
3465 | 27.3k | const auto initial_depth = parse_depth_counter_; |
3466 | 27.3k | (void)initial_depth; |
3467 | 27.3k | bool r; |
3468 | | |
3469 | 27.3k | if (opts.use_flexbuffers) { |
3470 | 0 | r = ParseFlexBuffer(source, source_filename, &flex_builder_); |
3471 | 27.3k | } else { |
3472 | 27.3k | r = !ParseRoot(source, include_paths, source_filename).Check(); |
3473 | 27.3k | } |
3474 | 27.3k | FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_); |
3475 | 27.3k | return r; |
3476 | 27.3k | } |
3477 | | |
3478 | 0 | bool Parser::ParseJson(const char *json, const char *json_filename) { |
3479 | 0 | const auto initial_depth = parse_depth_counter_; |
3480 | 0 | (void)initial_depth; |
3481 | 0 | builder_.Clear(); |
3482 | 0 | const auto done = |
3483 | 0 | !StartParseFile(json, json_filename).Check() && !DoParseJson().Check(); |
3484 | 0 | FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_); |
3485 | 0 | return done; |
3486 | 0 | } |
3487 | | |
3488 | 0 | std::ptrdiff_t Parser::BytesConsumed() const { |
3489 | 0 | return std::distance(source_, prev_cursor_); |
3490 | 0 | } |
3491 | | |
3492 | | CheckedError Parser::StartParseFile(const char *source, |
3493 | 27.3k | const char *source_filename) { |
3494 | 27.3k | file_being_parsed_ = source_filename ? source_filename : ""; |
3495 | 27.3k | source_ = source; |
3496 | 27.3k | ResetState(source_); |
3497 | 27.3k | error_.clear(); |
3498 | 27.3k | ECHECK(SkipByteOrderMark()); |
3499 | 27.3k | NEXT(); |
3500 | 26.8k | if (Is(kTokenEof)) return Error("input file is empty"); |
3501 | 26.7k | return NoError(); |
3502 | 26.8k | } |
3503 | | |
3504 | | CheckedError Parser::ParseRoot(const char *source, const char **include_paths, |
3505 | 27.3k | const char *source_filename) { |
3506 | 27.3k | ECHECK(DoParse(source, include_paths, source_filename, nullptr)); |
3507 | | |
3508 | | // Check that all types were defined. |
3509 | 26.1k | for (auto it = structs_.vec.begin(); it != structs_.vec.end();) { |
3510 | 14.8k | auto &struct_def = **it; |
3511 | 14.8k | if (struct_def.predecl) { |
3512 | 2.63k | if (opts.proto_mode) { |
3513 | | // Protos allow enums to be used before declaration, so check if that |
3514 | | // is the case here. |
3515 | 0 | EnumDef *enum_def = nullptr; |
3516 | 0 | for (size_t components = |
3517 | 0 | struct_def.defined_namespace->components.size() + 1; |
3518 | 0 | components && !enum_def; components--) { |
3519 | 0 | auto qualified_name = |
3520 | 0 | struct_def.defined_namespace->GetFullyQualifiedName( |
3521 | 0 | struct_def.name, components - 1); |
3522 | 0 | enum_def = LookupEnum(qualified_name); |
3523 | 0 | } |
3524 | 0 | if (enum_def) { |
3525 | | // This is pretty slow, but a simple solution for now. |
3526 | 0 | auto initial_count = struct_def.refcount; |
3527 | 0 | for (auto struct_it = structs_.vec.begin(); |
3528 | 0 | struct_it != structs_.vec.end(); ++struct_it) { |
3529 | 0 | auto &sd = **struct_it; |
3530 | 0 | for (auto field_it = sd.fields.vec.begin(); |
3531 | 0 | field_it != sd.fields.vec.end(); ++field_it) { |
3532 | 0 | auto &field = **field_it; |
3533 | 0 | if (field.value.type.struct_def == &struct_def) { |
3534 | 0 | field.value.type.struct_def = nullptr; |
3535 | 0 | field.value.type.enum_def = enum_def; |
3536 | 0 | auto &bt = IsVector(field.value.type) |
3537 | 0 | ? field.value.type.element |
3538 | 0 | : field.value.type.base_type; |
3539 | 0 | FLATBUFFERS_ASSERT(bt == BASE_TYPE_STRUCT); |
3540 | 0 | bt = enum_def->underlying_type.base_type; |
3541 | 0 | struct_def.refcount--; |
3542 | 0 | enum_def->refcount++; |
3543 | 0 | } |
3544 | 0 | } |
3545 | 0 | } |
3546 | 0 | if (struct_def.refcount) |
3547 | 0 | return Error("internal: " + NumToString(struct_def.refcount) + "/" + |
3548 | 0 | NumToString(initial_count) + |
3549 | 0 | " use(s) of pre-declaration enum not accounted for: " + |
3550 | 0 | enum_def->name); |
3551 | 0 | structs_.dict.erase(structs_.dict.find(struct_def.name)); |
3552 | 0 | it = structs_.vec.erase(it); |
3553 | 0 | delete &struct_def; |
3554 | 0 | continue; // Skip error. |
3555 | 0 | } |
3556 | 0 | } |
3557 | 2.63k | auto err = "type referenced but not defined (check namespace): " + |
3558 | 2.63k | struct_def.name; |
3559 | 2.63k | if (struct_def.original_location) |
3560 | 2.63k | err += ", originally at: " + *struct_def.original_location; |
3561 | 2.63k | return Error(err); |
3562 | 2.63k | } |
3563 | 12.2k | ++it; |
3564 | 12.2k | } |
3565 | | |
3566 | | // This check has to happen here and not earlier, because only now do we |
3567 | | // know for sure what the type of these are. |
3568 | 14.3k | for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { |
3569 | 3.00k | auto &enum_def = **it; |
3570 | 3.00k | if (enum_def.is_union) { |
3571 | 677 | for (auto val_it = enum_def.Vals().begin(); |
3572 | 1.51k | val_it != enum_def.Vals().end(); ++val_it) { |
3573 | 840 | auto &val = **val_it; |
3574 | | |
3575 | 840 | if (!(opts.lang_to_generate != 0 && SupportsAdvancedUnionFeatures()) && |
3576 | 840 | (IsStruct(val.union_type) || IsString(val.union_type))) |
3577 | | |
3578 | 2 | return Error( |
3579 | 2 | "only tables can be union elements in the generated language: " + |
3580 | 2 | val.name); |
3581 | 840 | } |
3582 | 677 | } |
3583 | 3.00k | } |
3584 | | |
3585 | 11.2k | auto err = CheckPrivateLeak(); |
3586 | 11.2k | if (err.Check()) return err; |
3587 | | |
3588 | | // Parse JSON object only if the scheme has been parsed. |
3589 | 11.2k | if (token_ == '{') { ECHECK(DoParseJson()); } |
3590 | 2.33k | return NoError(); |
3591 | 11.2k | } |
3592 | | |
3593 | 11.2k | CheckedError Parser::CheckPrivateLeak() { |
3594 | 11.2k | if (!opts.no_leak_private_annotations) return NoError(); |
3595 | | // Iterate over all structs/tables to validate we arent leaking |
3596 | | // any private (structs/tables/enums) |
3597 | 0 | for (auto it = structs_.vec.begin(); it != structs_.vec.end(); it++) { |
3598 | 0 | auto &struct_def = **it; |
3599 | 0 | for (auto fld_it = struct_def.fields.vec.begin(); |
3600 | 0 | fld_it != struct_def.fields.vec.end(); ++fld_it) { |
3601 | 0 | auto &field = **fld_it; |
3602 | |
|
3603 | 0 | if (field.value.type.enum_def) { |
3604 | 0 | auto err = |
3605 | 0 | CheckPrivatelyLeakedFields(struct_def, *field.value.type.enum_def); |
3606 | 0 | if (err.Check()) { return err; } |
3607 | 0 | } else if (field.value.type.struct_def) { |
3608 | 0 | auto err = CheckPrivatelyLeakedFields(struct_def, |
3609 | 0 | *field.value.type.struct_def); |
3610 | 0 | if (err.Check()) { return err; } |
3611 | 0 | } |
3612 | 0 | } |
3613 | 0 | } |
3614 | | // Iterate over all enums to validate we arent leaking |
3615 | | // any private (structs/tables) |
3616 | 0 | for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { |
3617 | 0 | auto &enum_def = **it; |
3618 | 0 | if (enum_def.is_union) { |
3619 | 0 | for (auto val_it = enum_def.Vals().begin(); |
3620 | 0 | val_it != enum_def.Vals().end(); ++val_it) { |
3621 | 0 | auto &val = **val_it; |
3622 | 0 | if (val.union_type.struct_def) { |
3623 | 0 | auto err = |
3624 | 0 | CheckPrivatelyLeakedFields(enum_def, *val.union_type.struct_def); |
3625 | 0 | if (err.Check()) { return err; } |
3626 | 0 | } |
3627 | 0 | } |
3628 | 0 | } |
3629 | 0 | } |
3630 | 0 | return NoError(); |
3631 | 0 | } |
3632 | | |
3633 | | CheckedError Parser::CheckPrivatelyLeakedFields(const Definition &def, |
3634 | 0 | const Definition &value_type) { |
3635 | 0 | if (!opts.no_leak_private_annotations) return NoError(); |
3636 | 0 | const auto is_private = def.attributes.Lookup("private"); |
3637 | 0 | const auto is_field_private = value_type.attributes.Lookup("private"); |
3638 | 0 | if (!is_private && is_field_private) { |
3639 | 0 | return Error( |
3640 | 0 | "Leaking private implementation, verify all objects have similar " |
3641 | 0 | "annotations"); |
3642 | 0 | } |
3643 | 0 | return NoError(); |
3644 | 0 | } |
3645 | | |
3646 | | CheckedError Parser::DoParse(const char *source, const char **include_paths, |
3647 | | const char *source_filename, |
3648 | 27.3k | const char *include_filename) { |
3649 | 27.3k | uint64_t source_hash = 0; |
3650 | 27.3k | if (source_filename) { |
3651 | | // If the file is in-memory, don't include its contents in the hash as we |
3652 | | // won't be able to load them later. |
3653 | 0 | if (FileExists(source_filename)) |
3654 | 0 | source_hash = HashFile(source_filename, source); |
3655 | 0 | else |
3656 | 0 | source_hash = HashFile(source_filename, nullptr); |
3657 | |
|
3658 | 0 | if (included_files_.find(source_hash) == included_files_.end()) { |
3659 | 0 | included_files_[source_hash] = include_filename ? include_filename : ""; |
3660 | 0 | files_included_per_file_[source_filename] = std::set<IncludedFile>(); |
3661 | 0 | } else { |
3662 | 0 | return NoError(); |
3663 | 0 | } |
3664 | 0 | } |
3665 | 27.3k | if (!include_paths) { |
3666 | 27.3k | static const char *current_directory[] = { "", nullptr }; |
3667 | 27.3k | include_paths = current_directory; |
3668 | 27.3k | } |
3669 | 27.3k | field_stack_.clear(); |
3670 | 27.3k | builder_.Clear(); |
3671 | | // Start with a blank namespace just in case this file doesn't have one. |
3672 | 27.3k | current_namespace_ = empty_namespace_; |
3673 | | |
3674 | 27.3k | ECHECK(StartParseFile(source, source_filename)); |
3675 | | |
3676 | | // Includes must come before type declarations: |
3677 | 27.3k | for (;;) { |
3678 | | // Parse pre-include proto statements if any: |
3679 | 27.3k | if (opts.proto_mode && (attribute_ == "option" || attribute_ == "syntax" || |
3680 | 0 | attribute_ == "package")) { |
3681 | 0 | ECHECK(ParseProtoDecl()); |
3682 | 27.3k | } else if (IsIdent("native_include")) { |
3683 | 680 | NEXT(); |
3684 | 679 | native_included_files_.emplace_back(attribute_); |
3685 | 679 | EXPECT(kTokenStringConstant); |
3686 | 667 | EXPECT(';'); |
3687 | 26.7k | } else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) { |
3688 | 133 | NEXT(); |
3689 | 132 | if (opts.proto_mode && attribute_ == "public") NEXT(); |
3690 | 132 | auto name = flatbuffers::PosixPath(attribute_.c_str()); |
3691 | 132 | EXPECT(kTokenStringConstant); |
3692 | | // Look for the file relative to the directory of the current file. |
3693 | 101 | std::string filepath; |
3694 | 101 | if (source_filename) { |
3695 | 0 | auto source_file_directory = |
3696 | 0 | flatbuffers::StripFileName(source_filename); |
3697 | 0 | filepath = flatbuffers::ConCatPathFileName(source_file_directory, name); |
3698 | 0 | } |
3699 | 101 | if (filepath.empty() || !FileExists(filepath.c_str())) { |
3700 | | // Look for the file in include_paths. |
3701 | 195 | for (auto paths = include_paths; paths && *paths; paths++) { |
3702 | 101 | filepath = flatbuffers::ConCatPathFileName(*paths, name); |
3703 | 101 | if (FileExists(filepath.c_str())) break; |
3704 | 101 | } |
3705 | 101 | } |
3706 | 101 | if (filepath.empty()) |
3707 | 3 | return Error("unable to locate include file: " + name); |
3708 | 98 | if (source_filename) { |
3709 | 0 | IncludedFile included_file; |
3710 | 0 | included_file.filename = filepath; |
3711 | 0 | included_file.schema_name = name; |
3712 | 0 | files_included_per_file_[source_filename].insert(included_file); |
3713 | 0 | } |
3714 | | |
3715 | 98 | std::string contents; |
3716 | 98 | bool file_loaded = LoadFile(filepath.c_str(), true, &contents); |
3717 | 98 | if (included_files_.find(HashFile(filepath.c_str(), contents.c_str())) == |
3718 | 98 | included_files_.end()) { |
3719 | | // We found an include file that we have not parsed yet. |
3720 | | // Parse it. |
3721 | 98 | if (!file_loaded) return Error("unable to load include file: " + name); |
3722 | 0 | ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(), |
3723 | 0 | name.c_str())); |
3724 | | // We generally do not want to output code for any included files: |
3725 | 0 | if (!opts.generate_all) MarkGenerated(); |
3726 | | // Reset these just in case the included file had them, and the |
3727 | | // parent doesn't. |
3728 | 0 | root_struct_def_ = nullptr; |
3729 | 0 | file_identifier_.clear(); |
3730 | 0 | file_extension_.clear(); |
3731 | | // This is the easiest way to continue this file after an include: |
3732 | | // instead of saving and restoring all the state, we simply start the |
3733 | | // file anew. This will cause it to encounter the same include |
3734 | | // statement again, but this time it will skip it, because it was |
3735 | | // entered into included_files_. |
3736 | | // This is recursive, but only go as deep as the number of include |
3737 | | // statements. |
3738 | 0 | included_files_.erase(source_hash); |
3739 | 0 | return DoParse(source, include_paths, source_filename, |
3740 | 0 | include_filename); |
3741 | 0 | } |
3742 | 0 | EXPECT(';'); |
3743 | 26.5k | } else { |
3744 | 26.5k | break; |
3745 | 26.5k | } |
3746 | 27.3k | } |
3747 | | // Now parse all other kinds of declarations: |
3748 | 95.9k | while (token_ != kTokenEof) { |
3749 | 91.1k | if (opts.proto_mode) { |
3750 | 0 | ECHECK(ParseProtoDecl()); |
3751 | 91.1k | } else if (IsIdent("namespace")) { |
3752 | 5.82k | ECHECK(ParseNamespace()); |
3753 | 85.2k | } else if (token_ == '{') { |
3754 | 9.09k | return NoError(); |
3755 | 76.1k | } else if (IsIdent("enum")) { |
3756 | 15.2k | ECHECK(ParseEnum(false, nullptr, source_filename)); |
3757 | 60.9k | } else if (IsIdent("union")) { |
3758 | 17.9k | ECHECK(ParseEnum(true, nullptr, source_filename)); |
3759 | 42.9k | } else if (IsIdent("root_type")) { |
3760 | 9.39k | NEXT(); |
3761 | 9.39k | auto root_type = attribute_; |
3762 | 9.39k | EXPECT(kTokenIdentifier); |
3763 | 9.38k | ECHECK(ParseNamespacing(&root_type, nullptr)); |
3764 | 9.38k | if (opts.root_type.empty()) { |
3765 | 9.38k | if (!SetRootType(root_type.c_str())) |
3766 | 34 | return Error("unknown root type: " + root_type); |
3767 | 9.35k | if (root_struct_def_->fixed) return Error("root type must be a table"); |
3768 | 9.35k | } |
3769 | 9.35k | EXPECT(';'); |
3770 | 33.5k | } else if (IsIdent("file_identifier")) { |
3771 | 50 | NEXT(); |
3772 | 49 | file_identifier_ = attribute_; |
3773 | 49 | EXPECT(kTokenStringConstant); |
3774 | 46 | if (file_identifier_.length() != flatbuffers::kFileIdentifierLength) |
3775 | 4 | return Error("file_identifier must be exactly " + |
3776 | 4 | NumToString(flatbuffers::kFileIdentifierLength) + |
3777 | 4 | " characters"); |
3778 | 42 | EXPECT(';'); |
3779 | 33.5k | } else if (IsIdent("file_extension")) { |
3780 | 201 | NEXT(); |
3781 | 199 | file_extension_ = attribute_; |
3782 | 199 | EXPECT(kTokenStringConstant); |
3783 | 195 | EXPECT(';'); |
3784 | 33.3k | } else if (IsIdent("include")) { |
3785 | 1 | return Error("includes must come before declarations"); |
3786 | 33.3k | } else if (IsIdent("attribute")) { |
3787 | 5.66k | NEXT(); |
3788 | 5.66k | auto name = attribute_; |
3789 | 5.66k | if (Is(kTokenIdentifier)) { |
3790 | 4.94k | NEXT(); |
3791 | 4.94k | } else { |
3792 | 722 | EXPECT(kTokenStringConstant); |
3793 | 709 | } |
3794 | 5.64k | EXPECT(';'); |
3795 | 5.63k | known_attributes_[name] = false; |
3796 | 27.6k | } else if (IsIdent("rpc_service")) { |
3797 | 2.10k | ECHECK(ParseService(source_filename)); |
3798 | 25.5k | } else { |
3799 | 25.5k | ECHECK(ParseDecl(source_filename)); |
3800 | 19.7k | } |
3801 | 91.1k | } |
3802 | 4.83k | EXPECT(kTokenEof); |
3803 | 4.83k | if (opts.warnings_as_errors && has_warning_) { |
3804 | 0 | return Error("treating warnings as errors, failed due to above warnings"); |
3805 | 0 | } |
3806 | 4.83k | return NoError(); |
3807 | 4.83k | } |
3808 | | |
3809 | 9.08k | CheckedError Parser::DoParseJson() { |
3810 | 9.08k | if (token_ != '{') { |
3811 | 0 | EXPECT('{'); |
3812 | 9.08k | } else { |
3813 | 9.08k | if (!root_struct_def_) return Error("no root type set to parse json with"); |
3814 | 9.06k | if (builder_.GetSize()) { |
3815 | 0 | return Error("cannot have more than one json object in a file"); |
3816 | 0 | } |
3817 | 9.06k | uoffset_t toff; |
3818 | 9.06k | ECHECK(ParseTable(*root_struct_def_, nullptr, &toff)); |
3819 | 185 | if (opts.size_prefixed) { |
3820 | 0 | builder_.FinishSizePrefixed( |
3821 | 0 | Offset<Table>(toff), |
3822 | 0 | file_identifier_.length() ? file_identifier_.c_str() : nullptr); |
3823 | 185 | } else { |
3824 | 185 | builder_.Finish(Offset<Table>(toff), file_identifier_.length() |
3825 | 185 | ? file_identifier_.c_str() |
3826 | 185 | : nullptr); |
3827 | 185 | } |
3828 | 185 | } |
3829 | 185 | if (opts.require_json_eof) { |
3830 | | // Check that JSON file doesn't contain more objects or IDL directives. |
3831 | | // Comments after JSON are allowed. |
3832 | 185 | EXPECT(kTokenEof); |
3833 | 121 | } |
3834 | 121 | return NoError(); |
3835 | 185 | } |
3836 | | |
3837 | | std::set<std::string> Parser::GetIncludedFilesRecursive( |
3838 | 0 | const std::string &file_name) const { |
3839 | 0 | std::set<std::string> included_files; |
3840 | 0 | std::list<std::string> to_process; |
3841 | |
|
3842 | 0 | if (file_name.empty()) return included_files; |
3843 | 0 | to_process.push_back(file_name); |
3844 | |
|
3845 | 0 | while (!to_process.empty()) { |
3846 | 0 | std::string current = to_process.front(); |
3847 | 0 | to_process.pop_front(); |
3848 | 0 | included_files.insert(current); |
3849 | | |
3850 | | // Workaround the lack of const accessor in C++98 maps. |
3851 | 0 | auto &new_files = |
3852 | 0 | (*const_cast<std::map<std::string, std::set<IncludedFile>> *>( |
3853 | 0 | &files_included_per_file_))[current]; |
3854 | 0 | for (auto it = new_files.begin(); it != new_files.end(); ++it) { |
3855 | 0 | if (included_files.find(it->filename) == included_files.end()) |
3856 | 0 | to_process.push_back(it->filename); |
3857 | 0 | } |
3858 | 0 | } |
3859 | |
|
3860 | 0 | return included_files; |
3861 | 0 | } |
3862 | | |
3863 | | // Schema serialization functionality: |
3864 | | |
3865 | | static flatbuffers::Offset< |
3866 | | flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> |
3867 | | SerializeAttributesCommon(const SymbolTable<Value> &attributes, |
3868 | 0 | FlatBufferBuilder *builder, const Parser &parser) { |
3869 | 0 | std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs; |
3870 | 0 | for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) { |
3871 | 0 | auto it = parser.known_attributes_.find(kv->first); |
3872 | 0 | FLATBUFFERS_ASSERT(it != parser.known_attributes_.end()); |
3873 | 0 | if (parser.opts.binary_schema_builtins || !it->second) { |
3874 | 0 | auto key = builder->CreateString(kv->first); |
3875 | 0 | auto val = builder->CreateString(kv->second->constant); |
3876 | 0 | attrs.push_back(reflection::CreateKeyValue(*builder, key, val)); |
3877 | 0 | } |
3878 | 0 | } |
3879 | 0 | if (attrs.size()) { |
3880 | 0 | return builder->CreateVectorOfSortedTables(&attrs); |
3881 | 0 | } else { |
3882 | 0 | return 0; |
3883 | 0 | } |
3884 | 0 | } |
3885 | | |
3886 | | static bool DeserializeAttributesCommon( |
3887 | | SymbolTable<Value> &attributes, Parser &parser, |
3888 | 0 | const Vector<Offset<reflection::KeyValue>> *attrs) { |
3889 | 0 | if (attrs == nullptr) return true; |
3890 | 0 | for (uoffset_t i = 0; i < attrs->size(); ++i) { |
3891 | 0 | auto kv = attrs->Get(i); |
3892 | 0 | auto value = new Value(); |
3893 | 0 | if (kv->value()) { value->constant = kv->value()->str(); } |
3894 | 0 | if (attributes.Add(kv->key()->str(), value)) { |
3895 | 0 | delete value; |
3896 | 0 | return false; |
3897 | 0 | } |
3898 | 0 | parser.known_attributes_[kv->key()->str()]; |
3899 | 0 | } |
3900 | 0 | return true; |
3901 | 0 | } |
3902 | | |
3903 | 0 | void Parser::Serialize() { |
3904 | 0 | builder_.Clear(); |
3905 | 0 | AssignIndices(structs_.vec); |
3906 | 0 | AssignIndices(enums_.vec); |
3907 | 0 | std::vector<Offset<reflection::Object>> object_offsets; |
3908 | 0 | std::set<std::string> files; |
3909 | 0 | for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) { |
3910 | 0 | auto offset = (*it)->Serialize(&builder_, *this); |
3911 | 0 | object_offsets.push_back(offset); |
3912 | 0 | (*it)->serialized_location = offset.o; |
3913 | 0 | const std::string *file = (*it)->declaration_file; |
3914 | 0 | if (file) files.insert(*file); |
3915 | 0 | } |
3916 | 0 | std::vector<Offset<reflection::Enum>> enum_offsets; |
3917 | 0 | for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { |
3918 | 0 | auto offset = (*it)->Serialize(&builder_, *this); |
3919 | 0 | enum_offsets.push_back(offset); |
3920 | 0 | const std::string *file = (*it)->declaration_file; |
3921 | 0 | if (file) files.insert(*file); |
3922 | 0 | } |
3923 | 0 | std::vector<Offset<reflection::Service>> service_offsets; |
3924 | 0 | for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) { |
3925 | 0 | auto offset = (*it)->Serialize(&builder_, *this); |
3926 | 0 | service_offsets.push_back(offset); |
3927 | 0 | const std::string *file = (*it)->declaration_file; |
3928 | 0 | if (file) files.insert(*file); |
3929 | 0 | } |
3930 | | |
3931 | | // Create Schemafiles vector of tables. |
3932 | 0 | flatbuffers::Offset< |
3933 | 0 | flatbuffers::Vector<flatbuffers::Offset<reflection::SchemaFile>>> |
3934 | 0 | schema_files__; |
3935 | 0 | if (!opts.project_root.empty()) { |
3936 | 0 | std::vector<Offset<reflection::SchemaFile>> schema_files; |
3937 | 0 | std::vector<Offset<flatbuffers::String>> included_files; |
3938 | 0 | for (auto f = files_included_per_file_.begin(); |
3939 | 0 | f != files_included_per_file_.end(); f++) { |
3940 | |
|
3941 | 0 | const auto filename__ = builder_.CreateSharedString(FilePath( |
3942 | 0 | opts.project_root, f->first, opts.binary_schema_absolute_paths)); |
3943 | 0 | for (auto i = f->second.begin(); i != f->second.end(); i++) { |
3944 | 0 | included_files.push_back(builder_.CreateSharedString( |
3945 | 0 | FilePath(opts.project_root, i->filename, opts.binary_schema_absolute_paths))); |
3946 | 0 | } |
3947 | 0 | const auto included_files__ = builder_.CreateVector(included_files); |
3948 | 0 | included_files.clear(); |
3949 | |
|
3950 | 0 | schema_files.push_back( |
3951 | 0 | reflection::CreateSchemaFile(builder_, filename__, included_files__)); |
3952 | 0 | } |
3953 | 0 | schema_files__ = builder_.CreateVectorOfSortedTables(&schema_files); |
3954 | 0 | } |
3955 | |
|
3956 | 0 | const auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets); |
3957 | 0 | const auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets); |
3958 | 0 | const auto fiid__ = builder_.CreateString(file_identifier_); |
3959 | 0 | const auto fext__ = builder_.CreateString(file_extension_); |
3960 | 0 | const auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets); |
3961 | 0 | const auto schema_offset = reflection::CreateSchema( |
3962 | 0 | builder_, objs__, enum__, fiid__, fext__, |
3963 | 0 | (root_struct_def_ ? root_struct_def_->serialized_location : 0), serv__, |
3964 | 0 | static_cast<reflection::AdvancedFeatures>(advanced_features_), |
3965 | 0 | schema_files__); |
3966 | 0 | if (opts.size_prefixed) { |
3967 | 0 | builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier()); |
3968 | 0 | } else { |
3969 | 0 | builder_.Finish(schema_offset, reflection::SchemaIdentifier()); |
3970 | 0 | } |
3971 | 0 | } |
3972 | | |
3973 | | Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder, |
3974 | 0 | const Parser &parser) const { |
3975 | 0 | std::vector<Offset<reflection::Field>> field_offsets; |
3976 | 0 | for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) { |
3977 | 0 | field_offsets.push_back((*it)->Serialize( |
3978 | 0 | builder, static_cast<uint16_t>(it - fields.vec.begin()), parser)); |
3979 | 0 | } |
3980 | 0 | const auto qualified_name = defined_namespace->GetFullyQualifiedName(name); |
3981 | 0 | const auto name__ = builder->CreateString(qualified_name); |
3982 | 0 | const auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets); |
3983 | 0 | const auto attr__ = SerializeAttributes(builder, parser); |
3984 | 0 | const auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty() |
3985 | 0 | ? builder->CreateVectorOfStrings(doc_comment) |
3986 | 0 | : 0; |
3987 | 0 | std::string decl_file_in_project = declaration_file ? *declaration_file : ""; |
3988 | 0 | const auto file__ = builder->CreateSharedString(decl_file_in_project); |
3989 | 0 | return reflection::CreateObject( |
3990 | 0 | *builder, name__, flds__, fixed, static_cast<int>(minalign), |
3991 | 0 | static_cast<int>(bytesize), attr__, docs__, file__); |
3992 | 0 | } |
3993 | | |
3994 | 0 | bool StructDef::Deserialize(Parser &parser, const reflection::Object *object) { |
3995 | 0 | if (!DeserializeAttributes(parser, object->attributes())) return false; |
3996 | 0 | DeserializeDoc(doc_comment, object->documentation()); |
3997 | 0 | name = parser.UnqualifiedName(object->name()->str()); |
3998 | 0 | predecl = false; |
3999 | 0 | sortbysize = attributes.Lookup("original_order") == nullptr && !fixed; |
4000 | 0 | const auto &of = *(object->fields()); |
4001 | 0 | auto indexes = std::vector<uoffset_t>(of.size()); |
4002 | 0 | for (uoffset_t i = 0; i < of.size(); i++) indexes[of.Get(i)->id()] = i; |
4003 | 0 | size_t tmp_struct_size = 0; |
4004 | 0 | for (size_t i = 0; i < indexes.size(); i++) { |
4005 | 0 | auto field = of.Get(indexes[i]); |
4006 | 0 | auto field_def = new FieldDef(); |
4007 | 0 | if (!field_def->Deserialize(parser, field) || |
4008 | 0 | fields.Add(field_def->name, field_def)) { |
4009 | 0 | delete field_def; |
4010 | 0 | return false; |
4011 | 0 | } |
4012 | 0 | if (field_def->key) { |
4013 | 0 | if (has_key) { |
4014 | | // only one field may be set as key |
4015 | 0 | delete field_def; |
4016 | 0 | return false; |
4017 | 0 | } |
4018 | 0 | has_key = true; |
4019 | 0 | } |
4020 | 0 | if (fixed) { |
4021 | | // Recompute padding since that's currently not serialized. |
4022 | 0 | auto size = InlineSize(field_def->value.type); |
4023 | 0 | auto next_field = |
4024 | 0 | i + 1 < indexes.size() ? of.Get(indexes[i + 1]) : nullptr; |
4025 | 0 | tmp_struct_size += size; |
4026 | 0 | field_def->padding = |
4027 | 0 | next_field ? (next_field->offset() - field_def->value.offset) - size |
4028 | 0 | : PaddingBytes(tmp_struct_size, minalign); |
4029 | 0 | tmp_struct_size += field_def->padding; |
4030 | 0 | } |
4031 | 0 | } |
4032 | 0 | FLATBUFFERS_ASSERT(static_cast<int>(tmp_struct_size) == object->bytesize()); |
4033 | 0 | return true; |
4034 | 0 | } |
4035 | | |
4036 | | Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder, |
4037 | | uint16_t id, |
4038 | 0 | const Parser &parser) const { |
4039 | 0 | auto name__ = builder->CreateString(name); |
4040 | 0 | auto type__ = value.type.Serialize(builder); |
4041 | 0 | auto attr__ = SerializeAttributes(builder, parser); |
4042 | 0 | auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty() |
4043 | 0 | ? builder->CreateVectorOfStrings(doc_comment) |
4044 | 0 | : 0; |
4045 | 0 | double d; |
4046 | 0 | StringToNumber(value.constant.c_str(), &d); |
4047 | 0 | return reflection::CreateField( |
4048 | 0 | *builder, name__, type__, id, value.offset, |
4049 | | // Is uint64>max(int64) tested? |
4050 | 0 | IsInteger(value.type.base_type) ? StringToInt(value.constant.c_str()) : 0, |
4051 | | // result may be platform-dependent if underlying is float (not double) |
4052 | 0 | IsFloat(value.type.base_type) ? d : 0.0, deprecated, IsRequired(), key, |
4053 | 0 | attr__, docs__, IsOptional(), static_cast<uint16_t>(padding), offset64); |
4054 | | // TODO: value.constant is almost always "0", we could save quite a bit of |
4055 | | // space by sharing it. Same for common values of value.type. |
4056 | 0 | } |
4057 | | |
4058 | 0 | bool FieldDef::Deserialize(Parser &parser, const reflection::Field *field) { |
4059 | 0 | name = field->name()->str(); |
4060 | 0 | defined_namespace = parser.current_namespace_; |
4061 | 0 | if (!value.type.Deserialize(parser, field->type())) return false; |
4062 | 0 | value.offset = field->offset(); |
4063 | 0 | if (IsInteger(value.type.base_type)) { |
4064 | 0 | value.constant = NumToString(field->default_integer()); |
4065 | 0 | } else if (IsFloat(value.type.base_type)) { |
4066 | 0 | value.constant = FloatToString(field->default_real(), 17); |
4067 | 0 | } |
4068 | 0 | presence = FieldDef::MakeFieldPresence(field->optional(), field->required()); |
4069 | 0 | padding = field->padding(); |
4070 | 0 | key = field->key(); |
4071 | 0 | offset64 = field->offset64(); |
4072 | 0 | if (!DeserializeAttributes(parser, field->attributes())) return false; |
4073 | | // TODO: this should probably be handled by a separate attribute |
4074 | 0 | if (attributes.Lookup("flexbuffer")) { |
4075 | 0 | flexbuffer = true; |
4076 | 0 | parser.uses_flexbuffers_ = true; |
4077 | 0 | if (value.type.base_type != BASE_TYPE_VECTOR || |
4078 | 0 | value.type.element != BASE_TYPE_UCHAR) |
4079 | 0 | return false; |
4080 | 0 | } |
4081 | 0 | if (auto nested = attributes.Lookup("nested_flatbuffer")) { |
4082 | 0 | auto nested_qualified_name = |
4083 | 0 | parser.current_namespace_->GetFullyQualifiedName(nested->constant); |
4084 | 0 | nested_flatbuffer = parser.LookupStruct(nested_qualified_name); |
4085 | 0 | if (!nested_flatbuffer) return false; |
4086 | 0 | } |
4087 | 0 | shared = attributes.Lookup("shared") != nullptr; |
4088 | 0 | DeserializeDoc(doc_comment, field->documentation()); |
4089 | 0 | return true; |
4090 | 0 | } |
4091 | | |
4092 | | Offset<reflection::RPCCall> RPCCall::Serialize(FlatBufferBuilder *builder, |
4093 | 0 | const Parser &parser) const { |
4094 | 0 | auto name__ = builder->CreateString(name); |
4095 | 0 | auto attr__ = SerializeAttributes(builder, parser); |
4096 | 0 | auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty() |
4097 | 0 | ? builder->CreateVectorOfStrings(doc_comment) |
4098 | 0 | : 0; |
4099 | 0 | return reflection::CreateRPCCall( |
4100 | 0 | *builder, name__, request->serialized_location, |
4101 | 0 | response->serialized_location, attr__, docs__); |
4102 | 0 | } |
4103 | | |
4104 | 0 | bool RPCCall::Deserialize(Parser &parser, const reflection::RPCCall *call) { |
4105 | 0 | name = call->name()->str(); |
4106 | 0 | if (!DeserializeAttributes(parser, call->attributes())) return false; |
4107 | 0 | DeserializeDoc(doc_comment, call->documentation()); |
4108 | 0 | request = parser.structs_.Lookup(call->request()->name()->str()); |
4109 | 0 | response = parser.structs_.Lookup(call->response()->name()->str()); |
4110 | 0 | if (!request || !response) { return false; } |
4111 | 0 | return true; |
4112 | 0 | } |
4113 | | |
4114 | | Offset<reflection::Service> ServiceDef::Serialize(FlatBufferBuilder *builder, |
4115 | 0 | const Parser &parser) const { |
4116 | 0 | std::vector<Offset<reflection::RPCCall>> servicecall_offsets; |
4117 | 0 | for (auto it = calls.vec.begin(); it != calls.vec.end(); ++it) { |
4118 | 0 | servicecall_offsets.push_back((*it)->Serialize(builder, parser)); |
4119 | 0 | } |
4120 | 0 | const auto qualified_name = defined_namespace->GetFullyQualifiedName(name); |
4121 | 0 | const auto name__ = builder->CreateString(qualified_name); |
4122 | 0 | const auto call__ = builder->CreateVector(servicecall_offsets); |
4123 | 0 | const auto attr__ = SerializeAttributes(builder, parser); |
4124 | 0 | const auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty() |
4125 | 0 | ? builder->CreateVectorOfStrings(doc_comment) |
4126 | 0 | : 0; |
4127 | 0 | std::string decl_file_in_project = declaration_file ? *declaration_file : ""; |
4128 | 0 | const auto file__ = builder->CreateSharedString(decl_file_in_project); |
4129 | 0 | return reflection::CreateService(*builder, name__, call__, attr__, docs__, |
4130 | 0 | file__); |
4131 | 0 | } |
4132 | | |
4133 | | bool ServiceDef::Deserialize(Parser &parser, |
4134 | 0 | const reflection::Service *service) { |
4135 | 0 | name = parser.UnqualifiedName(service->name()->str()); |
4136 | 0 | if (service->calls()) { |
4137 | 0 | for (uoffset_t i = 0; i < service->calls()->size(); ++i) { |
4138 | 0 | auto call = new RPCCall(); |
4139 | 0 | if (!call->Deserialize(parser, service->calls()->Get(i)) || |
4140 | 0 | calls.Add(call->name, call)) { |
4141 | 0 | delete call; |
4142 | 0 | return false; |
4143 | 0 | } |
4144 | 0 | } |
4145 | 0 | } |
4146 | 0 | if (!DeserializeAttributes(parser, service->attributes())) return false; |
4147 | 0 | DeserializeDoc(doc_comment, service->documentation()); |
4148 | 0 | return true; |
4149 | 0 | } |
4150 | | |
4151 | | Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder, |
4152 | 0 | const Parser &parser) const { |
4153 | 0 | std::vector<Offset<reflection::EnumVal>> enumval_offsets; |
4154 | 0 | for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) { |
4155 | 0 | enumval_offsets.push_back((*it)->Serialize(builder, parser)); |
4156 | 0 | } |
4157 | 0 | const auto qualified_name = defined_namespace->GetFullyQualifiedName(name); |
4158 | 0 | const auto name__ = builder->CreateString(qualified_name); |
4159 | 0 | const auto vals__ = builder->CreateVector(enumval_offsets); |
4160 | 0 | const auto type__ = underlying_type.Serialize(builder); |
4161 | 0 | const auto attr__ = SerializeAttributes(builder, parser); |
4162 | 0 | const auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty() |
4163 | 0 | ? builder->CreateVectorOfStrings(doc_comment) |
4164 | 0 | : 0; |
4165 | 0 | std::string decl_file_in_project = declaration_file ? *declaration_file : ""; |
4166 | 0 | const auto file__ = builder->CreateSharedString(decl_file_in_project); |
4167 | 0 | return reflection::CreateEnum(*builder, name__, vals__, is_union, type__, |
4168 | 0 | attr__, docs__, file__); |
4169 | 0 | } |
4170 | | |
4171 | 0 | bool EnumDef::Deserialize(Parser &parser, const reflection::Enum *_enum) { |
4172 | 0 | name = parser.UnqualifiedName(_enum->name()->str()); |
4173 | 0 | for (uoffset_t i = 0; i < _enum->values()->size(); ++i) { |
4174 | 0 | auto val = new EnumVal(); |
4175 | 0 | if (!val->Deserialize(parser, _enum->values()->Get(i)) || |
4176 | 0 | vals.Add(val->name, val)) { |
4177 | 0 | delete val; |
4178 | 0 | return false; |
4179 | 0 | } |
4180 | 0 | } |
4181 | 0 | is_union = _enum->is_union(); |
4182 | 0 | if (!underlying_type.Deserialize(parser, _enum->underlying_type())) { |
4183 | 0 | return false; |
4184 | 0 | } |
4185 | 0 | if (!DeserializeAttributes(parser, _enum->attributes())) return false; |
4186 | 0 | DeserializeDoc(doc_comment, _enum->documentation()); |
4187 | 0 | return true; |
4188 | 0 | } |
4189 | | |
4190 | | flatbuffers::Offset< |
4191 | | flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> |
4192 | | EnumVal::SerializeAttributes(FlatBufferBuilder *builder, |
4193 | 0 | const Parser &parser) const { |
4194 | 0 | return SerializeAttributesCommon(attributes, builder, parser); |
4195 | 0 | } |
4196 | | |
4197 | | bool EnumVal::DeserializeAttributes( |
4198 | 0 | Parser &parser, const Vector<Offset<reflection::KeyValue>> *attrs) { |
4199 | 0 | return DeserializeAttributesCommon(attributes, parser, attrs); |
4200 | 0 | } |
4201 | | |
4202 | | Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder, |
4203 | 0 | const Parser &parser) const { |
4204 | 0 | const auto name__ = builder->CreateString(name); |
4205 | 0 | const auto type__ = union_type.Serialize(builder); |
4206 | 0 | const auto attr__ = SerializeAttributes(builder, parser); |
4207 | 0 | const auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty() |
4208 | 0 | ? builder->CreateVectorOfStrings(doc_comment) |
4209 | 0 | : 0; |
4210 | 0 | return reflection::CreateEnumVal(*builder, name__, value, type__, docs__, |
4211 | 0 | attr__); |
4212 | 0 | } |
4213 | | |
4214 | 0 | bool EnumVal::Deserialize(Parser &parser, const reflection::EnumVal *val) { |
4215 | 0 | name = val->name()->str(); |
4216 | 0 | value = val->value(); |
4217 | 0 | if (!union_type.Deserialize(parser, val->union_type())) return false; |
4218 | 0 | if (!DeserializeAttributes(parser, val->attributes())) return false; |
4219 | 0 | DeserializeDoc(doc_comment, val->documentation()); |
4220 | 0 | return true; |
4221 | 0 | } |
4222 | | |
4223 | 0 | Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const { |
4224 | 0 | size_t element_size = SizeOf(element); |
4225 | 0 | if (base_type == BASE_TYPE_VECTOR && element == BASE_TYPE_STRUCT && |
4226 | 0 | struct_def->bytesize != 0) { |
4227 | | // struct_def->bytesize==0 means struct is table |
4228 | 0 | element_size = struct_def->bytesize; |
4229 | 0 | } |
4230 | 0 | return reflection::CreateType( |
4231 | 0 | *builder, static_cast<reflection::BaseType>(base_type), |
4232 | 0 | static_cast<reflection::BaseType>(element), |
4233 | 0 | struct_def ? struct_def->index : (enum_def ? enum_def->index : -1), |
4234 | 0 | fixed_length, static_cast<uint32_t>(SizeOf(base_type)), |
4235 | 0 | static_cast<uint32_t>(element_size)); |
4236 | 0 | } |
4237 | | |
4238 | 0 | bool Type::Deserialize(const Parser &parser, const reflection::Type *type) { |
4239 | 0 | if (type == nullptr) return true; |
4240 | 0 | base_type = static_cast<BaseType>(type->base_type()); |
4241 | 0 | element = static_cast<BaseType>(type->element()); |
4242 | 0 | fixed_length = type->fixed_length(); |
4243 | 0 | if (type->index() >= 0) { |
4244 | 0 | bool is_series = type->base_type() == reflection::Vector || |
4245 | 0 | type->base_type() == reflection::Array; |
4246 | 0 | if (type->base_type() == reflection::Obj || |
4247 | 0 | (is_series && type->element() == reflection::Obj)) { |
4248 | 0 | if (static_cast<size_t>(type->index()) < parser.structs_.vec.size()) { |
4249 | 0 | struct_def = parser.structs_.vec[type->index()]; |
4250 | 0 | struct_def->refcount++; |
4251 | 0 | } else { |
4252 | 0 | return false; |
4253 | 0 | } |
4254 | 0 | } else { |
4255 | 0 | if (static_cast<size_t>(type->index()) < parser.enums_.vec.size()) { |
4256 | 0 | enum_def = parser.enums_.vec[type->index()]; |
4257 | 0 | } else { |
4258 | 0 | return false; |
4259 | 0 | } |
4260 | 0 | } |
4261 | 0 | } |
4262 | 0 | return true; |
4263 | 0 | } |
4264 | | |
4265 | | flatbuffers::Offset< |
4266 | | flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> |
4267 | | Definition::SerializeAttributes(FlatBufferBuilder *builder, |
4268 | 0 | const Parser &parser) const { |
4269 | 0 | return SerializeAttributesCommon(attributes, builder, parser); |
4270 | 0 | } |
4271 | | |
4272 | | bool Definition::DeserializeAttributes( |
4273 | 0 | Parser &parser, const Vector<Offset<reflection::KeyValue>> *attrs) { |
4274 | 0 | return DeserializeAttributesCommon(attributes, parser, attrs); |
4275 | 0 | } |
4276 | | |
4277 | | /************************************************************************/ |
4278 | | /* DESERIALIZATION */ |
4279 | | /************************************************************************/ |
4280 | 0 | bool Parser::Deserialize(const uint8_t *buf, const size_t size) { |
4281 | 0 | flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t *>(buf), size); |
4282 | 0 | bool size_prefixed = false; |
4283 | 0 | if (!reflection::SchemaBufferHasIdentifier(buf)) { |
4284 | 0 | if (!flatbuffers::BufferHasIdentifier(buf, reflection::SchemaIdentifier(), |
4285 | 0 | true)) |
4286 | 0 | return false; |
4287 | 0 | else |
4288 | 0 | size_prefixed = true; |
4289 | 0 | } |
4290 | 0 | auto verify_fn = size_prefixed ? &reflection::VerifySizePrefixedSchemaBuffer |
4291 | 0 | : &reflection::VerifySchemaBuffer; |
4292 | 0 | if (!verify_fn(verifier)) { return false; } |
4293 | 0 | auto schema = size_prefixed ? reflection::GetSizePrefixedSchema(buf) |
4294 | 0 | : reflection::GetSchema(buf); |
4295 | 0 | return Deserialize(schema); |
4296 | 0 | } |
4297 | | |
4298 | 0 | bool Parser::Deserialize(const reflection::Schema *schema) { |
4299 | 0 | file_identifier_ = schema->file_ident() ? schema->file_ident()->str() : ""; |
4300 | 0 | file_extension_ = schema->file_ext() ? schema->file_ext()->str() : ""; |
4301 | 0 | std::map<std::string, Namespace *> namespaces_index; |
4302 | | |
4303 | | // Create defs without deserializing so references from fields to structs and |
4304 | | // enums can be resolved. |
4305 | 0 | for (auto it = schema->objects()->begin(); it != schema->objects()->end(); |
4306 | 0 | ++it) { |
4307 | 0 | auto struct_def = new StructDef(); |
4308 | 0 | struct_def->bytesize = it->bytesize(); |
4309 | 0 | struct_def->fixed = it->is_struct(); |
4310 | 0 | struct_def->minalign = it->minalign(); |
4311 | 0 | if (structs_.Add(it->name()->str(), struct_def)) { |
4312 | 0 | delete struct_def; |
4313 | 0 | return false; |
4314 | 0 | } |
4315 | 0 | auto type = new Type(BASE_TYPE_STRUCT, struct_def, nullptr); |
4316 | 0 | if (types_.Add(it->name()->str(), type)) { |
4317 | 0 | delete type; |
4318 | 0 | return false; |
4319 | 0 | } |
4320 | 0 | } |
4321 | 0 | for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) { |
4322 | 0 | auto enum_def = new EnumDef(); |
4323 | 0 | if (enums_.Add(it->name()->str(), enum_def)) { |
4324 | 0 | delete enum_def; |
4325 | 0 | return false; |
4326 | 0 | } |
4327 | 0 | auto type = new Type(BASE_TYPE_UNION, nullptr, enum_def); |
4328 | 0 | if (types_.Add(it->name()->str(), type)) { |
4329 | 0 | delete type; |
4330 | 0 | return false; |
4331 | 0 | } |
4332 | 0 | } |
4333 | | |
4334 | | // Now fields can refer to structs and enums by index. |
4335 | 0 | for (auto it = schema->objects()->begin(); it != schema->objects()->end(); |
4336 | 0 | ++it) { |
4337 | 0 | std::string qualified_name = it->name()->str(); |
4338 | 0 | auto struct_def = structs_.Lookup(qualified_name); |
4339 | 0 | struct_def->defined_namespace = |
4340 | 0 | GetNamespace(qualified_name, namespaces_, namespaces_index); |
4341 | 0 | if (!struct_def->Deserialize(*this, *it)) { return false; } |
4342 | 0 | if (schema->root_table() == *it) { root_struct_def_ = struct_def; } |
4343 | 0 | } |
4344 | 0 | for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) { |
4345 | 0 | std::string qualified_name = it->name()->str(); |
4346 | 0 | auto enum_def = enums_.Lookup(qualified_name); |
4347 | 0 | enum_def->defined_namespace = |
4348 | 0 | GetNamespace(qualified_name, namespaces_, namespaces_index); |
4349 | 0 | if (!enum_def->Deserialize(*this, *it)) { return false; } |
4350 | 0 | } |
4351 | | |
4352 | 0 | if (schema->services()) { |
4353 | 0 | for (auto it = schema->services()->begin(); it != schema->services()->end(); |
4354 | 0 | ++it) { |
4355 | 0 | std::string qualified_name = it->name()->str(); |
4356 | 0 | auto service_def = new ServiceDef(); |
4357 | 0 | service_def->defined_namespace = |
4358 | 0 | GetNamespace(qualified_name, namespaces_, namespaces_index); |
4359 | 0 | if (!service_def->Deserialize(*this, *it) || |
4360 | 0 | services_.Add(qualified_name, service_def)) { |
4361 | 0 | delete service_def; |
4362 | 0 | return false; |
4363 | 0 | } |
4364 | 0 | } |
4365 | 0 | } |
4366 | 0 | advanced_features_ = schema->advanced_features(); |
4367 | |
|
4368 | 0 | if (schema->fbs_files()) |
4369 | 0 | for (auto s = schema->fbs_files()->begin(); s != schema->fbs_files()->end(); |
4370 | 0 | ++s) { |
4371 | 0 | for (auto f = s->included_filenames()->begin(); |
4372 | 0 | f != s->included_filenames()->end(); ++f) { |
4373 | 0 | IncludedFile included_file; |
4374 | 0 | included_file.filename = f->str(); |
4375 | 0 | files_included_per_file_[s->filename()->str()].insert(included_file); |
4376 | 0 | } |
4377 | 0 | } |
4378 | |
|
4379 | 0 | return true; |
4380 | 0 | } |
4381 | | |
4382 | 0 | std::string Parser::ConformTo(const Parser &base) { |
4383 | 0 | for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) { |
4384 | 0 | auto &struct_def = **sit; |
4385 | 0 | auto qualified_name = |
4386 | 0 | struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name); |
4387 | 0 | auto struct_def_base = base.LookupStruct(qualified_name); |
4388 | 0 | if (!struct_def_base) continue; |
4389 | 0 | std::set<FieldDef *> renamed_fields; |
4390 | 0 | for (auto fit = struct_def.fields.vec.begin(); |
4391 | 0 | fit != struct_def.fields.vec.end(); ++fit) { |
4392 | 0 | auto &field = **fit; |
4393 | 0 | auto field_base = struct_def_base->fields.Lookup(field.name); |
4394 | 0 | const auto qualified_field_name = qualified_name + "." + field.name; |
4395 | 0 | if (field_base) { |
4396 | 0 | if (field.value.offset != field_base->value.offset) { |
4397 | 0 | return "offsets differ for field: " + qualified_field_name; |
4398 | 0 | } |
4399 | 0 | if (field.value.constant != field_base->value.constant) { |
4400 | 0 | return "defaults differ for field: " + qualified_field_name; |
4401 | 0 | } |
4402 | 0 | if (!EqualByName(field.value.type, field_base->value.type)) { |
4403 | 0 | return "types differ for field: " + qualified_field_name; |
4404 | 0 | } |
4405 | 0 | if (field.offset64 != field_base->offset64) { |
4406 | 0 | return "offset types differ for field: " + qualified_field_name; |
4407 | 0 | } |
4408 | 0 | } else { |
4409 | | // Doesn't have to exist, deleting fields is fine. |
4410 | | // But we should check if there is a field that has the same offset |
4411 | | // but is incompatible (in the case of field renaming). |
4412 | 0 | for (auto fbit = struct_def_base->fields.vec.begin(); |
4413 | 0 | fbit != struct_def_base->fields.vec.end(); ++fbit) { |
4414 | 0 | field_base = *fbit; |
4415 | 0 | if (field.value.offset == field_base->value.offset) { |
4416 | 0 | renamed_fields.insert(field_base); |
4417 | 0 | if (!EqualByName(field.value.type, field_base->value.type)) { |
4418 | 0 | const auto qualified_field_base = |
4419 | 0 | qualified_name + "." + field_base->name; |
4420 | 0 | return "field renamed to different type: " + |
4421 | 0 | qualified_field_name + " (renamed from " + |
4422 | 0 | qualified_field_base + ")"; |
4423 | 0 | } |
4424 | 0 | break; |
4425 | 0 | } |
4426 | 0 | } |
4427 | 0 | } |
4428 | 0 | } |
4429 | | // deletion of trailing fields are not allowed |
4430 | 0 | for (auto fit = struct_def_base->fields.vec.begin(); |
4431 | 0 | fit != struct_def_base->fields.vec.end(); ++fit) { |
4432 | 0 | auto &field_base = **fit; |
4433 | | // not a renamed field |
4434 | 0 | if (renamed_fields.find(&field_base) == renamed_fields.end()) { |
4435 | 0 | auto field = struct_def.fields.Lookup(field_base.name); |
4436 | 0 | if (!field) { |
4437 | 0 | return "field deleted: " + qualified_name + "." + field_base.name; |
4438 | 0 | } |
4439 | 0 | } |
4440 | 0 | } |
4441 | 0 | } |
4442 | | |
4443 | 0 | for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) { |
4444 | 0 | auto &enum_def = **eit; |
4445 | 0 | auto qualified_name = |
4446 | 0 | enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name); |
4447 | 0 | auto enum_def_base = base.enums_.Lookup(qualified_name); |
4448 | 0 | if (!enum_def_base) continue; |
4449 | 0 | for (auto evit = enum_def.Vals().begin(); evit != enum_def.Vals().end(); |
4450 | 0 | ++evit) { |
4451 | 0 | auto &enum_val = **evit; |
4452 | 0 | auto enum_val_base = enum_def_base->Lookup(enum_val.name); |
4453 | 0 | if (enum_val_base) { |
4454 | 0 | if (enum_val != *enum_val_base) |
4455 | 0 | return "values differ for enum: " + enum_val.name; |
4456 | 0 | } |
4457 | 0 | } |
4458 | | // Check underlying type changes |
4459 | 0 | if (enum_def_base->underlying_type.base_type != enum_def.underlying_type.base_type) { |
4460 | 0 | return "underlying type differ for " + std::string(enum_def.is_union ? "union: " : "enum: ") + qualified_name; |
4461 | 0 | } |
4462 | 0 | } |
4463 | 0 | return ""; |
4464 | 0 | } |
4465 | | |
4466 | | } // namespace flatbuffers |