/src/wabt/src/wast-parser.cc
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2017 WebAssembly Community Group participants |
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 "wabt/wast-parser.h" |
18 | | |
19 | | #include "wabt/binary-reader-ir.h" |
20 | | #include "wabt/binary-reader.h" |
21 | | #include "wabt/cast.h" |
22 | | #include "wabt/expr-visitor.h" |
23 | | #include "wabt/resolve-names.h" |
24 | | #include "wabt/stream.h" |
25 | | #include "wabt/utf8.h" |
26 | | #include "wabt/validator.h" |
27 | | |
28 | | #define WABT_TRACING 0 |
29 | | #include "wabt/tracing.h" |
30 | | |
31 | 11.5M | #define EXPECT(token_type) CHECK_RESULT(Expect(TokenType::token_type)) |
32 | | |
33 | | namespace wabt { |
34 | | |
35 | | namespace { |
36 | | |
37 | | static const size_t kMaxErrorTokenLength = 80; |
38 | | |
39 | 3.53k | bool IsPowerOfTwo(uint32_t x) { |
40 | 3.53k | return x && ((x & (x - 1)) == 0); |
41 | 3.53k | } |
42 | | |
43 | | template <typename OutputIter> |
44 | 454k | void RemoveEscapes(std::string_view text, OutputIter dest) { |
45 | | // Remove surrounding quotes; if any. This may be empty if the string was |
46 | | // invalid (e.g. if it contained a bad escape sequence). |
47 | 454k | if (text.size() <= 2) { |
48 | 345k | return; |
49 | 345k | } |
50 | | |
51 | 108k | text = text.substr(1, text.size() - 2); |
52 | | |
53 | 108k | const char* src = text.data(); |
54 | 108k | const char* end = text.data() + text.size(); |
55 | | |
56 | 6.88M | while (src < end) { |
57 | 6.77M | if (*src == '\\') { |
58 | 11.6k | src++; |
59 | 11.6k | switch (*src) { |
60 | 702 | case 'n': |
61 | 702 | *dest++ = '\n'; |
62 | 702 | break; |
63 | 810 | case 'r': |
64 | 810 | *dest++ = '\r'; |
65 | 810 | break; |
66 | 798 | case 't': |
67 | 798 | *dest++ = '\t'; |
68 | 798 | break; |
69 | 1.75k | case '\\': |
70 | 1.75k | *dest++ = '\\'; |
71 | 1.75k | break; |
72 | 626 | case '\'': |
73 | 626 | *dest++ = '\''; |
74 | 626 | break; |
75 | 848 | case '\"': |
76 | 848 | *dest++ = '\"'; |
77 | 848 | break; |
78 | 5.24k | case 'u': { |
79 | | // The string should be validated already, |
80 | | // so this must be a valid unicode escape sequence. |
81 | 5.24k | uint32_t digit; |
82 | 5.24k | uint32_t scalar_value = 0; |
83 | | |
84 | | // Skip u and { characters. |
85 | 5.24k | src += 2; |
86 | | |
87 | 16.8k | do { |
88 | 16.8k | if (Succeeded(ParseHexdigit(src[0], &digit))) { |
89 | 16.8k | scalar_value = (scalar_value << 4) | digit; |
90 | 16.8k | } else { |
91 | 0 | assert(0); |
92 | 0 | } |
93 | 16.8k | src++; |
94 | 16.8k | } while (src[0] != '}'); |
95 | | |
96 | | // Maximum value of a unicode scalar value |
97 | 5.24k | assert(scalar_value < 0x110000); |
98 | | |
99 | | // Encode the unicode scalar value as UTF8 sequence |
100 | 5.24k | if (scalar_value < 0x80) { |
101 | 938 | *dest++ = static_cast<uint8_t>(scalar_value); |
102 | 4.30k | } else { |
103 | 4.30k | if (scalar_value < 0x800) { |
104 | 1.02k | *dest++ = static_cast<uint8_t>(0xc0 | (scalar_value >> 6)); |
105 | 3.28k | } else { |
106 | 3.28k | if (scalar_value < 0x10000) { |
107 | 1.80k | *dest++ = static_cast<uint8_t>(0xe0 | (scalar_value >> 12)); |
108 | 1.80k | } else { |
109 | 1.47k | *dest++ = static_cast<uint8_t>(0xf0 | (scalar_value >> 18)); |
110 | 1.47k | *dest++ = |
111 | 1.47k | static_cast<uint8_t>(0x80 | ((scalar_value >> 12) & 0x3f)); |
112 | 1.47k | } |
113 | | |
114 | 3.28k | *dest++ = |
115 | 3.28k | static_cast<uint8_t>(0x80 | ((scalar_value >> 6) & 0x3f)); |
116 | 3.28k | } |
117 | | |
118 | 4.30k | *dest++ = static_cast<uint8_t>(0x80 | (scalar_value & 0x3f)); |
119 | 4.30k | } |
120 | 5.24k | break; |
121 | 5.24k | } |
122 | 866 | default: { |
123 | | // The string should be validated already, so we know this is a hex |
124 | | // sequence. |
125 | 866 | uint32_t hi; |
126 | 866 | uint32_t lo; |
127 | 866 | if (Succeeded(ParseHexdigit(src[0], &hi)) && |
128 | 866 | Succeeded(ParseHexdigit(src[1], &lo))) { |
129 | 866 | *dest++ = (hi << 4) | lo; |
130 | 866 | } else { |
131 | 0 | assert(0); |
132 | 0 | } |
133 | 866 | src++; |
134 | 866 | break; |
135 | 866 | } |
136 | 11.6k | } |
137 | 11.6k | src++; |
138 | 6.76M | } else { |
139 | 6.76M | *dest++ = *src++; |
140 | 6.76M | } |
141 | 6.77M | } |
142 | 108k | } wast-parser.cc:void wabt::(anonymous namespace)::RemoveEscapes<std::__1::back_insert_iterator<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > >(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::back_insert_iterator<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >) Line | Count | Source | 44 | 6.16k | void RemoveEscapes(std::string_view text, OutputIter dest) { | 45 | | // Remove surrounding quotes; if any. This may be empty if the string was | 46 | | // invalid (e.g. if it contained a bad escape sequence). | 47 | 6.16k | if (text.size() <= 2) { | 48 | 3.73k | return; | 49 | 3.73k | } | 50 | | | 51 | 2.43k | text = text.substr(1, text.size() - 2); | 52 | | | 53 | 2.43k | const char* src = text.data(); | 54 | 2.43k | const char* end = text.data() + text.size(); | 55 | | | 56 | 4.00M | while (src < end) { | 57 | 4.00M | if (*src == '\\') { | 58 | 8.28k | src++; | 59 | 8.28k | switch (*src) { | 60 | 452 | case 'n': | 61 | 452 | *dest++ = '\n'; | 62 | 452 | break; | 63 | 603 | case 'r': | 64 | 603 | *dest++ = '\r'; | 65 | 603 | break; | 66 | 593 | case 't': | 67 | 593 | *dest++ = '\t'; | 68 | 593 | break; | 69 | 1.51k | case '\\': | 70 | 1.51k | *dest++ = '\\'; | 71 | 1.51k | break; | 72 | 416 | case '\'': | 73 | 416 | *dest++ = '\''; | 74 | 416 | break; | 75 | 654 | case '\"': | 76 | 654 | *dest++ = '\"'; | 77 | 654 | break; | 78 | 3.42k | case 'u': { | 79 | | // The string should be validated already, | 80 | | // so this must be a valid unicode escape sequence. | 81 | 3.42k | uint32_t digit; | 82 | 3.42k | uint32_t scalar_value = 0; | 83 | | | 84 | | // Skip u and { characters. | 85 | 3.42k | src += 2; | 86 | | | 87 | 10.9k | do { | 88 | 10.9k | if (Succeeded(ParseHexdigit(src[0], &digit))) { | 89 | 10.9k | scalar_value = (scalar_value << 4) | digit; | 90 | 10.9k | } else { | 91 | 0 | assert(0); | 92 | 0 | } | 93 | 10.9k | src++; | 94 | 10.9k | } while (src[0] != '}'); | 95 | | | 96 | | // Maximum value of a unicode scalar value | 97 | 3.42k | assert(scalar_value < 0x110000); | 98 | | | 99 | | // Encode the unicode scalar value as UTF8 sequence | 100 | 3.42k | if (scalar_value < 0x80) { | 101 | 459 | *dest++ = static_cast<uint8_t>(scalar_value); | 102 | 2.96k | } else { | 103 | 2.96k | if (scalar_value < 0x800) { | 104 | 809 | *dest++ = static_cast<uint8_t>(0xc0 | (scalar_value >> 6)); | 105 | 2.15k | } else { | 106 | 2.15k | if (scalar_value < 0x10000) { | 107 | 1.18k | *dest++ = static_cast<uint8_t>(0xe0 | (scalar_value >> 12)); | 108 | 1.18k | } else { | 109 | 967 | *dest++ = static_cast<uint8_t>(0xf0 | (scalar_value >> 18)); | 110 | 967 | *dest++ = | 111 | 967 | static_cast<uint8_t>(0x80 | ((scalar_value >> 12) & 0x3f)); | 112 | 967 | } | 113 | | | 114 | 2.15k | *dest++ = | 115 | 2.15k | static_cast<uint8_t>(0x80 | ((scalar_value >> 6) & 0x3f)); | 116 | 2.15k | } | 117 | | | 118 | 2.96k | *dest++ = static_cast<uint8_t>(0x80 | (scalar_value & 0x3f)); | 119 | 2.96k | } | 120 | 3.42k | break; | 121 | 3.42k | } | 122 | 630 | default: { | 123 | | // The string should be validated already, so we know this is a hex | 124 | | // sequence. | 125 | 630 | uint32_t hi; | 126 | 630 | uint32_t lo; | 127 | 630 | if (Succeeded(ParseHexdigit(src[0], &hi)) && | 128 | 630 | Succeeded(ParseHexdigit(src[1], &lo))) { | 129 | 630 | *dest++ = (hi << 4) | lo; | 130 | 630 | } else { | 131 | 0 | assert(0); | 132 | 0 | } | 133 | 630 | src++; | 134 | 630 | break; | 135 | 630 | } | 136 | 8.28k | } | 137 | 8.28k | src++; | 138 | 3.99M | } else { | 139 | 3.99M | *dest++ = *src++; | 140 | 3.99M | } | 141 | 4.00M | } | 142 | 2.43k | } |
wast-parser.cc:void wabt::(anonymous namespace)::RemoveEscapes<std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >) Line | Count | Source | 44 | 447k | void RemoveEscapes(std::string_view text, OutputIter dest) { | 45 | | // Remove surrounding quotes; if any. This may be empty if the string was | 46 | | // invalid (e.g. if it contained a bad escape sequence). | 47 | 447k | if (text.size() <= 2) { | 48 | 341k | return; | 49 | 341k | } | 50 | | | 51 | 106k | text = text.substr(1, text.size() - 2); | 52 | | | 53 | 106k | const char* src = text.data(); | 54 | 106k | const char* end = text.data() + text.size(); | 55 | | | 56 | 2.87M | while (src < end) { | 57 | 2.77M | if (*src == '\\') { | 58 | 3.35k | src++; | 59 | 3.35k | switch (*src) { | 60 | 250 | case 'n': | 61 | 250 | *dest++ = '\n'; | 62 | 250 | break; | 63 | 207 | case 'r': | 64 | 207 | *dest++ = '\r'; | 65 | 207 | break; | 66 | 205 | case 't': | 67 | 205 | *dest++ = '\t'; | 68 | 205 | break; | 69 | 234 | case '\\': | 70 | 234 | *dest++ = '\\'; | 71 | 234 | break; | 72 | 210 | case '\'': | 73 | 210 | *dest++ = '\''; | 74 | 210 | break; | 75 | 194 | case '\"': | 76 | 194 | *dest++ = '\"'; | 77 | 194 | break; | 78 | 1.82k | case 'u': { | 79 | | // The string should be validated already, | 80 | | // so this must be a valid unicode escape sequence. | 81 | 1.82k | uint32_t digit; | 82 | 1.82k | uint32_t scalar_value = 0; | 83 | | | 84 | | // Skip u and { characters. | 85 | 1.82k | src += 2; | 86 | | | 87 | 5.86k | do { | 88 | 5.86k | if (Succeeded(ParseHexdigit(src[0], &digit))) { | 89 | 5.86k | scalar_value = (scalar_value << 4) | digit; | 90 | 5.86k | } else { | 91 | 0 | assert(0); | 92 | 0 | } | 93 | 5.86k | src++; | 94 | 5.86k | } while (src[0] != '}'); | 95 | | | 96 | | // Maximum value of a unicode scalar value | 97 | 1.82k | assert(scalar_value < 0x110000); | 98 | | | 99 | | // Encode the unicode scalar value as UTF8 sequence | 100 | 1.82k | if (scalar_value < 0x80) { | 101 | 479 | *dest++ = static_cast<uint8_t>(scalar_value); | 102 | 1.34k | } else { | 103 | 1.34k | if (scalar_value < 0x800) { | 104 | 216 | *dest++ = static_cast<uint8_t>(0xc0 | (scalar_value >> 6)); | 105 | 1.12k | } else { | 106 | 1.12k | if (scalar_value < 0x10000) { | 107 | 613 | *dest++ = static_cast<uint8_t>(0xe0 | (scalar_value >> 12)); | 108 | 613 | } else { | 109 | 512 | *dest++ = static_cast<uint8_t>(0xf0 | (scalar_value >> 18)); | 110 | 512 | *dest++ = | 111 | 512 | static_cast<uint8_t>(0x80 | ((scalar_value >> 12) & 0x3f)); | 112 | 512 | } | 113 | | | 114 | 1.12k | *dest++ = | 115 | 1.12k | static_cast<uint8_t>(0x80 | ((scalar_value >> 6) & 0x3f)); | 116 | 1.12k | } | 117 | | | 118 | 1.34k | *dest++ = static_cast<uint8_t>(0x80 | (scalar_value & 0x3f)); | 119 | 1.34k | } | 120 | 1.82k | break; | 121 | 1.82k | } | 122 | 236 | default: { | 123 | | // The string should be validated already, so we know this is a hex | 124 | | // sequence. | 125 | 236 | uint32_t hi; | 126 | 236 | uint32_t lo; | 127 | 236 | if (Succeeded(ParseHexdigit(src[0], &hi)) && | 128 | 236 | Succeeded(ParseHexdigit(src[1], &lo))) { | 129 | 236 | *dest++ = (hi << 4) | lo; | 130 | 236 | } else { | 131 | 0 | assert(0); | 132 | 0 | } | 133 | 236 | src++; | 134 | 236 | break; | 135 | 236 | } | 136 | 3.35k | } | 137 | 3.35k | src++; | 138 | 2.76M | } else { | 139 | 2.76M | *dest++ = *src++; | 140 | 2.76M | } | 141 | 2.77M | } | 142 | 106k | } |
|
143 | | |
144 | | using TextVector = std::vector<std::string_view>; |
145 | | |
146 | | template <typename OutputIter> |
147 | 44.0k | void RemoveEscapes(const TextVector& texts, OutputIter out) { |
148 | 44.0k | for (std::string_view text : texts) |
149 | 6.16k | RemoveEscapes(text, out); |
150 | 44.0k | } |
151 | | |
152 | 8.12M | bool IsPlainInstr(TokenType token_type) { |
153 | 8.12M | switch (token_type) { |
154 | 2.06k | case TokenType::Unreachable: |
155 | 310k | case TokenType::Nop: |
156 | 312k | case TokenType::Drop: |
157 | 316k | case TokenType::Select: |
158 | 332k | case TokenType::Br: |
159 | 334k | case TokenType::BrIf: |
160 | 373k | case TokenType::BrTable: |
161 | 390k | case TokenType::Return: |
162 | 393k | case TokenType::ReturnCall: |
163 | 413k | case TokenType::ReturnCallIndirect: |
164 | 419k | case TokenType::Call: |
165 | 438k | case TokenType::CallIndirect: |
166 | 439k | case TokenType::CallRef: |
167 | 444k | case TokenType::LocalGet: |
168 | 448k | case TokenType::LocalSet: |
169 | 461k | case TokenType::LocalTee: |
170 | 465k | case TokenType::GlobalGet: |
171 | 469k | case TokenType::GlobalSet: |
172 | 557k | case TokenType::Load: |
173 | 577k | case TokenType::Store: |
174 | 1.72M | case TokenType::Const: |
175 | 1.78M | case TokenType::Unary: |
176 | 1.81M | case TokenType::Binary: |
177 | 1.82M | case TokenType::Compare: |
178 | 1.83M | case TokenType::Convert: |
179 | 1.84M | case TokenType::MemoryCopy: |
180 | 1.84M | case TokenType::DataDrop: |
181 | 1.84M | case TokenType::MemoryFill: |
182 | 1.85M | case TokenType::MemoryGrow: |
183 | 1.85M | case TokenType::MemoryInit: |
184 | 1.92M | case TokenType::MemorySize: |
185 | 1.93M | case TokenType::TableCopy: |
186 | 1.93M | case TokenType::ElemDrop: |
187 | 1.94M | case TokenType::TableInit: |
188 | 1.94M | case TokenType::TableGet: |
189 | 1.94M | case TokenType::TableSet: |
190 | 1.95M | case TokenType::TableGrow: |
191 | 1.96M | case TokenType::TableSize: |
192 | 1.96M | case TokenType::TableFill: |
193 | 1.97M | case TokenType::Throw: |
194 | 1.97M | case TokenType::Rethrow: |
195 | 1.97M | case TokenType::RefFunc: |
196 | 1.98M | case TokenType::RefNull: |
197 | 1.98M | case TokenType::RefIsNull: |
198 | 1.98M | case TokenType::AtomicLoad: |
199 | 2.05M | case TokenType::AtomicStore: |
200 | 2.08M | case TokenType::AtomicRmw: |
201 | 2.08M | case TokenType::AtomicRmwCmpxchg: |
202 | 2.09M | case TokenType::AtomicNotify: |
203 | 2.09M | case TokenType::AtomicFence: |
204 | 2.09M | case TokenType::AtomicWait: |
205 | 2.11M | case TokenType::Ternary: |
206 | 2.13M | case TokenType::SimdLaneOp: |
207 | 2.16M | case TokenType::SimdLoadLane: |
208 | 2.16M | case TokenType::SimdStoreLane: |
209 | 2.22M | case TokenType::SimdShuffleOp: |
210 | 2.22M | return true; |
211 | 5.90M | default: |
212 | 5.90M | return false; |
213 | 8.12M | } |
214 | 8.12M | } |
215 | | |
216 | 5.73M | bool IsBlockInstr(TokenType token_type) { |
217 | 5.73M | switch (token_type) { |
218 | 34.5k | case TokenType::Block: |
219 | 181k | case TokenType::Loop: |
220 | 352k | case TokenType::If: |
221 | 440k | case TokenType::Try: |
222 | 440k | return true; |
223 | 5.29M | default: |
224 | 5.29M | return false; |
225 | 5.73M | } |
226 | 5.73M | } |
227 | | |
228 | 6.80M | bool IsPlainOrBlockInstr(TokenType token_type) { |
229 | 6.80M | return IsPlainInstr(token_type) || IsBlockInstr(token_type); |
230 | 6.80M | } |
231 | | |
232 | 7.15M | bool IsExpr(TokenTypePair pair) { |
233 | 7.15M | return pair[0] == TokenType::Lpar && IsPlainOrBlockInstr(pair[1]); |
234 | 7.15M | } |
235 | | |
236 | 4.40M | bool IsInstr(TokenTypePair pair) { |
237 | 4.40M | return IsPlainOrBlockInstr(pair[0]) || IsExpr(pair); |
238 | 4.40M | } |
239 | | |
240 | 2.27M | bool IsLparAnn(TokenTypePair pair) { |
241 | 2.27M | return pair[0] == TokenType::LparAnn; |
242 | 2.27M | } |
243 | | |
244 | 43.0k | bool IsCatch(TokenType token_type) { |
245 | 43.0k | return token_type == TokenType::Catch || token_type == TokenType::CatchAll; |
246 | 43.0k | } |
247 | | |
248 | 9.65M | bool IsModuleField(TokenTypePair pair) { |
249 | 9.65M | if (pair[0] != TokenType::Lpar) { |
250 | 2.87M | return false; |
251 | 2.87M | } |
252 | | |
253 | 6.77M | switch (pair[1]) { |
254 | 133k | case TokenType::Data: |
255 | 382k | case TokenType::Elem: |
256 | 544k | case TokenType::Tag: |
257 | 636k | case TokenType::Export: |
258 | 4.55M | case TokenType::Func: |
259 | 4.62M | case TokenType::Type: |
260 | 4.71M | case TokenType::Global: |
261 | 4.85M | case TokenType::Import: |
262 | 5.54M | case TokenType::Memory: |
263 | 5.54M | case TokenType::Start: |
264 | 6.40M | case TokenType::Table: |
265 | 6.40M | return true; |
266 | 369k | default: |
267 | 369k | return false; |
268 | 6.77M | } |
269 | 6.77M | } |
270 | | |
271 | 0 | bool IsCommand(TokenTypePair pair) { |
272 | 0 | if (pair[0] != TokenType::Lpar) { |
273 | 0 | return false; |
274 | 0 | } |
275 | | |
276 | 0 | switch (pair[1]) { |
277 | 0 | case TokenType::AssertException: |
278 | 0 | case TokenType::AssertExhaustion: |
279 | 0 | case TokenType::AssertInvalid: |
280 | 0 | case TokenType::AssertMalformed: |
281 | 0 | case TokenType::AssertReturn: |
282 | 0 | case TokenType::AssertTrap: |
283 | 0 | case TokenType::AssertUnlinkable: |
284 | 0 | case TokenType::Get: |
285 | 0 | case TokenType::Invoke: |
286 | 0 | case TokenType::Input: |
287 | 0 | case TokenType::Module: |
288 | 0 | case TokenType::Output: |
289 | 0 | case TokenType::Register: |
290 | 0 | return true; |
291 | 0 | default: |
292 | 0 | return false; |
293 | 0 | } |
294 | 0 | } |
295 | | |
296 | 10.0k | bool IsEmptySignature(const FuncSignature& sig) { |
297 | 10.0k | return sig.result_types.empty() && sig.param_types.empty(); |
298 | 10.0k | } |
299 | | |
300 | | bool ResolveFuncTypeWithEmptySignature(const Module& module, |
301 | 1.60M | FuncDeclaration* decl) { |
302 | | // Resolve func type variables where the signature was not specified |
303 | | // explicitly, e.g.: (func (type 1) ...) |
304 | 1.60M | if (decl->has_func_type && IsEmptySignature(decl->sig)) { |
305 | 6.18k | const FuncType* func_type = module.GetFuncType(decl->type_var); |
306 | 6.18k | if (func_type) { |
307 | 2.85k | decl->sig = func_type->sig; |
308 | 2.85k | return true; |
309 | 2.85k | } |
310 | 6.18k | } |
311 | 1.60M | return false; |
312 | 1.60M | } |
313 | | |
314 | | void ResolveTypeName( |
315 | | const Module& module, |
316 | | Type& type, |
317 | | Index index, |
318 | 54.9k | const std::unordered_map<uint32_t, std::string>& bindings) { |
319 | 54.9k | if (type != Type::Reference || type.GetReferenceIndex() != kInvalidIndex) { |
320 | 54.9k | return; |
321 | 54.9k | } |
322 | | |
323 | 0 | const auto name_iterator = bindings.find(index); |
324 | 0 | assert(name_iterator != bindings.cend()); |
325 | 0 | const auto type_index = module.type_bindings.FindIndex(name_iterator->second); |
326 | 0 | assert(type_index != kInvalidIndex); |
327 | 0 | type = Type(Type::Reference, type_index); |
328 | 0 | } |
329 | | |
330 | 1.59M | void ResolveTypeNames(const Module& module, FuncDeclaration* decl) { |
331 | 1.59M | assert(decl); |
332 | 1.59M | auto& signature = decl->sig; |
333 | | |
334 | 1.63M | for (uint32_t param_index = 0; param_index < signature.GetNumParams(); |
335 | 1.59M | ++param_index) { |
336 | 39.7k | ResolveTypeName(module, signature.param_types[param_index], param_index, |
337 | 39.7k | signature.param_type_names); |
338 | 39.7k | } |
339 | | |
340 | 1.60M | for (uint32_t result_index = 0; result_index < signature.GetNumResults(); |
341 | 1.59M | ++result_index) { |
342 | 15.2k | ResolveTypeName(module, signature.result_types[result_index], result_index, |
343 | 15.2k | signature.result_type_names); |
344 | 15.2k | } |
345 | 1.59M | } |
346 | | |
347 | | void ResolveImplicitlyDefinedFunctionType(const Location& loc, |
348 | | Module* module, |
349 | 1.57M | const FuncDeclaration& decl) { |
350 | | // Resolve implicitly defined function types, e.g.: (func (param i32) ...) |
351 | 1.57M | if (!decl.has_func_type) { |
352 | 1.57M | Index func_type_index = module->GetFuncTypeIndex(decl.sig); |
353 | 1.57M | if (func_type_index == kInvalidIndex) { |
354 | 5.82k | auto func_type_field = std::make_unique<TypeModuleField>(loc); |
355 | 5.82k | auto func_type = std::make_unique<FuncType>(); |
356 | 5.82k | func_type->sig = decl.sig; |
357 | 5.82k | func_type_field->type = std::move(func_type); |
358 | 5.82k | module->AppendField(std::move(func_type_field)); |
359 | 5.82k | } |
360 | 1.57M | } |
361 | 1.57M | } |
362 | | |
363 | | Result CheckTypeIndex(const Location& loc, |
364 | | Type actual, |
365 | | Type expected, |
366 | | const char* desc, |
367 | | Index index, |
368 | | const char* index_kind, |
369 | 1.32k | Errors* errors) { |
370 | | // Types must match exactly; no subtyping should be allowed. |
371 | 1.32k | if (actual != expected) { |
372 | 612 | errors->emplace_back( |
373 | 612 | ErrorLevel::Error, loc, |
374 | 612 | StringPrintf("type mismatch for %s %" PRIindex |
375 | 612 | " of %s. got %s, expected %s", |
376 | 612 | index_kind, index, desc, actual.GetName().c_str(), |
377 | 612 | expected.GetName().c_str())); |
378 | 612 | return Result::Error; |
379 | 612 | } |
380 | 713 | return Result::Ok; |
381 | 1.32k | } |
382 | | |
383 | | Result CheckTypes(const Location& loc, |
384 | | const TypeVector& actual, |
385 | | const TypeVector& expected, |
386 | | const char* desc, |
387 | | const char* index_kind, |
388 | 9.40k | Errors* errors) { |
389 | 9.40k | Result result = Result::Ok; |
390 | 9.40k | if (actual.size() == expected.size()) { |
391 | 8.41k | for (size_t i = 0; i < actual.size(); ++i) { |
392 | 1.32k | result |= CheckTypeIndex(loc, actual[i], expected[i], desc, i, index_kind, |
393 | 1.32k | errors); |
394 | 1.32k | } |
395 | 7.09k | } else { |
396 | 2.31k | errors->emplace_back( |
397 | 2.31k | ErrorLevel::Error, loc, |
398 | 2.31k | StringPrintf("expected %" PRIzd " %ss, got %" PRIzd, expected.size(), |
399 | 2.31k | index_kind, actual.size())); |
400 | 2.31k | result = Result::Error; |
401 | 2.31k | } |
402 | 9.40k | return result; |
403 | 9.40k | } |
404 | | |
405 | | Result CheckFuncTypeVarMatchesExplicit(const Location& loc, |
406 | | const Module& module, |
407 | | const FuncDeclaration& decl, |
408 | 1.60M | Errors* errors) { |
409 | 1.60M | Result result = Result::Ok; |
410 | 1.60M | if (decl.has_func_type) { |
411 | 10.0k | const FuncType* func_type = module.GetFuncType(decl.type_var); |
412 | 10.0k | if (func_type) { |
413 | 4.70k | result |= |
414 | 4.70k | CheckTypes(loc, decl.sig.result_types, func_type->sig.result_types, |
415 | 4.70k | "function", "result", errors); |
416 | 4.70k | result |= |
417 | 4.70k | CheckTypes(loc, decl.sig.param_types, func_type->sig.param_types, |
418 | 4.70k | "function", "argument", errors); |
419 | 5.32k | } else if (!(decl.sig.param_types.empty() && |
420 | 5.32k | decl.sig.result_types.empty())) { |
421 | | // We want to check whether the function type at the explicit index |
422 | | // matches the given param and result types. If they were omitted then |
423 | | // they'll be resolved automatically (see |
424 | | // ResolveFuncTypeWithEmptySignature), but if they are provided then we |
425 | | // have to check. If we get here then the type var is invalid, so we |
426 | | // can't check whether they match. |
427 | 1.98k | if (decl.type_var.is_index()) { |
428 | 1.27k | errors->emplace_back(ErrorLevel::Error, loc, |
429 | 1.27k | StringPrintf("invalid func type index %" PRIindex, |
430 | 1.27k | decl.type_var.index())); |
431 | 1.27k | } else { |
432 | 712 | errors->emplace_back(ErrorLevel::Error, loc, |
433 | 712 | StringPrintf("expected func type identifier %s", |
434 | 712 | decl.type_var.name().c_str())); |
435 | 712 | } |
436 | 1.98k | result = Result::Error; |
437 | 1.98k | } |
438 | 10.0k | } |
439 | 1.60M | return result; |
440 | 1.60M | } |
441 | | |
442 | 27.3k | bool IsInlinableFuncSignature(const FuncSignature& sig) { |
443 | 27.3k | return sig.GetNumParams() == 0 && sig.GetNumResults() <= 1; |
444 | 27.3k | } |
445 | | |
446 | | class ResolveFuncTypesExprVisitorDelegate : public ExprVisitor::DelegateNop { |
447 | | public: |
448 | | explicit ResolveFuncTypesExprVisitorDelegate(Module* module, Errors* errors) |
449 | 1.52M | : module_(module), errors_(errors) {} |
450 | | |
451 | 27.3k | void ResolveBlockDeclaration(const Location& loc, BlockDeclaration* decl) { |
452 | 27.3k | ResolveTypeNames(*module_, decl); |
453 | 27.3k | ResolveFuncTypeWithEmptySignature(*module_, decl); |
454 | 27.3k | if (!IsInlinableFuncSignature(decl->sig)) { |
455 | 1.61k | ResolveImplicitlyDefinedFunctionType(loc, module_, *decl); |
456 | 1.61k | } |
457 | 27.3k | } |
458 | | |
459 | 6.78k | Result BeginBlockExpr(BlockExpr* expr) override { |
460 | 6.78k | ResolveBlockDeclaration(expr->loc, &expr->block.decl); |
461 | 6.78k | return CheckFuncTypeVarMatchesExplicit(expr->loc, *module_, |
462 | 6.78k | expr->block.decl, errors_); |
463 | 6.78k | } |
464 | | |
465 | 1.72k | Result BeginIfExpr(IfExpr* expr) override { |
466 | 1.72k | ResolveBlockDeclaration(expr->loc, &expr->true_.decl); |
467 | 1.72k | return CheckFuncTypeVarMatchesExplicit(expr->loc, *module_, |
468 | 1.72k | expr->true_.decl, errors_); |
469 | 1.72k | } |
470 | | |
471 | 16.3k | Result BeginLoopExpr(LoopExpr* expr) override { |
472 | 16.3k | ResolveBlockDeclaration(expr->loc, &expr->block.decl); |
473 | 16.3k | return CheckFuncTypeVarMatchesExplicit(expr->loc, *module_, |
474 | 16.3k | expr->block.decl, errors_); |
475 | 16.3k | } |
476 | | |
477 | 2.48k | Result BeginTryExpr(TryExpr* expr) override { |
478 | 2.48k | ResolveBlockDeclaration(expr->loc, &expr->block.decl); |
479 | 2.48k | return CheckFuncTypeVarMatchesExplicit(expr->loc, *module_, |
480 | 2.48k | expr->block.decl, errors_); |
481 | 2.48k | } |
482 | | |
483 | 6.76k | Result OnCallIndirectExpr(CallIndirectExpr* expr) override { |
484 | 6.76k | ResolveFuncTypeWithEmptySignature(*module_, &expr->decl); |
485 | 6.76k | ResolveImplicitlyDefinedFunctionType(expr->loc, module_, expr->decl); |
486 | 6.76k | return CheckFuncTypeVarMatchesExplicit(expr->loc, *module_, expr->decl, |
487 | 6.76k | errors_); |
488 | 6.76k | } |
489 | | |
490 | 5.49k | Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr* expr) override { |
491 | 5.49k | ResolveFuncTypeWithEmptySignature(*module_, &expr->decl); |
492 | 5.49k | ResolveImplicitlyDefinedFunctionType(expr->loc, module_, expr->decl); |
493 | 5.49k | return CheckFuncTypeVarMatchesExplicit(expr->loc, *module_, expr->decl, |
494 | 5.49k | errors_); |
495 | 5.49k | } |
496 | | |
497 | | private: |
498 | | Module* module_; |
499 | | Errors* errors_; |
500 | | }; |
501 | | |
502 | 7.25k | Result ResolveFuncTypes(Module* module, Errors* errors) { |
503 | 7.25k | Result result = Result::Ok; |
504 | 2.05M | for (ModuleField& field : module->fields) { |
505 | 2.05M | Func* func = nullptr; |
506 | 2.05M | FuncDeclaration* decl = nullptr; |
507 | 2.05M | if (auto* func_field = dyn_cast<FuncModuleField>(&field)) { |
508 | 1.52M | func = &func_field->func; |
509 | 1.52M | decl = &func->decl; |
510 | 1.52M | } else if (auto* tag_field = dyn_cast<TagModuleField>(&field)) { |
511 | 0 | decl = &tag_field->tag.decl; |
512 | 530k | } else if (auto* import_field = dyn_cast<ImportModuleField>(&field)) { |
513 | 40.5k | if (auto* func_import = |
514 | 40.5k | dyn_cast<FuncImport>(import_field->import.get())) { |
515 | | // Only check the declaration, not the function itself, since it is an |
516 | | // import. |
517 | 27.1k | decl = &func_import->func.decl; |
518 | 27.1k | } else if (auto* tag_import = |
519 | 13.4k | dyn_cast<TagImport>(import_field->import.get())) { |
520 | 12.9k | decl = &tag_import->tag.decl; |
521 | 12.9k | } else { |
522 | 517 | continue; |
523 | 517 | } |
524 | 490k | } else { |
525 | 490k | continue; |
526 | 490k | } |
527 | | |
528 | 1.56M | bool has_func_type_and_empty_signature = false; |
529 | | |
530 | 1.56M | if (decl) { |
531 | 1.56M | ResolveTypeNames(*module, decl); |
532 | 1.56M | has_func_type_and_empty_signature = |
533 | 1.56M | ResolveFuncTypeWithEmptySignature(*module, decl); |
534 | 1.56M | ResolveImplicitlyDefinedFunctionType(field.loc, module, *decl); |
535 | 1.56M | result |= |
536 | 1.56M | CheckFuncTypeVarMatchesExplicit(field.loc, *module, *decl, errors); |
537 | 1.56M | } |
538 | | |
539 | 1.56M | if (func) { |
540 | 1.52M | if (has_func_type_and_empty_signature) { |
541 | | // The call to ResolveFuncTypeWithEmptySignature may have updated the |
542 | | // function signature so there are parameters. Since parameters and |
543 | | // local variables share the same index space, we need to increment the |
544 | | // local indexes bound to a given name by the number of parameters in |
545 | | // the function. |
546 | 2.04k | for (auto& [name, binding] : func->bindings) { |
547 | 2.04k | binding.index += func->GetNumParams(); |
548 | 2.04k | } |
549 | 1.33k | } |
550 | | |
551 | 1.52M | ResolveFuncTypesExprVisitorDelegate delegate(module, errors); |
552 | 1.52M | ExprVisitor visitor(&delegate); |
553 | 1.52M | result |= visitor.VisitFunc(func); |
554 | 1.52M | } |
555 | 1.56M | } |
556 | 7.25k | return result; |
557 | 7.25k | } |
558 | | |
559 | | void AppendInlineExportFields(Module* module, |
560 | | ModuleFieldList* fields, |
561 | 2.80M | Index index) { |
562 | 2.80M | Location last_field_loc = module->fields.back().loc; |
563 | | |
564 | 2.80M | for (ModuleField& field : *fields) { |
565 | 48.8k | auto* export_field = cast<ExportModuleField>(&field); |
566 | 48.8k | export_field->export_.var = Var(index, last_field_loc); |
567 | 48.8k | } |
568 | | |
569 | 2.80M | module->AppendFields(fields); |
570 | 2.80M | } |
571 | | |
572 | | } // End of anonymous namespace |
573 | | |
574 | | WastParser::WastParser(WastLexer* lexer, |
575 | | Errors* errors, |
576 | | WastParseOptions* options) |
577 | 22.7k | : lexer_(lexer), errors_(errors), options_(options) {} |
578 | | |
579 | 6.23M | void WastParser::Error(Location loc, const char* format, ...) { |
580 | 6.23M | WABT_SNPRINTF_ALLOCA(buffer, length, format); |
581 | 6.23M | errors_->emplace_back(ErrorLevel::Error, loc, buffer); |
582 | 6.23M | } |
583 | | |
584 | 8.86M | Token WastParser::GetToken() { |
585 | 8.86M | if (tokens_.empty()) { |
586 | 618k | tokens_.push_back(lexer_->GetToken()); |
587 | 618k | } |
588 | 8.86M | return tokens_.front(); |
589 | 8.86M | } |
590 | | |
591 | 7.89M | Location WastParser::GetLocation() { |
592 | 7.89M | return GetToken().loc; |
593 | 7.89M | } |
594 | | |
595 | 88.2M | TokenType WastParser::Peek(size_t n) { |
596 | 88.2M | assert(n <= 1); |
597 | 112M | while (tokens_.size() <= n) { |
598 | 24.2M | Token cur = lexer_->GetToken(); |
599 | 24.2M | if (cur.token_type() != TokenType::LparAnn) { |
600 | 22.8M | tokens_.push_back(cur); |
601 | 22.8M | } else { |
602 | | // Custom annotation. For now, discard until matching Rpar, unless it is |
603 | | // a code metadata annotation or custom section. In those cases, we know |
604 | | // how to parse it. |
605 | 1.41M | if (!options_->features.annotations_enabled()) { |
606 | 1.41M | Error(cur.loc, "annotations not enabled: %s", cur.to_string().c_str()); |
607 | 1.41M | tokens_.push_back(Token(cur.loc, TokenType::Invalid)); |
608 | 1.41M | continue; |
609 | 1.41M | } |
610 | 0 | if ((options_->features.code_metadata_enabled() && |
611 | 0 | cur.text().find("metadata.code.") == 0) || |
612 | 0 | cur.text() == "custom") { |
613 | 0 | tokens_.push_back(cur); |
614 | 0 | continue; |
615 | 0 | } |
616 | 0 | int indent = 1; |
617 | 0 | while (indent > 0) { |
618 | 0 | cur = lexer_->GetToken(); |
619 | 0 | switch (cur.token_type()) { |
620 | 0 | case TokenType::Lpar: |
621 | 0 | case TokenType::LparAnn: |
622 | 0 | indent++; |
623 | 0 | break; |
624 | | |
625 | 0 | case TokenType::Rpar: |
626 | 0 | indent--; |
627 | 0 | break; |
628 | | |
629 | 0 | case TokenType::Eof: |
630 | 0 | indent = 0; |
631 | 0 | Error(cur.loc, "unterminated annotation"); |
632 | 0 | break; |
633 | | |
634 | 0 | default: |
635 | 0 | break; |
636 | 0 | } |
637 | 0 | } |
638 | 0 | } |
639 | 24.2M | } |
640 | 88.2M | return tokens_.at(n).token_type(); |
641 | 88.2M | } |
642 | | |
643 | 17.2M | TokenTypePair WastParser::PeekPair() { |
644 | 17.2M | return TokenTypePair{{Peek(), Peek(1)}}; |
645 | 17.2M | } |
646 | | |
647 | 28.8M | bool WastParser::PeekMatch(TokenType type, size_t n) { |
648 | 28.8M | return Peek(n) == type; |
649 | 28.8M | } |
650 | | |
651 | 16.7M | bool WastParser::PeekMatchLpar(TokenType type) { |
652 | 16.7M | return Peek() == TokenType::Lpar && Peek(1) == type; |
653 | 16.7M | } |
654 | | |
655 | 1.44M | bool WastParser::PeekMatchExpr() { |
656 | 1.44M | return IsExpr(PeekPair()); |
657 | 1.44M | } |
658 | | |
659 | 221k | bool WastParser::PeekMatchRefType() { |
660 | 221k | return options_->features.function_references_enabled() && |
661 | 221k | PeekMatchLpar(TokenType::Ref); |
662 | 221k | } |
663 | | |
664 | 15.3M | bool WastParser::Match(TokenType type) { |
665 | 15.3M | if (PeekMatch(type)) { |
666 | 9.21M | Consume(); |
667 | 9.21M | return true; |
668 | 9.21M | } |
669 | 6.11M | return false; |
670 | 15.3M | } |
671 | | |
672 | 10.2M | bool WastParser::MatchLpar(TokenType type) { |
673 | 10.2M | if (PeekMatchLpar(type)) { |
674 | 117k | Consume(); |
675 | 117k | Consume(); |
676 | 117k | return true; |
677 | 117k | } |
678 | 10.1M | return false; |
679 | 10.2M | } |
680 | | |
681 | 11.5M | Result WastParser::Expect(TokenType type) { |
682 | 11.5M | if (!Match(type)) { |
683 | 2.64M | Token token = Consume(); |
684 | 2.64M | Error(token.loc, "unexpected token %s, expected %s.", |
685 | 2.64M | token.to_string_clamp(kMaxErrorTokenLength).c_str(), |
686 | 2.64M | GetTokenTypeName(type)); |
687 | 2.64M | return Result::Error; |
688 | 2.64M | } |
689 | | |
690 | 8.88M | return Result::Ok; |
691 | 11.5M | } |
692 | | |
693 | 24.8M | Token WastParser::Consume() { |
694 | 24.8M | assert(!tokens_.empty()); |
695 | 24.8M | Token token = tokens_.front(); |
696 | 24.8M | tokens_.pop_front(); |
697 | 24.8M | return token; |
698 | 24.8M | } |
699 | | |
700 | 3.44M | Result WastParser::Synchronize(SynchronizeFunc func) { |
701 | 3.44M | static const int kMaxConsumed = 10; |
702 | 9.49M | for (int i = 0; i < kMaxConsumed; ++i) { |
703 | 9.31M | if (func(PeekPair())) { |
704 | 3.26M | return Result::Ok; |
705 | 3.26M | } |
706 | | |
707 | 6.05M | Token token = Consume(); |
708 | 6.05M | if (token.token_type() == TokenType::Reserved) { |
709 | 1.23M | Error(token.loc, "unexpected token %s.", |
710 | 1.23M | token.to_string_clamp(kMaxErrorTokenLength).c_str()); |
711 | 1.23M | } |
712 | 6.05M | } |
713 | | |
714 | 181k | return Result::Error; |
715 | 3.44M | } |
716 | | |
717 | 231k | void WastParser::ErrorUnlessOpcodeEnabled(const Token& token) { |
718 | 231k | Opcode opcode = token.opcode(); |
719 | 231k | if (!opcode.IsEnabled(options_->features)) { |
720 | 98.0k | Error(token.loc, "opcode not allowed: %s", opcode.GetName()); |
721 | 98.0k | } |
722 | 231k | } |
723 | | |
724 | | Result WastParser::ErrorExpected(const std::vector<std::string>& expected, |
725 | 488k | const char* example) { |
726 | 488k | GetToken(); |
727 | 488k | Token token = Consume(); |
728 | 488k | std::string expected_str; |
729 | 488k | if (!expected.empty()) { |
730 | 488k | expected_str = ", expected "; |
731 | 1.11M | for (size_t i = 0; i < expected.size(); ++i) { |
732 | 625k | if (i != 0) { |
733 | 137k | if (i == expected.size() - 1) { |
734 | 62.8k | expected_str += " or "; |
735 | 74.5k | } else { |
736 | 74.5k | expected_str += ", "; |
737 | 74.5k | } |
738 | 137k | } |
739 | | |
740 | 625k | expected_str += expected[i]; |
741 | 625k | } |
742 | | |
743 | 488k | if (example) { |
744 | 171k | expected_str += " (e.g. "; |
745 | 171k | expected_str += example; |
746 | 171k | expected_str += ")"; |
747 | 171k | } |
748 | 488k | } |
749 | | |
750 | 488k | Error(token.loc, "unexpected token \"%s\"%s.", |
751 | 488k | token.to_string_clamp(kMaxErrorTokenLength).c_str(), |
752 | 488k | expected_str.c_str()); |
753 | 488k | return Result::Error; |
754 | 488k | } |
755 | | |
756 | | Result WastParser::ErrorIfLpar(const std::vector<std::string>& expected, |
757 | 2.70M | const char* example) { |
758 | 2.70M | if (Match(TokenType::Lpar)) { |
759 | 259k | return ErrorExpected(expected, example); |
760 | 259k | } |
761 | 2.44M | return Result::Ok; |
762 | 2.70M | } |
763 | | |
764 | 3.48M | bool WastParser::ParseBindVarOpt(std::string* name) { |
765 | 3.48M | WABT_TRACE(ParseBindVarOpt); |
766 | 3.48M | if (!PeekMatch(TokenType::Var)) { |
767 | 2.50M | return false; |
768 | 2.50M | } |
769 | 982k | Token token = Consume(); |
770 | 982k | *name = std::string(token.text()); |
771 | 982k | return true; |
772 | 3.48M | } |
773 | | |
774 | 992k | Result WastParser::ParseVar(Var* out_var) { |
775 | 992k | WABT_TRACE(ParseVar); |
776 | 992k | if (PeekMatch(TokenType::Nat)) { |
777 | 256k | Token token = Consume(); |
778 | 256k | std::string_view sv = token.literal().text; |
779 | 256k | uint64_t index = kInvalidIndex; |
780 | 256k | if (Failed(ParseUint64(sv, &index))) { |
781 | | // Print an error, but don't fail parsing. |
782 | 1.03k | Error(token.loc, "invalid int \"" PRIstringview "\"", |
783 | 1.03k | WABT_PRINTF_STRING_VIEW_ARG(sv)); |
784 | 1.03k | } |
785 | | |
786 | 256k | *out_var = Var(index, token.loc); |
787 | 256k | return Result::Ok; |
788 | 736k | } else if (PeekMatch(TokenType::Var)) { |
789 | 715k | Token token = Consume(); |
790 | 715k | *out_var = Var(token.text(), token.loc); |
791 | 715k | return Result::Ok; |
792 | 715k | } else { |
793 | 21.2k | return ErrorExpected({"a numeric index", "a name"}, "12 or $foo"); |
794 | 21.2k | } |
795 | 992k | } |
796 | | |
797 | 1.45M | bool WastParser::ParseVarOpt(Var* out_var, Var default_var) { |
798 | 1.45M | WABT_TRACE(ParseVarOpt); |
799 | 1.45M | if (PeekMatch(TokenType::Nat) || PeekMatch(TokenType::Var)) { |
800 | 861k | Result result = ParseVar(out_var); |
801 | | // Should always succeed, the only way it could fail is if the token |
802 | | // doesn't match. |
803 | 861k | assert(Succeeded(result)); |
804 | 861k | WABT_USE(result); |
805 | 861k | return true; |
806 | 861k | } else { |
807 | 593k | *out_var = default_var; |
808 | 593k | return false; |
809 | 593k | } |
810 | 1.45M | } |
811 | | |
812 | 4.18k | Result WastParser::ParseOffsetExpr(ExprList* out_expr_list) { |
813 | 4.18k | WABT_TRACE(ParseOffsetExpr); |
814 | 4.18k | if (!ParseOffsetExprOpt(out_expr_list)) { |
815 | 3.01k | return ErrorExpected({"an offset expr"}, "(i32.const 123)"); |
816 | 3.01k | } |
817 | 1.17k | return Result::Ok; |
818 | 4.18k | } |
819 | | |
820 | 277k | bool WastParser::ParseOffsetExprOpt(ExprList* out_expr_list) { |
821 | 277k | WABT_TRACE(ParseOffsetExprOpt); |
822 | 277k | if (MatchLpar(TokenType::Offset)) { |
823 | 393 | CHECK_RESULT(ParseTerminatingInstrList(out_expr_list)); |
824 | 194 | EXPECT(Rpar); |
825 | 0 | return true; |
826 | 276k | } else if (PeekMatchExpr()) { |
827 | 2.56k | CHECK_RESULT(ParseExpr(out_expr_list)); |
828 | 555 | return true; |
829 | 274k | } else { |
830 | 274k | return false; |
831 | 274k | } |
832 | 277k | } |
833 | | |
834 | 0 | Result WastParser::ParseTextList(std::vector<uint8_t>* out_data) { |
835 | 0 | WABT_TRACE(ParseTextList); |
836 | 0 | if (!ParseTextListOpt(out_data)) { |
837 | | // TODO(binji): Add error message here. |
838 | 0 | return Result::Error; |
839 | 0 | } |
840 | | |
841 | 0 | return Result::Ok; |
842 | 0 | } |
843 | | |
844 | 44.0k | bool WastParser::ParseTextListOpt(std::vector<uint8_t>* out_data) { |
845 | 44.0k | WABT_TRACE(ParseTextListOpt); |
846 | 44.0k | TextVector texts; |
847 | 50.2k | while (PeekMatch(TokenType::Text)) |
848 | 6.16k | texts.push_back(Consume().text()); |
849 | | |
850 | 44.0k | RemoveEscapes(texts, std::back_inserter(*out_data)); |
851 | 44.0k | return !texts.empty(); |
852 | 44.0k | } |
853 | | |
854 | 10.8k | Result WastParser::ParseVarList(VarVector* out_var_list) { |
855 | 10.8k | WABT_TRACE(ParseVarList); |
856 | 10.8k | Var var; |
857 | 287k | while (ParseVarOpt(&var)) { |
858 | 276k | out_var_list->emplace_back(var); |
859 | 276k | } |
860 | 10.8k | if (out_var_list->empty()) { |
861 | 9.72k | return ErrorExpected({"a var"}, "12 or $foo"); |
862 | 9.72k | } else { |
863 | 1.14k | return Result::Ok; |
864 | 1.14k | } |
865 | 10.8k | } |
866 | | |
867 | 4.67k | bool WastParser::ParseElemExprOpt(ExprList* out_elem_expr) { |
868 | 4.67k | WABT_TRACE(ParseElemExprOpt); |
869 | 4.67k | bool item = MatchLpar(TokenType::Item); |
870 | 4.67k | ExprList exprs; |
871 | 4.67k | if (item) { |
872 | 633 | if (ParseTerminatingInstrList(&exprs) != Result::Ok) { |
873 | 197 | return false; |
874 | 197 | } |
875 | 436 | EXPECT(Rpar); |
876 | 4.04k | } else { |
877 | 4.04k | if (!IsExpr(PeekPair()) || ParseExpr(&exprs) != Result::Ok) { |
878 | 2.39k | return false; |
879 | 2.39k | } |
880 | 4.04k | } |
881 | 1.83k | if (!exprs.size()) { |
882 | 194 | return false; |
883 | 194 | } |
884 | 1.64k | *out_elem_expr = std::move(exprs); |
885 | 1.64k | return true; |
886 | 1.83k | } |
887 | | |
888 | 1.92k | bool WastParser::ParseElemExprListOpt(ExprListVector* out_list) { |
889 | 1.92k | ExprList elem_expr; |
890 | 3.61k | while (ParseElemExprOpt(&elem_expr)) { |
891 | 1.69k | out_list->push_back(std::move(elem_expr)); |
892 | 1.69k | } |
893 | 1.92k | return !out_list->empty(); |
894 | 1.92k | } |
895 | | |
896 | 229k | bool WastParser::ParseElemExprVarListOpt(ExprListVector* out_list) { |
897 | 229k | WABT_TRACE(ParseElemExprVarListOpt); |
898 | 229k | Var var; |
899 | 229k | ExprList init_expr; |
900 | 761k | while (ParseVarOpt(&var)) { |
901 | 531k | init_expr.push_back(std::make_unique<RefFuncExpr>(var)); |
902 | 531k | out_list->push_back(std::move(init_expr)); |
903 | 531k | } |
904 | 229k | return !out_list->empty(); |
905 | 229k | } |
906 | | |
907 | 173k | Result WastParser::ParseValueType(Var* out_type) { |
908 | 173k | WABT_TRACE(ParseValueType); |
909 | | |
910 | 173k | const bool is_ref_type = PeekMatchRefType(); |
911 | 173k | const bool is_value_type = PeekMatch(TokenType::ValueType); |
912 | | |
913 | 173k | if (!is_value_type && !is_ref_type) { |
914 | 12.6k | return ErrorExpected( |
915 | 12.6k | {"i32", "i64", "f32", "f64", "v128", "externref", "funcref"}); |
916 | 12.6k | } |
917 | | |
918 | 160k | if (is_ref_type) { |
919 | 0 | EXPECT(Lpar); |
920 | 0 | EXPECT(Ref); |
921 | 0 | CHECK_RESULT(ParseVar(out_type)); |
922 | 0 | EXPECT(Rpar); |
923 | 0 | return Result::Ok; |
924 | 0 | } |
925 | | |
926 | 160k | Token token = Consume(); |
927 | 160k | Type type = token.type(); |
928 | 160k | bool is_enabled; |
929 | 160k | switch (type) { |
930 | 195 | case Type::V128: |
931 | 195 | is_enabled = options_->features.simd_enabled(); |
932 | 195 | break; |
933 | 220 | case Type::FuncRef: |
934 | 416 | case Type::ExternRef: |
935 | 416 | is_enabled = options_->features.reference_types_enabled(); |
936 | 416 | break; |
937 | 160k | default: |
938 | 160k | is_enabled = true; |
939 | 160k | break; |
940 | 160k | } |
941 | | |
942 | 160k | if (!is_enabled) { |
943 | 0 | Error(token.loc, "value type not allowed: %s", type.GetName().c_str()); |
944 | 0 | return Result::Error; |
945 | 0 | } |
946 | | |
947 | 160k | *out_type = Var(type, GetLocation()); |
948 | 160k | return Result::Ok; |
949 | 160k | } |
950 | | |
951 | | Result WastParser::ParseValueTypeList( |
952 | | TypeVector* out_type_list, |
953 | 16.1k | std::unordered_map<uint32_t, std::string>* type_names) { |
954 | 16.1k | WABT_TRACE(ParseValueTypeList); |
955 | 48.1k | while (true) { |
956 | 48.1k | if (!PeekMatchRefType() && !PeekMatch(TokenType::ValueType)) { |
957 | 16.1k | break; |
958 | 16.1k | } |
959 | | |
960 | 32.0k | Var type; |
961 | 32.0k | CHECK_RESULT(ParseValueType(&type)); |
962 | | |
963 | 32.0k | if (type.is_index()) { |
964 | 32.0k | out_type_list->push_back(Type(type.index())); |
965 | 32.0k | } else { |
966 | 0 | assert(type.is_name()); |
967 | 0 | assert(options_->features.function_references_enabled()); |
968 | 0 | type_names->emplace(out_type_list->size(), type.name()); |
969 | 0 | out_type_list->push_back(Type(Type::Reference, kInvalidIndex)); |
970 | 0 | } |
971 | 32.0k | } |
972 | | |
973 | 16.1k | return Result::Ok; |
974 | 16.1k | } |
975 | | |
976 | 1.58k | Result WastParser::ParseRefKind(Type* out_type) { |
977 | 1.58k | WABT_TRACE(ParseRefKind); |
978 | 1.58k | if (!IsTokenTypeRefKind(Peek())) { |
979 | 861 | return ErrorExpected({"func", "extern", "exn"}); |
980 | 861 | } |
981 | | |
982 | 728 | Token token = Consume(); |
983 | 728 | Type type = token.type(); |
984 | | |
985 | 728 | if ((type == Type::ExternRef && |
986 | 728 | !options_->features.reference_types_enabled()) || |
987 | 728 | ((type == Type::Struct || type == Type::Array) && |
988 | 728 | !options_->features.gc_enabled())) { |
989 | 0 | Error(token.loc, "value type not allowed: %s", type.GetName().c_str()); |
990 | 0 | return Result::Error; |
991 | 0 | } |
992 | | |
993 | 728 | *out_type = type; |
994 | 728 | return Result::Ok; |
995 | 728 | } |
996 | | |
997 | 415k | Result WastParser::ParseRefType(Type* out_type) { |
998 | 415k | WABT_TRACE(ParseRefType); |
999 | 415k | if (!PeekMatch(TokenType::ValueType)) { |
1000 | 15.9k | return ErrorExpected({"funcref", "externref"}); |
1001 | 15.9k | } |
1002 | | |
1003 | 399k | Token token = Consume(); |
1004 | 399k | Type type = token.type(); |
1005 | 399k | if (type == Type::ExternRef && |
1006 | 399k | !options_->features.reference_types_enabled()) { |
1007 | 0 | Error(token.loc, "value type not allowed: %s", type.GetName().c_str()); |
1008 | 0 | return Result::Error; |
1009 | 0 | } |
1010 | | |
1011 | 399k | *out_type = type; |
1012 | 399k | return Result::Ok; |
1013 | 399k | } |
1014 | | |
1015 | 230k | bool WastParser::ParseRefTypeOpt(Type* out_type) { |
1016 | 230k | WABT_TRACE(ParseRefTypeOpt); |
1017 | 230k | if (!PeekMatch(TokenType::ValueType)) { |
1018 | 229k | return false; |
1019 | 229k | } |
1020 | | |
1021 | 1.72k | Token token = Consume(); |
1022 | 1.72k | Type type = token.type(); |
1023 | 1.72k | if (type == Type::ExternRef && |
1024 | 1.72k | !options_->features.reference_types_enabled()) { |
1025 | 0 | return false; |
1026 | 0 | } |
1027 | | |
1028 | 1.72k | *out_type = type; |
1029 | 1.72k | return true; |
1030 | 1.72k | } |
1031 | | |
1032 | 474k | Result WastParser::ParseQuotedText(std::string* text, bool check_utf8) { |
1033 | 474k | WABT_TRACE(ParseQuotedText); |
1034 | 474k | if (!PeekMatch(TokenType::Text)) { |
1035 | 26.9k | return ErrorExpected({"a quoted string"}, "\"foo\""); |
1036 | 26.9k | } |
1037 | | |
1038 | 447k | Token token = Consume(); |
1039 | 447k | RemoveEscapes(token.text(), std::back_inserter(*text)); |
1040 | 447k | if (check_utf8 && !IsValidUtf8(text->data(), text->length())) { |
1041 | 96.3k | Error(token.loc, "quoted string has an invalid utf-8 encoding"); |
1042 | 96.3k | } |
1043 | 447k | return Result::Ok; |
1044 | 474k | } |
1045 | | |
1046 | 57.4k | bool WastParser::ParseOffsetOpt(Address* out_offset) { |
1047 | 57.4k | WABT_TRACE(ParseOffsetOpt); |
1048 | 57.4k | if (PeekMatch(TokenType::OffsetEqNat)) { |
1049 | 20.0k | Token token = Consume(); |
1050 | 20.0k | uint64_t offset64; |
1051 | 20.0k | std::string_view sv = token.text(); |
1052 | 20.0k | if (Failed(ParseInt64(sv, &offset64, ParseIntType::SignedAndUnsigned))) { |
1053 | 18.3k | Error(token.loc, "invalid offset \"" PRIstringview "\"", |
1054 | 18.3k | WABT_PRINTF_STRING_VIEW_ARG(sv)); |
1055 | 18.3k | } |
1056 | | // With memory64, offsets > UINT32_MAX for i32 memories are no longer |
1057 | | // malformed (just invalid) |
1058 | 20.0k | if ((!options_->features.memory64_enabled()) && (offset64 > UINT32_MAX)) { |
1059 | 1.09k | Error(token.loc, "offset must be less than or equal to 0xffffffff"); |
1060 | 1.09k | } |
1061 | 20.0k | *out_offset = offset64; |
1062 | 20.0k | return true; |
1063 | 37.3k | } else { |
1064 | 37.3k | *out_offset = 0; |
1065 | 37.3k | return false; |
1066 | 37.3k | } |
1067 | 57.4k | } |
1068 | | |
1069 | 57.4k | bool WastParser::ParseAlignOpt(Address* out_align) { |
1070 | 57.4k | WABT_TRACE(ParseAlignOpt); |
1071 | 57.4k | if (PeekMatch(TokenType::AlignEqNat)) { |
1072 | 3.53k | Token token = Consume(); |
1073 | 3.53k | std::string_view sv = token.text(); |
1074 | 3.53k | if (Failed(ParseInt64(sv, out_align, ParseIntType::UnsignedOnly))) { |
1075 | 393 | Error(token.loc, "invalid alignment \"" PRIstringview "\"", |
1076 | 393 | WABT_PRINTF_STRING_VIEW_ARG(sv)); |
1077 | 393 | } |
1078 | | |
1079 | 3.53k | if (!IsPowerOfTwo(*out_align)) { |
1080 | 1.50k | Error(token.loc, "alignment must be power-of-two"); |
1081 | 1.50k | } |
1082 | | |
1083 | 3.53k | return true; |
1084 | 53.8k | } else { |
1085 | 53.8k | *out_align = WABT_USE_NATURAL_ALIGNMENT; |
1086 | 53.8k | return false; |
1087 | 53.8k | } |
1088 | 57.4k | } |
1089 | | |
1090 | 94.0k | Result WastParser::ParseMemidx(Location loc, Var* out_memidx) { |
1091 | 94.0k | WABT_TRACE(ParseMemidx); |
1092 | 94.0k | if (PeekMatchLpar(TokenType::Memory)) { |
1093 | 1.77k | if (!options_->features.multi_memory_enabled()) { |
1094 | 1.77k | Error(loc, "Specifying memory variable is not allowed"); |
1095 | 1.77k | return Result::Error; |
1096 | 1.77k | } |
1097 | 0 | EXPECT(Lpar); |
1098 | 0 | EXPECT(Memory); |
1099 | 0 | CHECK_RESULT(ParseVar(out_memidx)); |
1100 | 0 | EXPECT(Rpar); |
1101 | 92.2k | } else { |
1102 | 92.2k | if (ParseVarOpt(out_memidx, Var(0, loc)) && |
1103 | 92.2k | !options_->features.multi_memory_enabled()) { |
1104 | 22.6k | Error(loc, "Specifying memory variable is not allowed"); |
1105 | 22.6k | return Result::Error; |
1106 | 22.6k | } |
1107 | 92.2k | } |
1108 | 69.5k | return Result::Ok; |
1109 | 94.0k | } |
1110 | | |
1111 | 784k | Result WastParser::ParseLimitsIndex(Limits* out_limits) { |
1112 | 784k | WABT_TRACE(ParseLimitsIndex); |
1113 | | |
1114 | 784k | if (PeekMatch(TokenType::ValueType)) { |
1115 | 3.01k | if (GetToken().type() == Type::I64) { |
1116 | 886 | Consume(); |
1117 | 886 | out_limits->is_64 = true; |
1118 | 2.12k | } else if (GetToken().type() == Type::I32) { |
1119 | 225 | Consume(); |
1120 | 225 | out_limits->is_64 = false; |
1121 | 225 | } |
1122 | 3.01k | } |
1123 | | |
1124 | 784k | return Result::Ok; |
1125 | 784k | } |
1126 | | |
1127 | 782k | Result WastParser::ParseLimits(Limits* out_limits) { |
1128 | 782k | WABT_TRACE(ParseLimits); |
1129 | | |
1130 | 782k | CHECK_RESULT(ParseNat(&out_limits->initial, out_limits->is_64)); |
1131 | 744k | if (PeekMatch(TokenType::Nat)) { |
1132 | 20.5k | CHECK_RESULT(ParseNat(&out_limits->max, out_limits->is_64)); |
1133 | 20.5k | out_limits->has_max = true; |
1134 | 724k | } else { |
1135 | 724k | out_limits->has_max = false; |
1136 | 724k | } |
1137 | | |
1138 | 744k | if (Match(TokenType::Shared)) { |
1139 | 215 | out_limits->is_shared = true; |
1140 | 215 | } |
1141 | | |
1142 | 744k | return Result::Ok; |
1143 | 744k | } |
1144 | | |
1145 | 802k | Result WastParser::ParseNat(uint64_t* out_nat, bool is_64) { |
1146 | 802k | WABT_TRACE(ParseNat); |
1147 | 802k | if (!PeekMatch(TokenType::Nat)) { |
1148 | 37.4k | return ErrorExpected({"a natural number"}, "123"); |
1149 | 37.4k | } |
1150 | | |
1151 | 765k | Token token = Consume(); |
1152 | 765k | std::string_view sv = token.literal().text; |
1153 | 765k | if (Failed(ParseUint64(sv, out_nat)) || (!is_64 && *out_nat > 0xffffffffu)) { |
1154 | 2.15k | Error(token.loc, "invalid int \"" PRIstringview "\"", |
1155 | 2.15k | WABT_PRINTF_STRING_VIEW_ARG(sv)); |
1156 | 2.15k | } |
1157 | | |
1158 | 765k | return Result::Ok; |
1159 | 802k | } |
1160 | | |
1161 | 22.7k | Result WastParser::ParseModule(std::unique_ptr<Module>* out_module) { |
1162 | 22.7k | WABT_TRACE(ParseModule); |
1163 | 22.7k | auto module = std::make_unique<Module>(); |
1164 | | |
1165 | 22.7k | if (PeekMatchLpar(TokenType::Module)) { |
1166 | | // Starts with "(module". Allow text and binary modules, but no quoted |
1167 | | // modules. |
1168 | 128 | CommandPtr command; |
1169 | 128 | CHECK_RESULT(ParseModuleCommand(nullptr, &command)); |
1170 | 71 | if (isa<ModuleCommand>(command.get())) { |
1171 | 71 | auto module_command = cast<ModuleCommand>(std::move(command)); |
1172 | 71 | *module = std::move(module_command->module); |
1173 | 71 | } else { |
1174 | 0 | assert(isa<ScriptModuleCommand>(command.get())); |
1175 | 0 | auto module_command = cast<ScriptModuleCommand>(std::move(command)); |
1176 | 0 | *module = std::move(module_command->module); |
1177 | 0 | } |
1178 | 22.5k | } else if (IsModuleField(PeekPair()) || PeekIsCustom()) { |
1179 | | // Parse an inline module (i.e. one with no surrounding (module)). |
1180 | 20.5k | CHECK_RESULT(ParseModuleFieldList(module.get())); |
1181 | 20.5k | } else if (PeekMatch(TokenType::Eof)) { |
1182 | 679 | errors_->emplace_back(ErrorLevel::Warning, GetLocation(), "empty module"); |
1183 | 1.31k | } else { |
1184 | 1.31k | ConsumeIfLpar(); |
1185 | 1.31k | ErrorExpected({"a module field", "a module"}); |
1186 | 1.31k | } |
1187 | | |
1188 | 4.26k | EXPECT(Eof); |
1189 | 3.38k | if (!HasError()) { |
1190 | 1.66k | *out_module = std::move(module); |
1191 | 1.66k | return Result::Ok; |
1192 | 1.71k | } else { |
1193 | 1.71k | return Result::Error; |
1194 | 1.71k | } |
1195 | 3.38k | } |
1196 | | |
1197 | 0 | Result WastParser::ParseScript(std::unique_ptr<Script>* out_script) { |
1198 | 0 | WABT_TRACE(ParseScript); |
1199 | 0 | auto script = std::make_unique<Script>(); |
1200 | | |
1201 | | // Don't consume the Lpar yet, even though it is required. This way the |
1202 | | // sub-parser functions (e.g. ParseFuncModuleField) can consume it and keep |
1203 | | // the parsing structure more regular. |
1204 | 0 | if (IsModuleField(PeekPair()) || PeekIsCustom()) { |
1205 | | // Parse an inline module (i.e. one with no surrounding (module)). |
1206 | 0 | auto command = std::make_unique<ModuleCommand>(); |
1207 | 0 | command->module.loc = GetLocation(); |
1208 | 0 | CHECK_RESULT(ParseModuleFieldList(&command->module)); |
1209 | 0 | script->commands.emplace_back(std::move(command)); |
1210 | 0 | } else if (IsCommand(PeekPair())) { |
1211 | 0 | CHECK_RESULT(ParseCommandList(script.get(), &script->commands)); |
1212 | 0 | } else if (PeekMatch(TokenType::Eof)) { |
1213 | 0 | errors_->emplace_back(ErrorLevel::Warning, GetLocation(), "empty script"); |
1214 | 0 | } else { |
1215 | 0 | ConsumeIfLpar(); |
1216 | 0 | ErrorExpected({"a module field", "a command"}); |
1217 | 0 | } |
1218 | | |
1219 | 0 | EXPECT(Eof); |
1220 | 0 | if (!HasError()) { |
1221 | 0 | *out_script = std::move(script); |
1222 | 0 | return Result::Ok; |
1223 | 0 | } else { |
1224 | 0 | return Result::Error; |
1225 | 0 | } |
1226 | 0 | } |
1227 | | |
1228 | 0 | Result WastParser::ParseCustomSectionAnnotation(Module* module) { |
1229 | 0 | WABT_TRACE(ParseCustomSectionAnnotation); |
1230 | 0 | Location loc = GetLocation(); |
1231 | 0 | Token token = Consume(); |
1232 | 0 | if (token.text() != "custom") { |
1233 | 0 | assert( |
1234 | 0 | !"ParseCustomSectionAnnotation should only be called if PeekIsCustom() is true"); |
1235 | 0 | return Result::Error; |
1236 | 0 | } |
1237 | 0 | std::string section_name; |
1238 | 0 | CHECK_RESULT(ParseQuotedText(§ion_name)); |
1239 | 0 | if (Match(TokenType::Lpar)) { |
1240 | 0 | if (!PeekMatch(TokenType::After) && !PeekMatch(TokenType::Before)) { |
1241 | 0 | return ErrorExpected({"before", "after"}); |
1242 | 0 | } |
1243 | 0 | Consume(); |
1244 | 0 | switch (Peek()) { |
1245 | 0 | case TokenType::Function: |
1246 | 0 | case TokenType::Type: |
1247 | 0 | case TokenType::Import: |
1248 | 0 | case TokenType::Export: |
1249 | 0 | case TokenType::Table: |
1250 | 0 | case TokenType::Global: |
1251 | 0 | case TokenType::Elem: |
1252 | 0 | case TokenType::Data: |
1253 | 0 | case TokenType::Memory: |
1254 | 0 | case TokenType::Code: |
1255 | 0 | case TokenType::Start: { |
1256 | 0 | Consume(); |
1257 | 0 | break; |
1258 | 0 | } |
1259 | 0 | default: { |
1260 | 0 | return ErrorExpected({"type", "import", "function", "table", "memory", |
1261 | 0 | "global", "export", "start", "elem", "code", |
1262 | 0 | "data"}); |
1263 | 0 | } |
1264 | 0 | } |
1265 | 0 | EXPECT(Rpar); |
1266 | 0 | } |
1267 | 0 | std::vector<uint8_t> data; |
1268 | 0 | CHECK_RESULT(ParseTextList(&data)); |
1269 | 0 | EXPECT(Rpar); |
1270 | | |
1271 | 0 | Custom custom = Custom(loc, section_name, data); |
1272 | 0 | module->customs.push_back(custom); |
1273 | |
|
1274 | 0 | return Result::Ok; |
1275 | 0 | } |
1276 | | |
1277 | 3.59M | bool WastParser::PeekIsCustom() { |
1278 | | // If IsLparAnn succeeds, tokens_.front() must have text, as it is an LparAnn |
1279 | | // token. |
1280 | 3.59M | return options_->features.annotations_enabled() && IsLparAnn(PeekPair()) && |
1281 | 3.59M | tokens_.front().text() == "custom"; |
1282 | 3.59M | } |
1283 | | |
1284 | 20.7k | Result WastParser::ParseModuleFieldList(Module* module) { |
1285 | 20.7k | WABT_TRACE(ParseModuleFieldList); |
1286 | 3.59M | while (IsModuleField(PeekPair()) || PeekIsCustom()) { |
1287 | 3.58M | if (PeekIsCustom()) { |
1288 | 0 | CHECK_RESULT(ParseCustomSectionAnnotation(module)); |
1289 | 0 | continue; |
1290 | 0 | } |
1291 | 3.58M | if (Failed(ParseModuleField(module))) { |
1292 | 2.81M | CHECK_RESULT(Synchronize(IsModuleField)); |
1293 | 2.81M | } |
1294 | 3.58M | } |
1295 | 7.25k | CHECK_RESULT(ResolveFuncTypes(module, errors_)); |
1296 | 6.99k | CHECK_RESULT(ResolveNamesModule(module, errors_)); |
1297 | 2.27k | return Result::Ok; |
1298 | 6.99k | } |
1299 | | |
1300 | 3.58M | Result WastParser::ParseModuleField(Module* module) { |
1301 | 3.58M | WABT_TRACE(ParseModuleField); |
1302 | 3.58M | switch (Peek(1)) { |
1303 | 77.4k | case TokenType::Data: return ParseDataModuleField(module); |
1304 | 231k | case TokenType::Elem: return ParseElemModuleField(module); |
1305 | 80.8k | case TokenType::Tag: return ParseTagModuleField(module); |
1306 | 53.4k | case TokenType::Export: return ParseExportModuleField(module); |
1307 | 2.17M | case TokenType::Func: return ParseFuncModuleField(module); |
1308 | 50.1k | case TokenType::Type: return ParseTypeModuleField(module); |
1309 | 68.8k | case TokenType::Global: return ParseGlobalModuleField(module); |
1310 | 70.4k | case TokenType::Import: return ParseImportModuleField(module); |
1311 | 347k | case TokenType::Memory: return ParseMemoryModuleField(module); |
1312 | 1.26k | case TokenType::Start: return ParseStartModuleField(module); |
1313 | 432k | case TokenType::Table: return ParseTableModuleField(module); |
1314 | 0 | default: |
1315 | 0 | assert( |
1316 | 0 | !"ParseModuleField should only be called if IsModuleField() is true"); |
1317 | 0 | return Result::Error; |
1318 | 3.58M | } |
1319 | 3.58M | } |
1320 | | |
1321 | 77.4k | Result WastParser::ParseDataModuleField(Module* module) { |
1322 | 77.4k | WABT_TRACE(ParseDataModuleField); |
1323 | 77.4k | EXPECT(Lpar); |
1324 | 77.4k | Location loc = GetLocation(); |
1325 | 77.4k | EXPECT(Data); |
1326 | 77.4k | std::string name; |
1327 | 77.4k | ParseBindVarOpt(&name); |
1328 | 77.4k | auto field = std::make_unique<DataSegmentModuleField>(loc, name); |
1329 | | |
1330 | 77.4k | if (PeekMatchLpar(TokenType::Memory)) { |
1331 | 31.5k | EXPECT(Lpar); |
1332 | 31.5k | EXPECT(Memory); |
1333 | 31.5k | CHECK_RESULT(ParseVar(&field->data_segment.memory_var)); |
1334 | 29.9k | EXPECT(Rpar); |
1335 | 528 | CHECK_RESULT(ParseOffsetExpr(&field->data_segment.offset)); |
1336 | 45.9k | } else if (ParseVarOpt(&field->data_segment.memory_var, Var(0, loc))) { |
1337 | 3.65k | CHECK_RESULT(ParseOffsetExpr(&field->data_segment.offset)); |
1338 | 42.2k | } else if (!ParseOffsetExprOpt(&field->data_segment.offset)) { |
1339 | 41.1k | if (!options_->features.bulk_memory_enabled()) { |
1340 | 0 | Error(loc, "passive data segments are not allowed"); |
1341 | 0 | return Result::Error; |
1342 | 0 | } |
1343 | | |
1344 | 41.1k | field->data_segment.kind = SegmentKind::Passive; |
1345 | 41.1k | } |
1346 | | |
1347 | 43.4k | ParseTextListOpt(&field->data_segment.data); |
1348 | 43.4k | EXPECT(Rpar); |
1349 | 21.6k | module->AppendField(std::move(field)); |
1350 | 21.6k | return Result::Ok; |
1351 | 43.4k | } |
1352 | | |
1353 | 231k | Result WastParser::ParseElemModuleField(Module* module) { |
1354 | 231k | WABT_TRACE(ParseElemModuleField); |
1355 | 231k | EXPECT(Lpar); |
1356 | 231k | Location loc = GetLocation(); |
1357 | 231k | EXPECT(Elem); |
1358 | | |
1359 | | // With MVP text format the name here was intended to refer to the table |
1360 | | // that the elem segment was part of, but we never did anything with this name |
1361 | | // since there was only one table anyway. |
1362 | | // With bulk-memory enabled this introduces a new name for the particular |
1363 | | // elem segment. |
1364 | 231k | std::string initial_name; |
1365 | 231k | bool has_name = ParseBindVarOpt(&initial_name); |
1366 | | |
1367 | 231k | std::string segment_name = initial_name; |
1368 | 231k | if (!options_->features.bulk_memory_enabled()) { |
1369 | 0 | segment_name = ""; |
1370 | 0 | } |
1371 | 231k | auto field = std::make_unique<ElemSegmentModuleField>(loc, segment_name); |
1372 | 231k | if (options_->features.reference_types_enabled() && |
1373 | 231k | Match(TokenType::Declare)) { |
1374 | 194 | field->elem_segment.kind = SegmentKind::Declared; |
1375 | 194 | } |
1376 | | |
1377 | | // Optional table specifier |
1378 | 231k | if (options_->features.bulk_memory_enabled()) { |
1379 | 231k | if (PeekMatchLpar(TokenType::Table)) { |
1380 | 711 | EXPECT(Lpar); |
1381 | 711 | EXPECT(Table); |
1382 | 711 | CHECK_RESULT(ParseVar(&field->elem_segment.table_var)); |
1383 | 512 | EXPECT(Rpar); |
1384 | 230k | } else { |
1385 | 230k | ParseVarOpt(&field->elem_segment.table_var, Var(0, loc)); |
1386 | 230k | } |
1387 | 231k | } else { |
1388 | 0 | if (has_name) { |
1389 | 0 | field->elem_segment.table_var = Var(initial_name, loc); |
1390 | 0 | } else { |
1391 | 0 | ParseVarOpt(&field->elem_segment.table_var, Var(0, loc)); |
1392 | 0 | } |
1393 | 0 | } |
1394 | | |
1395 | | // Parse offset expression, if not declared/passive segment. |
1396 | 230k | if (options_->features.bulk_memory_enabled()) { |
1397 | 230k | if (field->elem_segment.kind != SegmentKind::Declared && |
1398 | 230k | !ParseOffsetExprOpt(&field->elem_segment.offset)) { |
1399 | 229k | field->elem_segment.kind = SegmentKind::Passive; |
1400 | 229k | } |
1401 | 230k | } else { |
1402 | 0 | CHECK_RESULT(ParseOffsetExpr(&field->elem_segment.offset)); |
1403 | 0 | } |
1404 | | |
1405 | 230k | if (ParseRefTypeOpt(&field->elem_segment.elem_type)) { |
1406 | 1.72k | ParseElemExprListOpt(&field->elem_segment.elem_exprs); |
1407 | 229k | } else { |
1408 | 229k | field->elem_segment.elem_type = Type::FuncRef; |
1409 | 229k | if (PeekMatch(TokenType::Func)) { |
1410 | 263 | EXPECT(Func); |
1411 | 263 | } |
1412 | 229k | ParseElemExprVarListOpt(&field->elem_segment.elem_exprs); |
1413 | 229k | } |
1414 | 230k | EXPECT(Rpar); |
1415 | 215k | module->AppendField(std::move(field)); |
1416 | 215k | return Result::Ok; |
1417 | 230k | } |
1418 | | |
1419 | 80.8k | Result WastParser::ParseTagModuleField(Module* module) { |
1420 | 80.8k | WABT_TRACE(ParseTagModuleField); |
1421 | 80.8k | if (!options_->features.exceptions_enabled()) { |
1422 | 80.8k | Error(Consume().loc, "tag not allowed"); |
1423 | 80.8k | return Result::Error; |
1424 | 80.8k | } |
1425 | 0 | EXPECT(Lpar); |
1426 | 0 | EXPECT(Tag); |
1427 | 0 | Location loc = GetLocation(); |
1428 | |
|
1429 | 0 | std::string name; |
1430 | 0 | ParseBindVarOpt(&name); |
1431 | |
|
1432 | 0 | ModuleFieldList export_fields; |
1433 | 0 | CHECK_RESULT(ParseInlineExports(&export_fields, ExternalKind::Tag)); |
1434 | | |
1435 | 0 | if (PeekMatchLpar(TokenType::Import)) { |
1436 | 0 | CheckImportOrdering(module); |
1437 | 0 | auto import = std::make_unique<TagImport>(name); |
1438 | 0 | Tag& tag = import->tag; |
1439 | 0 | CHECK_RESULT(ParseInlineImport(import.get())); |
1440 | 0 | CHECK_RESULT(ParseTypeUseOpt(&tag.decl)); |
1441 | 0 | CHECK_RESULT(ParseUnboundFuncSignature(&tag.decl.sig)); |
1442 | 0 | CHECK_RESULT(ErrorIfLpar({"type", "param", "result"})); |
1443 | 0 | auto field = |
1444 | 0 | std::make_unique<ImportModuleField>(std::move(import), GetLocation()); |
1445 | 0 | module->AppendField(std::move(field)); |
1446 | 0 | } else { |
1447 | 0 | auto field = std::make_unique<TagModuleField>(loc, name); |
1448 | 0 | CHECK_RESULT(ParseTypeUseOpt(&field->tag.decl)); |
1449 | 0 | CHECK_RESULT(ParseUnboundFuncSignature(&field->tag.decl.sig)); |
1450 | 0 | module->AppendField(std::move(field)); |
1451 | 0 | } |
1452 | | |
1453 | 0 | AppendInlineExportFields(module, &export_fields, module->tags.size() - 1); |
1454 | |
|
1455 | 0 | EXPECT(Rpar); |
1456 | 0 | return Result::Ok; |
1457 | 0 | } |
1458 | | |
1459 | 53.4k | Result WastParser::ParseExportModuleField(Module* module) { |
1460 | 53.4k | WABT_TRACE(ParseExportModuleField); |
1461 | 53.4k | EXPECT(Lpar); |
1462 | 53.4k | auto field = std::make_unique<ExportModuleField>(GetLocation()); |
1463 | 53.4k | EXPECT(Export); |
1464 | 53.4k | CHECK_RESULT(ParseQuotedText(&field->export_.name)); |
1465 | 48.8k | CHECK_RESULT(ParseExportDesc(&field->export_)); |
1466 | 15.0k | EXPECT(Rpar); |
1467 | 14.6k | module->AppendField(std::move(field)); |
1468 | 14.6k | return Result::Ok; |
1469 | 15.0k | } |
1470 | | |
1471 | 2.17M | Result WastParser::ParseFuncModuleField(Module* module) { |
1472 | 2.17M | WABT_TRACE(ParseFuncModuleField); |
1473 | 2.17M | EXPECT(Lpar); |
1474 | 2.17M | Location loc = GetLocation(); |
1475 | 2.17M | EXPECT(Func); |
1476 | 2.17M | std::string name; |
1477 | 2.17M | ParseBindVarOpt(&name); |
1478 | | |
1479 | 2.17M | ModuleFieldList export_fields; |
1480 | 2.17M | CHECK_RESULT(ParseInlineExports(&export_fields, ExternalKind::Func)); |
1481 | | |
1482 | 2.16M | if (PeekMatchLpar(TokenType::Import)) { |
1483 | 46.9k | CheckImportOrdering(module); |
1484 | 46.9k | auto import = std::make_unique<FuncImport>(name); |
1485 | 46.9k | Func& func = import->func; |
1486 | 46.9k | CHECK_RESULT(ParseInlineImport(import.get())); |
1487 | 44.7k | CHECK_RESULT(ParseTypeUseOpt(&func.decl)); |
1488 | 44.0k | CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings)); |
1489 | 43.8k | CHECK_RESULT(ErrorIfLpar({"type", "param", "result"})); |
1490 | 43.4k | auto field = |
1491 | 43.4k | std::make_unique<ImportModuleField>(std::move(import), GetLocation()); |
1492 | 43.4k | module->AppendField(std::move(field)); |
1493 | 2.12M | } else { |
1494 | 2.12M | auto field = std::make_unique<FuncModuleField>(loc, name); |
1495 | 2.12M | Func& func = field->func; |
1496 | 2.12M | func.loc = GetLocation(); |
1497 | 2.12M | CHECK_RESULT(ParseTypeUseOpt(&func.decl)); |
1498 | 2.12M | CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings)); |
1499 | 2.12M | TypeVector local_types; |
1500 | 2.12M | CHECK_RESULT(ParseBoundValueTypeList( |
1501 | 2.12M | TokenType::Local, &local_types, &func.bindings, |
1502 | 2.12M | &func.decl.sig.param_type_names, func.GetNumParams())); |
1503 | 2.11M | func.local_types.Set(local_types); |
1504 | 2.11M | CHECK_RESULT(ParseTerminatingInstrList(&func.exprs)); |
1505 | 1.98M | module->AppendField(std::move(field)); |
1506 | 1.98M | } |
1507 | | |
1508 | 2.03M | AppendInlineExportFields(module, &export_fields, module->funcs.size() - 1); |
1509 | | |
1510 | 2.03M | EXPECT(Rpar); |
1511 | 427k | return Result::Ok; |
1512 | 2.03M | } |
1513 | | |
1514 | 50.1k | Result WastParser::ParseTypeModuleField(Module* module) { |
1515 | 50.1k | WABT_TRACE(ParseTypeModuleField); |
1516 | 50.1k | EXPECT(Lpar); |
1517 | 50.1k | auto field = std::make_unique<TypeModuleField>(GetLocation()); |
1518 | 50.1k | EXPECT(Type); |
1519 | | |
1520 | 50.1k | std::string name; |
1521 | 50.1k | ParseBindVarOpt(&name); |
1522 | 50.1k | EXPECT(Lpar); |
1523 | 45.8k | Location loc = GetLocation(); |
1524 | | |
1525 | 45.8k | if (Match(TokenType::Func)) { |
1526 | 38.1k | auto func_type = std::make_unique<FuncType>(name); |
1527 | 38.1k | BindingHash bindings; |
1528 | 38.1k | CHECK_RESULT(ParseFuncSignature(&func_type->sig, &bindings)); |
1529 | 37.4k | CHECK_RESULT(ErrorIfLpar({"param", "result"})); |
1530 | 37.1k | field->type = std::move(func_type); |
1531 | 37.1k | } else if (Match(TokenType::Struct)) { |
1532 | 0 | if (!options_->features.gc_enabled()) { |
1533 | 0 | Error(loc, "struct not allowed"); |
1534 | 0 | return Result::Error; |
1535 | 0 | } |
1536 | 0 | auto struct_type = std::make_unique<StructType>(name); |
1537 | 0 | CHECK_RESULT(ParseFieldList(&struct_type->fields)); |
1538 | 0 | field->type = std::move(struct_type); |
1539 | 7.65k | } else if (Match(TokenType::Array)) { |
1540 | 0 | if (!options_->features.gc_enabled()) { |
1541 | 0 | Error(loc, "array type not allowed"); |
1542 | 0 | } |
1543 | 0 | auto array_type = std::make_unique<ArrayType>(name); |
1544 | 0 | CHECK_RESULT(ParseField(&array_type->field)); |
1545 | 0 | field->type = std::move(array_type); |
1546 | 7.65k | } else { |
1547 | 7.65k | return ErrorExpected({"func", "struct", "array"}); |
1548 | 7.65k | } |
1549 | | |
1550 | 37.1k | EXPECT(Rpar); |
1551 | 27.3k | EXPECT(Rpar); |
1552 | 26.7k | module->AppendField(std::move(field)); |
1553 | 26.7k | return Result::Ok; |
1554 | 27.3k | } |
1555 | | |
1556 | 0 | Result WastParser::ParseField(Field* field) { |
1557 | 0 | WABT_TRACE(ParseField); |
1558 | 0 | auto parse_mut_valuetype = [&]() -> Result { |
1559 | | // TODO: Share with ParseGlobalType? |
1560 | 0 | if (MatchLpar(TokenType::Mut)) { |
1561 | 0 | field->mutable_ = true; |
1562 | 0 | Var type; |
1563 | 0 | CHECK_RESULT(ParseValueType(&type)); |
1564 | 0 | field->type = Type(type.index()); |
1565 | 0 | EXPECT(Rpar); |
1566 | 0 | } else { |
1567 | 0 | field->mutable_ = false; |
1568 | 0 | Var type; |
1569 | 0 | CHECK_RESULT(ParseValueType(&type)); |
1570 | 0 | field->type = Type(type.index()); |
1571 | 0 | } |
1572 | 0 | return Result::Ok; |
1573 | 0 | }; |
1574 | |
|
1575 | 0 | if (MatchLpar(TokenType::Field)) { |
1576 | 0 | ParseBindVarOpt(&field->name); |
1577 | 0 | CHECK_RESULT(parse_mut_valuetype()); |
1578 | 0 | EXPECT(Rpar); |
1579 | 0 | } else { |
1580 | 0 | CHECK_RESULT(parse_mut_valuetype()); |
1581 | 0 | } |
1582 | | |
1583 | 0 | return Result::Ok; |
1584 | 0 | } |
1585 | | |
1586 | 0 | Result WastParser::ParseFieldList(std::vector<Field>* fields) { |
1587 | 0 | WABT_TRACE(ParseFieldList); |
1588 | 0 | while (PeekMatch(TokenType::ValueType) || PeekMatch(TokenType::Lpar)) { |
1589 | 0 | Field field; |
1590 | 0 | CHECK_RESULT(ParseField(&field)); |
1591 | 0 | fields->push_back(field); |
1592 | 0 | } |
1593 | 0 | return Result::Ok; |
1594 | 0 | } |
1595 | | |
1596 | 68.8k | Result WastParser::ParseGlobalModuleField(Module* module) { |
1597 | 68.8k | WABT_TRACE(ParseGlobalModuleField); |
1598 | 68.8k | EXPECT(Lpar); |
1599 | 68.8k | Location loc = GetLocation(); |
1600 | 68.8k | EXPECT(Global); |
1601 | 68.8k | std::string name; |
1602 | 68.8k | ParseBindVarOpt(&name); |
1603 | | |
1604 | 68.8k | ModuleFieldList export_fields; |
1605 | 68.8k | CHECK_RESULT(ParseInlineExports(&export_fields, ExternalKind::Global)); |
1606 | | |
1607 | 68.6k | if (PeekMatchLpar(TokenType::Import)) { |
1608 | 2.91k | CheckImportOrdering(module); |
1609 | 2.91k | auto import = std::make_unique<GlobalImport>(name); |
1610 | 2.91k | CHECK_RESULT(ParseInlineImport(import.get())); |
1611 | 402 | CHECK_RESULT(ParseGlobalType(&import->global)); |
1612 | 205 | auto field = |
1613 | 205 | std::make_unique<ImportModuleField>(std::move(import), GetLocation()); |
1614 | 205 | module->AppendField(std::move(field)); |
1615 | 65.7k | } else { |
1616 | 65.7k | auto field = std::make_unique<GlobalModuleField>(loc, name); |
1617 | 65.7k | CHECK_RESULT(ParseGlobalType(&field->global)); |
1618 | 56.0k | CHECK_RESULT(ParseTerminatingInstrList(&field->global.init_expr)); |
1619 | 54.7k | module->AppendField(std::move(field)); |
1620 | 54.7k | } |
1621 | | |
1622 | 54.9k | AppendInlineExportFields(module, &export_fields, module->globals.size() - 1); |
1623 | | |
1624 | 54.9k | EXPECT(Rpar); |
1625 | 51.9k | return Result::Ok; |
1626 | 54.9k | } |
1627 | | |
1628 | 70.4k | Result WastParser::ParseImportModuleField(Module* module) { |
1629 | 70.4k | WABT_TRACE(ParseImportModuleField); |
1630 | 70.4k | EXPECT(Lpar); |
1631 | 70.4k | Location loc = GetLocation(); |
1632 | 70.4k | CheckImportOrdering(module); |
1633 | 70.4k | EXPECT(Import); |
1634 | 70.4k | std::string module_name; |
1635 | 70.4k | std::string field_name; |
1636 | 70.4k | CHECK_RESULT(ParseQuotedText(&module_name)); |
1637 | 67.2k | CHECK_RESULT(ParseQuotedText(&field_name)); |
1638 | 56.6k | EXPECT(Lpar); |
1639 | | |
1640 | 38.9k | std::unique_ptr<ImportModuleField> field; |
1641 | 38.9k | std::string name; |
1642 | | |
1643 | 38.9k | switch (Peek()) { |
1644 | 2.33k | case TokenType::Func: { |
1645 | 2.33k | Consume(); |
1646 | 2.33k | ParseBindVarOpt(&name); |
1647 | 2.33k | auto import = std::make_unique<FuncImport>(name); |
1648 | 2.33k | CHECK_RESULT(ParseTypeUseOpt(&import->func.decl)); |
1649 | 2.13k | CHECK_RESULT( |
1650 | 2.13k | ParseFuncSignature(&import->func.decl.sig, &import->func.bindings)); |
1651 | 1.93k | CHECK_RESULT(ErrorIfLpar({"param", "result"})); |
1652 | 1.58k | EXPECT(Rpar); |
1653 | 647 | field = std::make_unique<ImportModuleField>(std::move(import), loc); |
1654 | 647 | break; |
1655 | 1.58k | } |
1656 | | |
1657 | 6.14k | case TokenType::Table: { |
1658 | 6.14k | Consume(); |
1659 | 6.14k | ParseBindVarOpt(&name); |
1660 | 6.14k | auto import = std::make_unique<TableImport>(name); |
1661 | 6.14k | CHECK_RESULT(ParseLimitsIndex(&import->table.elem_limits)); |
1662 | 6.14k | CHECK_RESULT(ParseLimits(&import->table.elem_limits)); |
1663 | 5.45k | CHECK_RESULT(ParseRefType(&import->table.elem_type)); |
1664 | 5.16k | EXPECT(Rpar); |
1665 | 495 | field = std::make_unique<ImportModuleField>(std::move(import), loc); |
1666 | 495 | break; |
1667 | 5.16k | } |
1668 | | |
1669 | 3.95k | case TokenType::Memory: { |
1670 | 3.95k | Consume(); |
1671 | 3.95k | ParseBindVarOpt(&name); |
1672 | 3.95k | auto import = std::make_unique<MemoryImport>(name); |
1673 | 3.95k | CHECK_RESULT(ParseLimitsIndex(&import->memory.page_limits)); |
1674 | 3.95k | CHECK_RESULT(ParseLimits(&import->memory.page_limits)); |
1675 | 404 | EXPECT(Rpar); |
1676 | 201 | field = std::make_unique<ImportModuleField>(std::move(import), loc); |
1677 | 201 | break; |
1678 | 404 | } |
1679 | | |
1680 | 2.53k | case TokenType::Global: { |
1681 | 2.53k | Consume(); |
1682 | 2.53k | ParseBindVarOpt(&name); |
1683 | 2.53k | auto import = std::make_unique<GlobalImport>(name); |
1684 | 2.53k | CHECK_RESULT(ParseGlobalType(&import->global)); |
1685 | 675 | EXPECT(Rpar); |
1686 | 481 | field = std::make_unique<ImportModuleField>(std::move(import), loc); |
1687 | 481 | break; |
1688 | 675 | } |
1689 | | |
1690 | 22.3k | case TokenType::Tag: { |
1691 | 22.3k | Consume(); |
1692 | 22.3k | ParseBindVarOpt(&name); |
1693 | 22.3k | auto import = std::make_unique<TagImport>(name); |
1694 | 22.3k | CHECK_RESULT(ParseTypeUseOpt(&import->tag.decl)); |
1695 | 22.1k | CHECK_RESULT(ParseUnboundFuncSignature(&import->tag.decl.sig)); |
1696 | 21.8k | EXPECT(Rpar); |
1697 | 16.6k | field = std::make_unique<ImportModuleField>(std::move(import), loc); |
1698 | 16.6k | break; |
1699 | 21.8k | } |
1700 | | |
1701 | 1.65k | default: |
1702 | 1.65k | return ErrorExpected({"an external kind"}); |
1703 | 38.9k | } |
1704 | | |
1705 | 18.4k | field->import->module_name = module_name; |
1706 | 18.4k | field->import->field_name = field_name; |
1707 | | |
1708 | 18.4k | module->AppendField(std::move(field)); |
1709 | 18.4k | EXPECT(Rpar); |
1710 | 1.30k | return Result::Ok; |
1711 | 18.4k | } |
1712 | | |
1713 | 347k | Result WastParser::ParseMemoryModuleField(Module* module) { |
1714 | 347k | WABT_TRACE(ParseMemoryModuleField); |
1715 | 347k | EXPECT(Lpar); |
1716 | 347k | Location loc = GetLocation(); |
1717 | 347k | EXPECT(Memory); |
1718 | 347k | std::string name; |
1719 | 347k | ParseBindVarOpt(&name); |
1720 | | |
1721 | 347k | ModuleFieldList export_fields; |
1722 | 347k | CHECK_RESULT(ParseInlineExports(&export_fields, ExternalKind::Memory)); |
1723 | | |
1724 | 347k | if (PeekMatchLpar(TokenType::Import)) { |
1725 | 3.05k | CheckImportOrdering(module); |
1726 | 3.05k | auto import = std::make_unique<MemoryImport>(name); |
1727 | 3.05k | CHECK_RESULT(ParseInlineImport(import.get())); |
1728 | 831 | CHECK_RESULT(ParseLimitsIndex(&import->memory.page_limits)); |
1729 | 831 | CHECK_RESULT(ParseLimits(&import->memory.page_limits)); |
1730 | 493 | auto field = |
1731 | 493 | std::make_unique<ImportModuleField>(std::move(import), GetLocation()); |
1732 | 493 | module->AppendField(std::move(field)); |
1733 | 343k | } else { |
1734 | 343k | auto field = std::make_unique<MemoryModuleField>(loc, name); |
1735 | 343k | CHECK_RESULT(ParseLimitsIndex(&field->memory.page_limits)); |
1736 | 343k | if (MatchLpar(TokenType::Data)) { |
1737 | 627 | auto data_segment_field = std::make_unique<DataSegmentModuleField>(loc); |
1738 | 627 | DataSegment& data_segment = data_segment_field->data_segment; |
1739 | 627 | data_segment.memory_var = Var(module->memories.size(), GetLocation()); |
1740 | 627 | data_segment.offset.push_back(std::make_unique<ConstExpr>( |
1741 | 627 | field->memory.page_limits.is_64 ? Const::I64(0) : Const::I32(0))); |
1742 | 627 | data_segment.offset.back().loc = loc; |
1743 | 627 | ParseTextListOpt(&data_segment.data); |
1744 | 627 | EXPECT(Rpar); |
1745 | | |
1746 | 245 | uint32_t byte_size = WABT_ALIGN_UP_TO_PAGE(data_segment.data.size()); |
1747 | 245 | uint32_t page_size = WABT_BYTES_TO_PAGES(byte_size); |
1748 | 245 | field->memory.page_limits.initial = page_size; |
1749 | 245 | field->memory.page_limits.max = page_size; |
1750 | 245 | field->memory.page_limits.has_max = true; |
1751 | | |
1752 | 245 | module->AppendField(std::move(field)); |
1753 | 245 | module->AppendField(std::move(data_segment_field)); |
1754 | 343k | } else { |
1755 | 343k | CHECK_RESULT(ParseLimits(&field->memory.page_limits)); |
1756 | 330k | module->AppendField(std::move(field)); |
1757 | 330k | } |
1758 | 343k | } |
1759 | | |
1760 | 330k | AppendInlineExportFields(module, &export_fields, module->memories.size() - 1); |
1761 | | |
1762 | 330k | EXPECT(Rpar); |
1763 | 1.11k | return Result::Ok; |
1764 | 330k | } |
1765 | | |
1766 | 1.26k | Result WastParser::ParseStartModuleField(Module* module) { |
1767 | 1.26k | WABT_TRACE(ParseStartModuleField); |
1768 | 1.26k | EXPECT(Lpar); |
1769 | 1.26k | Location loc = GetLocation(); |
1770 | 1.26k | if (module->starts.size() > 0) { |
1771 | 729 | Error(loc, "multiple start sections"); |
1772 | 729 | return Result::Error; |
1773 | 729 | } |
1774 | 534 | EXPECT(Start); |
1775 | 534 | Var var; |
1776 | 534 | CHECK_RESULT(ParseVar(&var)); |
1777 | 308 | EXPECT(Rpar); |
1778 | 84 | module->AppendField(std::make_unique<StartModuleField>(var, loc)); |
1779 | 84 | return Result::Ok; |
1780 | 308 | } |
1781 | | |
1782 | 432k | Result WastParser::ParseTableModuleField(Module* module) { |
1783 | 432k | WABT_TRACE(ParseTableModuleField); |
1784 | 432k | EXPECT(Lpar); |
1785 | 432k | Location loc = GetLocation(); |
1786 | 432k | EXPECT(Table); |
1787 | 432k | std::string name; |
1788 | 432k | ParseBindVarOpt(&name); |
1789 | | |
1790 | 432k | ModuleFieldList export_fields; |
1791 | 432k | CHECK_RESULT(ParseInlineExports(&export_fields, ExternalKind::Table)); |
1792 | | |
1793 | 432k | if (PeekMatchLpar(TokenType::Import)) { |
1794 | 51.6k | CheckImportOrdering(module); |
1795 | 51.6k | auto import = std::make_unique<TableImport>(name); |
1796 | 51.6k | CHECK_RESULT(ParseInlineImport(import.get())); |
1797 | 49.1k | CHECK_RESULT(ParseLimitsIndex(&import->table.elem_limits)); |
1798 | 49.1k | CHECK_RESULT(ParseLimits(&import->table.elem_limits)); |
1799 | 48.8k | CHECK_RESULT(ParseRefType(&import->table.elem_type)); |
1800 | 48.5k | auto field = |
1801 | 48.5k | std::make_unique<ImportModuleField>(std::move(import), GetLocation()); |
1802 | 48.5k | module->AppendField(std::move(field)); |
1803 | 380k | } else { |
1804 | 380k | auto field = std::make_unique<TableModuleField>(loc, name); |
1805 | 380k | auto& table = field->table; |
1806 | 380k | CHECK_RESULT(ParseLimitsIndex(&table.elem_limits)); |
1807 | 380k | if (PeekMatch(TokenType::ValueType)) { |
1808 | 1.81k | Type elem_type; |
1809 | 1.81k | CHECK_RESULT(ParseRefType(&elem_type)); |
1810 | | |
1811 | 1.81k | EXPECT(Lpar); |
1812 | 1.34k | EXPECT(Elem); |
1813 | | |
1814 | 1.06k | auto elem_segment_field = std::make_unique<ElemSegmentModuleField>(loc); |
1815 | 1.06k | ElemSegment& elem_segment = elem_segment_field->elem_segment; |
1816 | 1.06k | elem_segment.table_var = Var(module->tables.size(), GetLocation()); |
1817 | 1.06k | auto offset = table.elem_limits.is_64 ? Const::I64(0) : Const::I32(0); |
1818 | 1.06k | elem_segment.offset.push_back(std::make_unique<ConstExpr>(offset)); |
1819 | 1.06k | elem_segment.offset.back().loc = loc; |
1820 | 1.06k | elem_segment.elem_type = elem_type; |
1821 | | // Syntax is either an optional list of var (legacy), or a non-empty list |
1822 | | // of elem expr. |
1823 | 1.06k | ExprList elem_expr; |
1824 | 1.06k | if (ParseElemExprOpt(&elem_expr)) { |
1825 | 196 | elem_segment.elem_exprs.push_back(std::move(elem_expr)); |
1826 | | // Parse the rest. |
1827 | 196 | ParseElemExprListOpt(&elem_segment.elem_exprs); |
1828 | 864 | } else { |
1829 | 864 | ParseElemExprVarListOpt(&elem_segment.elem_exprs); |
1830 | 864 | } |
1831 | 1.06k | EXPECT(Rpar); |
1832 | | |
1833 | 374 | table.elem_limits.initial = elem_segment.elem_exprs.size(); |
1834 | 374 | table.elem_limits.max = elem_segment.elem_exprs.size(); |
1835 | 374 | table.elem_limits.has_max = true; |
1836 | 374 | table.elem_type = elem_type; |
1837 | 374 | module->AppendField(std::move(field)); |
1838 | 374 | module->AppendField(std::move(elem_segment_field)); |
1839 | 378k | } else { |
1840 | 378k | CHECK_RESULT(ParseLimits(&table.elem_limits)); |
1841 | 359k | CHECK_RESULT(ParseRefType(&table.elem_type)); |
1842 | 344k | module->AppendField(std::move(field)); |
1843 | 344k | } |
1844 | 380k | } |
1845 | | |
1846 | 392k | AppendInlineExportFields(module, &export_fields, module->tables.size() - 1); |
1847 | | |
1848 | 392k | EXPECT(Rpar); |
1849 | 7.07k | return Result::Ok; |
1850 | 392k | } |
1851 | | |
1852 | 48.8k | Result WastParser::ParseExportDesc(Export* export_) { |
1853 | 48.8k | WABT_TRACE(ParseExportDesc); |
1854 | 48.8k | EXPECT(Lpar); |
1855 | 19.8k | switch (Peek()) { |
1856 | 1.46k | case TokenType::Func: export_->kind = ExternalKind::Func; break; |
1857 | 9.08k | case TokenType::Table: export_->kind = ExternalKind::Table; break; |
1858 | 805 | case TokenType::Memory: export_->kind = ExternalKind::Memory; break; |
1859 | 3.63k | case TokenType::Global: export_->kind = ExternalKind::Global; break; |
1860 | 1.42k | case TokenType::Tag: export_->kind = ExternalKind::Tag; break; |
1861 | 3.38k | default: |
1862 | 3.38k | return ErrorExpected({"an external kind"}); |
1863 | 19.8k | } |
1864 | 16.4k | Consume(); |
1865 | 16.4k | CHECK_RESULT(ParseVar(&export_->var)); |
1866 | 15.6k | EXPECT(Rpar); |
1867 | 15.0k | return Result::Ok; |
1868 | 15.6k | } |
1869 | | |
1870 | | Result WastParser::ParseInlineExports(ModuleFieldList* fields, |
1871 | 3.01M | ExternalKind kind) { |
1872 | 3.01M | WABT_TRACE(ParseInlineExports); |
1873 | 3.09M | while (PeekMatchLpar(TokenType::Export)) { |
1874 | 75.4k | EXPECT(Lpar); |
1875 | 75.4k | auto field = std::make_unique<ExportModuleField>(GetLocation()); |
1876 | 75.4k | field->export_.kind = kind; |
1877 | 75.4k | EXPECT(Export); |
1878 | 75.4k | CHECK_RESULT(ParseQuotedText(&field->export_.name)); |
1879 | 74.2k | EXPECT(Rpar); |
1880 | 73.0k | fields->push_back(std::move(field)); |
1881 | 73.0k | } |
1882 | 3.01M | return Result::Ok; |
1883 | 3.01M | } |
1884 | | |
1885 | 104k | Result WastParser::ParseInlineImport(Import* import) { |
1886 | 104k | WABT_TRACE(ParseInlineImport); |
1887 | 104k | EXPECT(Lpar); |
1888 | 104k | EXPECT(Import); |
1889 | 104k | CHECK_RESULT(ParseQuotedText(&import->module_name)); |
1890 | 101k | CHECK_RESULT(ParseQuotedText(&import->field_name)); |
1891 | 97.9k | EXPECT(Rpar); |
1892 | 95.0k | return Result::Ok; |
1893 | 97.9k | } |
1894 | | |
1895 | 2.42M | Result WastParser::ParseTypeUseOpt(FuncDeclaration* decl) { |
1896 | 2.42M | WABT_TRACE(ParseTypeUseOpt); |
1897 | 2.42M | if (MatchLpar(TokenType::Type)) { |
1898 | 24.4k | decl->has_func_type = true; |
1899 | 24.4k | CHECK_RESULT(ParseVar(&decl->type_var)); |
1900 | 15.9k | EXPECT(Rpar); |
1901 | 2.40M | } else { |
1902 | 2.40M | decl->has_func_type = false; |
1903 | 2.40M | } |
1904 | 2.41M | return Result::Ok; |
1905 | 2.42M | } |
1906 | | |
1907 | | Result WastParser::ParseFuncSignature(FuncSignature* sig, |
1908 | 2.20M | BindingHash* param_bindings) { |
1909 | 2.20M | WABT_TRACE(ParseFuncSignature); |
1910 | 2.20M | CHECK_RESULT(ParseBoundValueTypeList(TokenType::Param, &sig->param_types, |
1911 | 2.20M | param_bindings, &sig->param_type_names)); |
1912 | 2.20M | CHECK_RESULT(ParseResultList(&sig->result_types, &sig->result_type_names)); |
1913 | 2.20M | return Result::Ok; |
1914 | 2.20M | } |
1915 | | |
1916 | 246k | Result WastParser::ParseUnboundFuncSignature(FuncSignature* sig) { |
1917 | 246k | WABT_TRACE(ParseUnboundFuncSignature); |
1918 | 246k | CHECK_RESULT(ParseUnboundValueTypeList(TokenType::Param, &sig->param_types, |
1919 | 246k | &sig->param_type_names)); |
1920 | 244k | CHECK_RESULT(ParseResultList(&sig->result_types, &sig->result_type_names)); |
1921 | 244k | return Result::Ok; |
1922 | 244k | } |
1923 | | |
1924 | | Result WastParser::ParseBoundValueTypeList( |
1925 | | TokenType token, |
1926 | | TypeVector* types, |
1927 | | BindingHash* bindings, |
1928 | | std::unordered_map<uint32_t, std::string>* type_names, |
1929 | 4.32M | Index binding_index_offset) { |
1930 | 4.32M | WABT_TRACE(ParseBoundValueTypeList); |
1931 | 4.40M | while (MatchLpar(token)) { |
1932 | 78.2k | if (PeekMatch(TokenType::Var)) { |
1933 | 72.7k | std::string name; |
1934 | 72.7k | Var type; |
1935 | 72.7k | Location loc = GetLocation(); |
1936 | 72.7k | ParseBindVarOpt(&name); |
1937 | 72.7k | CHECK_RESULT(ParseValueType(&type)); |
1938 | 70.9k | bindings->emplace(name, |
1939 | 70.9k | Binding(loc, binding_index_offset + types->size())); |
1940 | 70.9k | if (type.is_index()) { |
1941 | 70.9k | types->push_back(Type(type.index())); |
1942 | 70.9k | } else { |
1943 | 0 | assert(type.is_name()); |
1944 | 0 | assert(options_->features.function_references_enabled()); |
1945 | 0 | type_names->emplace(binding_index_offset + types->size(), type.name()); |
1946 | 0 | types->push_back(Type(Type::Reference, kInvalidIndex)); |
1947 | 0 | } |
1948 | 70.9k | } else { |
1949 | 5.42k | CHECK_RESULT(ParseValueTypeList(types, type_names)); |
1950 | 5.42k | } |
1951 | 76.4k | EXPECT(Rpar); |
1952 | 76.4k | } |
1953 | 4.32M | return Result::Ok; |
1954 | 4.32M | } |
1955 | | |
1956 | | Result WastParser::ParseUnboundValueTypeList( |
1957 | | TokenType token, |
1958 | | TypeVector* types, |
1959 | 2.69M | std::unordered_map<uint32_t, std::string>* type_names) { |
1960 | 2.69M | WABT_TRACE(ParseUnboundValueTypeList); |
1961 | 2.70M | while (MatchLpar(token)) { |
1962 | 10.7k | CHECK_RESULT(ParseValueTypeList(types, type_names)); |
1963 | 10.7k | EXPECT(Rpar); |
1964 | 10.7k | } |
1965 | 2.69M | return Result::Ok; |
1966 | 2.69M | } |
1967 | | |
1968 | | Result WastParser::ParseResultList( |
1969 | | TypeVector* result_types, |
1970 | 2.44M | std::unordered_map<uint32_t, std::string>* type_names) { |
1971 | 2.44M | WABT_TRACE(ParseResultList); |
1972 | 2.44M | return ParseUnboundValueTypeList(TokenType::Result, result_types, type_names); |
1973 | 2.44M | } |
1974 | | |
1975 | 2.33M | Result WastParser::ParseInstrList(ExprList* exprs) { |
1976 | 2.33M | WABT_TRACE(ParseInstrList); |
1977 | 2.33M | ExprList new_exprs; |
1978 | 2.82M | while (true) { |
1979 | 2.82M | auto pair = PeekPair(); |
1980 | 2.82M | if (IsInstr(pair)) { |
1981 | 558k | if (Succeeded(ParseInstr(&new_exprs))) { |
1982 | 206k | exprs->splice(exprs->end(), new_exprs); |
1983 | 352k | } else { |
1984 | 352k | CHECK_RESULT(Synchronize(IsInstr)); |
1985 | 352k | } |
1986 | 2.26M | } else if (IsLparAnn(pair)) { |
1987 | 2.17k | if (Succeeded(ParseCodeMetadataAnnotation(&new_exprs))) { |
1988 | 1.20k | exprs->splice(exprs->end(), new_exprs); |
1989 | 1.20k | } else { |
1990 | 971 | CHECK_RESULT(Synchronize(IsLparAnn)); |
1991 | 971 | } |
1992 | 2.26M | } else { |
1993 | 2.26M | break; |
1994 | 2.26M | } |
1995 | 2.82M | } |
1996 | 2.26M | return Result::Ok; |
1997 | 2.33M | } |
1998 | | |
1999 | 2.20M | Result WastParser::ParseTerminatingInstrList(ExprList* exprs) { |
2000 | 2.20M | WABT_TRACE(ParseTerminatingInstrList); |
2001 | 2.20M | Result result = ParseInstrList(exprs); |
2002 | | // An InstrList often has no further Lpar following it, because it would have |
2003 | | // gobbled it up. So if there is a following Lpar it is an error. If we |
2004 | | // handle it here we can produce a nicer error message. |
2005 | 2.20M | CHECK_RESULT(ErrorIfLpar({"an instr"})); |
2006 | 2.09M | return result; |
2007 | 2.20M | } |
2008 | | |
2009 | 558k | Result WastParser::ParseInstr(ExprList* exprs) { |
2010 | 558k | WABT_TRACE(ParseInstr); |
2011 | 558k | if (IsPlainInstr(Peek())) { |
2012 | 242k | std::unique_ptr<Expr> expr; |
2013 | 242k | CHECK_RESULT(ParsePlainInstr(&expr)); |
2014 | 178k | exprs->push_back(std::move(expr)); |
2015 | 178k | return Result::Ok; |
2016 | 315k | } else if (IsBlockInstr(Peek())) { |
2017 | 46.8k | std::unique_ptr<Expr> expr; |
2018 | 46.8k | CHECK_RESULT(ParseBlockInstr(&expr)); |
2019 | 5.45k | exprs->push_back(std::move(expr)); |
2020 | 5.45k | return Result::Ok; |
2021 | 268k | } else if (PeekMatchExpr()) { |
2022 | 268k | return ParseExpr(exprs); |
2023 | 268k | } else { |
2024 | 0 | assert(!"ParseInstr should only be called when IsInstr() is true"); |
2025 | 0 | return Result::Error; |
2026 | 0 | } |
2027 | 558k | } |
2028 | | |
2029 | 2.17k | Result WastParser::ParseCodeMetadataAnnotation(ExprList* exprs) { |
2030 | 2.17k | WABT_TRACE(ParseCodeMetadataAnnotation); |
2031 | 2.17k | Token tk = Consume(); |
2032 | 2.17k | std::string_view name = tk.text(); |
2033 | 2.17k | name.remove_prefix(sizeof("metadata.code.") - 1); |
2034 | 2.17k | std::string data_text; |
2035 | 2.17k | CHECK_RESULT(ParseQuotedText(&data_text, false)); |
2036 | 1.49k | std::vector<uint8_t> data(data_text.begin(), data_text.end()); |
2037 | 1.49k | exprs->push_back(std::make_unique<CodeMetadataExpr>(name, std::move(data))); |
2038 | 1.49k | EXPECT(Rpar); |
2039 | 1.20k | return Result::Ok; |
2040 | 1.49k | } |
2041 | | |
2042 | | template <typename T> |
2043 | | Result WastParser::ParsePlainInstrVar(Location loc, |
2044 | 28.7k | std::unique_ptr<Expr>* out_expr) { |
2045 | 28.7k | Var var; |
2046 | 28.7k | CHECK_RESULT(ParseVar(&var)); |
2047 | 19.9k | out_expr->reset(new T(var, loc)); |
2048 | 19.9k | return Result::Ok; |
2049 | 28.7k | } wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)9> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 6.58k | std::unique_ptr<Expr>* out_expr) { | 2045 | 6.58k | Var var; | 2046 | 6.58k | CHECK_RESULT(ParseVar(&var)); | 2047 | 4.46k | out_expr->reset(new T(var, loc)); | 2048 | 4.46k | return Result::Ok; | 2049 | 6.58k | } |
wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)10> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 783 | std::unique_ptr<Expr>* out_expr) { | 2045 | 783 | Var var; | 2046 | 783 | CHECK_RESULT(ParseVar(&var)); | 2047 | 422 | out_expr->reset(new T(var, loc)); | 2048 | 422 | return Result::Ok; | 2049 | 783 | } |
wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)12> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 2.71k | std::unique_ptr<Expr>* out_expr) { | 2045 | 2.71k | Var var; | 2046 | 2.71k | CHECK_RESULT(ParseVar(&var)); | 2047 | 2.14k | out_expr->reset(new T(var, loc)); | 2048 | 2.14k | return Result::Ok; | 2049 | 2.71k | } |
wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)40> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 1.28k | std::unique_ptr<Expr>* out_expr) { | 2045 | 1.28k | Var var; | 2046 | 1.28k | CHECK_RESULT(ParseVar(&var)); | 2047 | 912 | out_expr->reset(new T(var, loc)); | 2048 | 912 | return Result::Ok; | 2049 | 1.28k | } |
wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)24> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 1.43k | std::unique_ptr<Expr>* out_expr) { | 2045 | 1.43k | Var var; | 2046 | 1.43k | CHECK_RESULT(ParseVar(&var)); | 2047 | 1.10k | out_expr->reset(new T(var, loc)); | 2048 | 1.10k | return Result::Ok; | 2049 | 1.43k | } |
wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)25> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 1.82k | std::unique_ptr<Expr>* out_expr) { | 2045 | 1.82k | Var var; | 2046 | 1.82k | CHECK_RESULT(ParseVar(&var)); | 2047 | 1.47k | out_expr->reset(new T(var, loc)); | 2048 | 1.47k | return Result::Ok; | 2049 | 1.82k | } |
wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)26> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 3.62k | std::unique_ptr<Expr>* out_expr) { | 2045 | 3.62k | Var var; | 2046 | 3.62k | CHECK_RESULT(ParseVar(&var)); | 2047 | 2.17k | out_expr->reset(new T(var, loc)); | 2048 | 2.17k | return Result::Ok; | 2049 | 3.62k | } |
wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)20> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 1.52k | std::unique_ptr<Expr>* out_expr) { | 2045 | 1.52k | Var var; | 2046 | 1.52k | CHECK_RESULT(ParseVar(&var)); | 2047 | 1.09k | out_expr->reset(new T(var, loc)); | 2048 | 1.09k | return Result::Ok; | 2049 | 1.52k | } |
wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)21> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 1.41k | std::unique_ptr<Expr>* out_expr) { | 2045 | 1.41k | Var var; | 2046 | 1.41k | CHECK_RESULT(ParseVar(&var)); | 2047 | 1.02k | out_expr->reset(new T(var, loc)); | 2048 | 1.02k | return Result::Ok; | 2049 | 1.41k | } |
wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)29> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 1.58k | std::unique_ptr<Expr>* out_expr) { | 2045 | 1.58k | Var var; | 2046 | 1.58k | CHECK_RESULT(ParseVar(&var)); | 2047 | 994 | out_expr->reset(new T(var, loc)); | 2048 | 994 | return Result::Ok; | 2049 | 1.58k | } |
wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)51> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 1.40k | std::unique_ptr<Expr>* out_expr) { | 2045 | 1.40k | Var var; | 2046 | 1.40k | CHECK_RESULT(ParseVar(&var)); | 2047 | 1.04k | out_expr->reset(new T(var, loc)); | 2048 | 1.04k | return Result::Ok; | 2049 | 1.40k | } |
wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)36> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 1.52k | std::unique_ptr<Expr>* out_expr) { | 2045 | 1.52k | Var var; | 2046 | 1.52k | CHECK_RESULT(ParseVar(&var)); | 2047 | 1.04k | out_expr->reset(new T(var, loc)); | 2048 | 1.04k | return Result::Ok; | 2049 | 1.52k | } |
wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)59> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 2.10k | std::unique_ptr<Expr>* out_expr) { | 2045 | 2.10k | Var var; | 2046 | 2.10k | CHECK_RESULT(ParseVar(&var)); | 2047 | 1.58k | out_expr->reset(new T(var, loc)); | 2048 | 1.58k | return Result::Ok; | 2049 | 2.10k | } |
wabt::Result wabt::WastParser::ParsePlainInstrVar<wabt::VarExpr<(wabt::ExprType)38> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2044 | 925 | std::unique_ptr<Expr>* out_expr) { | 2045 | 925 | Var var; | 2046 | 925 | CHECK_RESULT(ParseVar(&var)); | 2047 | 474 | out_expr->reset(new T(var, loc)); | 2048 | 474 | return Result::Ok; | 2049 | 925 | } |
|
2050 | | |
2051 | | template <typename T> |
2052 | | Result WastParser::ParseMemoryInstrVar(Location loc, |
2053 | 2.22k | std::unique_ptr<Expr>* out_expr) { |
2054 | 2.22k | Var memidx; |
2055 | 2.22k | Var var; |
2056 | 2.22k | if (PeekMatchLpar(TokenType::Memory)) { |
2057 | 194 | if (!options_->features.multi_memory_enabled()) { |
2058 | 194 | Error(loc, "Specifying memory variable is not allowed"); |
2059 | 194 | return Result::Error; |
2060 | 194 | } |
2061 | 0 | CHECK_RESULT(ParseMemidx(loc, &memidx)); |
2062 | 0 | CHECK_RESULT(ParseVar(&var)); |
2063 | 0 | out_expr->reset(new T(var, memidx, loc)); |
2064 | 2.03k | } else { |
2065 | 2.03k | CHECK_RESULT(ParseVar(&memidx)); |
2066 | 1.62k | if (ParseVarOpt(&var, Var(0, loc))) { |
2067 | 414 | if (!options_->features.multi_memory_enabled()) { |
2068 | 414 | Error(loc, "Specifiying memory variable is not allowed"); |
2069 | 414 | return Result::Error; |
2070 | 414 | } |
2071 | 0 | out_expr->reset(new T(var, memidx, loc)); |
2072 | 1.20k | } else { |
2073 | 1.20k | out_expr->reset(new T(memidx, var, loc)); |
2074 | 1.20k | } |
2075 | 1.62k | } |
2076 | 1.20k | return Result::Ok; |
2077 | 2.22k | } |
2078 | | |
2079 | | template <typename T> |
2080 | | Result WastParser::ParseLoadStoreInstr(Location loc, |
2081 | | Token token, |
2082 | 68.0k | std::unique_ptr<Expr>* out_expr) { |
2083 | 68.0k | Opcode opcode = token.opcode(); |
2084 | 68.0k | Var memidx; |
2085 | 68.0k | Address offset; |
2086 | 68.0k | Address align; |
2087 | 68.0k | CHECK_RESULT(ParseMemidx(loc, &memidx)); |
2088 | 46.1k | ParseOffsetOpt(&offset); |
2089 | 46.1k | ParseAlignOpt(&align); |
2090 | 46.1k | out_expr->reset(new T(opcode, memidx, align, offset, loc)); |
2091 | 46.1k | return Result::Ok; |
2092 | 68.0k | } wabt::Result wabt::WastParser::ParseLoadStoreInstr<wabt::LoadStoreExpr<(wabt::ExprType)23> >(wabt::Location, wabt::Token, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2082 | 23.0k | std::unique_ptr<Expr>* out_expr) { | 2083 | 23.0k | Opcode opcode = token.opcode(); | 2084 | 23.0k | Var memidx; | 2085 | 23.0k | Address offset; | 2086 | 23.0k | Address align; | 2087 | 23.0k | CHECK_RESULT(ParseMemidx(loc, &memidx)); | 2088 | 22.6k | ParseOffsetOpt(&offset); | 2089 | 22.6k | ParseAlignOpt(&align); | 2090 | 22.6k | out_expr->reset(new T(opcode, memidx, align, offset, loc)); | 2091 | 22.6k | return Result::Ok; | 2092 | 23.0k | } |
wabt::Result wabt::WastParser::ParseLoadStoreInstr<wabt::LoadStoreExpr<(wabt::ExprType)49> >(wabt::Location, wabt::Token, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2082 | 6.63k | std::unique_ptr<Expr>* out_expr) { | 2083 | 6.63k | Opcode opcode = token.opcode(); | 2084 | 6.63k | Var memidx; | 2085 | 6.63k | Address offset; | 2086 | 6.63k | Address align; | 2087 | 6.63k | CHECK_RESULT(ParseMemidx(loc, &memidx)); | 2088 | 6.41k | ParseOffsetOpt(&offset); | 2089 | 6.41k | ParseAlignOpt(&align); | 2090 | 6.41k | out_expr->reset(new T(opcode, memidx, align, offset, loc)); | 2091 | 6.41k | return Result::Ok; | 2092 | 6.63k | } |
wabt::Result wabt::WastParser::ParseLoadStoreInstr<wabt::LoadStoreExpr<(wabt::ExprType)4> >(wabt::Location, wabt::Token, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2082 | 799 | std::unique_ptr<Expr>* out_expr) { | 2083 | 799 | Opcode opcode = token.opcode(); | 2084 | 799 | Var memidx; | 2085 | 799 | Address offset; | 2086 | 799 | Address align; | 2087 | 799 | CHECK_RESULT(ParseMemidx(loc, &memidx)); | 2088 | 351 | ParseOffsetOpt(&offset); | 2089 | 351 | ParseAlignOpt(&align); | 2090 | 351 | out_expr->reset(new T(opcode, memidx, align, offset, loc)); | 2091 | 351 | return Result::Ok; | 2092 | 799 | } |
wabt::Result wabt::WastParser::ParseLoadStoreInstr<wabt::LoadStoreExpr<(wabt::ExprType)6> >(wabt::Location, wabt::Token, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2082 | 744 | std::unique_ptr<Expr>* out_expr) { | 2083 | 744 | Opcode opcode = token.opcode(); | 2084 | 744 | Var memidx; | 2085 | 744 | Address offset; | 2086 | 744 | Address align; | 2087 | 744 | CHECK_RESULT(ParseMemidx(loc, &memidx)); | 2088 | 366 | ParseOffsetOpt(&offset); | 2089 | 366 | ParseAlignOpt(&align); | 2090 | 366 | out_expr->reset(new T(opcode, memidx, align, offset, loc)); | 2091 | 366 | return Result::Ok; | 2092 | 744 | } |
wabt::Result wabt::WastParser::ParseLoadStoreInstr<wabt::LoadStoreExpr<(wabt::ExprType)0> >(wabt::Location, wabt::Token, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2082 | 2.02k | std::unique_ptr<Expr>* out_expr) { | 2083 | 2.02k | Opcode opcode = token.opcode(); | 2084 | 2.02k | Var memidx; | 2085 | 2.02k | Address offset; | 2086 | 2.02k | Address align; | 2087 | 2.02k | CHECK_RESULT(ParseMemidx(loc, &memidx)); | 2088 | 1.72k | ParseOffsetOpt(&offset); | 2089 | 1.72k | ParseAlignOpt(&align); | 2090 | 1.72k | out_expr->reset(new T(opcode, memidx, align, offset, loc)); | 2091 | 1.72k | return Result::Ok; | 2092 | 2.02k | } |
wabt::Result wabt::WastParser::ParseLoadStoreInstr<wabt::LoadStoreExpr<(wabt::ExprType)3> >(wabt::Location, wabt::Token, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2082 | 21.2k | std::unique_ptr<Expr>* out_expr) { | 2083 | 21.2k | Opcode opcode = token.opcode(); | 2084 | 21.2k | Var memidx; | 2085 | 21.2k | Address offset; | 2086 | 21.2k | Address align; | 2087 | 21.2k | CHECK_RESULT(ParseMemidx(loc, &memidx)); | 2088 | 1.88k | ParseOffsetOpt(&offset); | 2089 | 1.88k | ParseAlignOpt(&align); | 2090 | 1.88k | out_expr->reset(new T(opcode, memidx, align, offset, loc)); | 2091 | 1.88k | return Result::Ok; | 2092 | 21.2k | } |
wabt::Result wabt::WastParser::ParseLoadStoreInstr<wabt::LoadStoreExpr<(wabt::ExprType)1> >(wabt::Location, wabt::Token, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2082 | 10.9k | std::unique_ptr<Expr>* out_expr) { | 2083 | 10.9k | Opcode opcode = token.opcode(); | 2084 | 10.9k | Var memidx; | 2085 | 10.9k | Address offset; | 2086 | 10.9k | Address align; | 2087 | 10.9k | CHECK_RESULT(ParseMemidx(loc, &memidx)); | 2088 | 10.3k | ParseOffsetOpt(&offset); | 2089 | 10.3k | ParseAlignOpt(&align); | 2090 | 10.3k | out_expr->reset(new T(opcode, memidx, align, offset, loc)); | 2091 | 10.3k | return Result::Ok; | 2092 | 10.9k | } |
wabt::Result wabt::WastParser::ParseLoadStoreInstr<wabt::LoadStoreExpr<(wabt::ExprType)2> >(wabt::Location, wabt::Token, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2082 | 2.65k | std::unique_ptr<Expr>* out_expr) { | 2083 | 2.65k | Opcode opcode = token.opcode(); | 2084 | 2.65k | Var memidx; | 2085 | 2.65k | Address offset; | 2086 | 2.65k | Address align; | 2087 | 2.65k | CHECK_RESULT(ParseMemidx(loc, &memidx)); | 2088 | 2.39k | ParseOffsetOpt(&offset); | 2089 | 2.39k | ParseAlignOpt(&align); | 2090 | 2.39k | out_expr->reset(new T(opcode, memidx, align, offset, loc)); | 2091 | 2.39k | return Result::Ok; | 2092 | 2.65k | } |
|
2093 | | |
2094 | | template <typename T> |
2095 | | Result WastParser::ParseSIMDLoadStoreInstr(Location loc, |
2096 | | Token token, |
2097 | 11.2k | std::unique_ptr<Expr>* out_expr) { |
2098 | 11.2k | ErrorUnlessOpcodeEnabled(token); |
2099 | | |
2100 | 11.2k | Var memidx(0, loc); |
2101 | | |
2102 | 11.2k | if (options_->features.multi_memory_enabled()) { |
2103 | | // We have to be a little careful when reading the memeory index. |
2104 | | // If there is just a single integer folloing the instruction that |
2105 | | // represents the lane index, so we check for either a pair of intergers |
2106 | | // or an integers followed by offset= or align=. |
2107 | 0 | bool try_read_mem_index = true; |
2108 | 0 | if (PeekMatch(TokenType::Nat)) { |
2109 | | // The next token could be a memory index or a lane index |
2110 | 0 | if (!PeekMatch(TokenType::OffsetEqNat, 1) && |
2111 | 0 | !PeekMatch(TokenType::AlignEqNat, 1) && |
2112 | 0 | !PeekMatch(TokenType::Nat, 1)) { |
2113 | 0 | try_read_mem_index = false; |
2114 | 0 | } |
2115 | 0 | } |
2116 | 0 | if (try_read_mem_index) { |
2117 | 0 | CHECK_RESULT(ParseMemidx(loc, &memidx)); |
2118 | 0 | } |
2119 | 0 | } |
2120 | 11.2k | Address offset; |
2121 | 11.2k | Address align; |
2122 | 11.2k | ParseOffsetOpt(&offset); |
2123 | 11.2k | ParseAlignOpt(&align); |
2124 | | |
2125 | 11.2k | uint64_t lane_idx = 0; |
2126 | 11.2k | Result result = ParseSimdLane(loc, &lane_idx); |
2127 | | |
2128 | 11.2k | if (Failed(result)) { |
2129 | 7.37k | return Result::Error; |
2130 | 7.37k | } |
2131 | | |
2132 | 3.87k | out_expr->reset(new T(token.opcode(), memidx, align, offset, lane_idx, loc)); |
2133 | 3.87k | return Result::Ok; |
2134 | 11.2k | } wabt::Result wabt::WastParser::ParseSIMDLoadStoreInstr<wabt::SimdLoadLaneExpr>(wabt::Location, wabt::Token, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2097 | 10.0k | std::unique_ptr<Expr>* out_expr) { | 2098 | 10.0k | ErrorUnlessOpcodeEnabled(token); | 2099 | | | 2100 | 10.0k | Var memidx(0, loc); | 2101 | | | 2102 | 10.0k | if (options_->features.multi_memory_enabled()) { | 2103 | | // We have to be a little careful when reading the memeory index. | 2104 | | // If there is just a single integer folloing the instruction that | 2105 | | // represents the lane index, so we check for either a pair of intergers | 2106 | | // or an integers followed by offset= or align=. | 2107 | 0 | bool try_read_mem_index = true; | 2108 | 0 | if (PeekMatch(TokenType::Nat)) { | 2109 | | // The next token could be a memory index or a lane index | 2110 | 0 | if (!PeekMatch(TokenType::OffsetEqNat, 1) && | 2111 | 0 | !PeekMatch(TokenType::AlignEqNat, 1) && | 2112 | 0 | !PeekMatch(TokenType::Nat, 1)) { | 2113 | 0 | try_read_mem_index = false; | 2114 | 0 | } | 2115 | 0 | } | 2116 | 0 | if (try_read_mem_index) { | 2117 | 0 | CHECK_RESULT(ParseMemidx(loc, &memidx)); | 2118 | 0 | } | 2119 | 0 | } | 2120 | 10.0k | Address offset; | 2121 | 10.0k | Address align; | 2122 | 10.0k | ParseOffsetOpt(&offset); | 2123 | 10.0k | ParseAlignOpt(&align); | 2124 | | | 2125 | 10.0k | uint64_t lane_idx = 0; | 2126 | 10.0k | Result result = ParseSimdLane(loc, &lane_idx); | 2127 | | | 2128 | 10.0k | if (Failed(result)) { | 2129 | 6.45k | return Result::Error; | 2130 | 6.45k | } | 2131 | | | 2132 | 3.56k | out_expr->reset(new T(token.opcode(), memidx, align, offset, lane_idx, loc)); | 2133 | 3.56k | return Result::Ok; | 2134 | 10.0k | } |
wabt::Result wabt::WastParser::ParseSIMDLoadStoreInstr<wabt::SimdStoreLaneExpr>(wabt::Location, wabt::Token, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2097 | 1.22k | std::unique_ptr<Expr>* out_expr) { | 2098 | 1.22k | ErrorUnlessOpcodeEnabled(token); | 2099 | | | 2100 | 1.22k | Var memidx(0, loc); | 2101 | | | 2102 | 1.22k | if (options_->features.multi_memory_enabled()) { | 2103 | | // We have to be a little careful when reading the memeory index. | 2104 | | // If there is just a single integer folloing the instruction that | 2105 | | // represents the lane index, so we check for either a pair of intergers | 2106 | | // or an integers followed by offset= or align=. | 2107 | 0 | bool try_read_mem_index = true; | 2108 | 0 | if (PeekMatch(TokenType::Nat)) { | 2109 | | // The next token could be a memory index or a lane index | 2110 | 0 | if (!PeekMatch(TokenType::OffsetEqNat, 1) && | 2111 | 0 | !PeekMatch(TokenType::AlignEqNat, 1) && | 2112 | 0 | !PeekMatch(TokenType::Nat, 1)) { | 2113 | 0 | try_read_mem_index = false; | 2114 | 0 | } | 2115 | 0 | } | 2116 | 0 | if (try_read_mem_index) { | 2117 | 0 | CHECK_RESULT(ParseMemidx(loc, &memidx)); | 2118 | 0 | } | 2119 | 0 | } | 2120 | 1.22k | Address offset; | 2121 | 1.22k | Address align; | 2122 | 1.22k | ParseOffsetOpt(&offset); | 2123 | 1.22k | ParseAlignOpt(&align); | 2124 | | | 2125 | 1.22k | uint64_t lane_idx = 0; | 2126 | 1.22k | Result result = ParseSimdLane(loc, &lane_idx); | 2127 | | | 2128 | 1.22k | if (Failed(result)) { | 2129 | 920 | return Result::Error; | 2130 | 920 | } | 2131 | | | 2132 | 309 | out_expr->reset(new T(token.opcode(), memidx, align, offset, lane_idx, loc)); | 2133 | 309 | return Result::Ok; | 2134 | 1.22k | } |
|
2135 | | |
2136 | | template <typename T> |
2137 | | Result WastParser::ParseMemoryExpr(Location loc, |
2138 | 24.4k | std::unique_ptr<Expr>* out_expr) { |
2139 | 24.4k | Var memidx; |
2140 | 24.4k | CHECK_RESULT(ParseMemidx(loc, &memidx)); |
2141 | 22.2k | out_expr->reset(new T(memidx, loc)); |
2142 | 22.2k | return Result::Ok; |
2143 | 24.4k | } wabt::Result wabt::WastParser::ParseMemoryExpr<wabt::MemoryExpr<(wabt::ExprType)30> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2138 | 777 | std::unique_ptr<Expr>* out_expr) { | 2139 | 777 | Var memidx; | 2140 | 777 | CHECK_RESULT(ParseMemidx(loc, &memidx)); | 2141 | 579 | out_expr->reset(new T(memidx, loc)); | 2142 | 579 | return Result::Ok; | 2143 | 777 | } |
wabt::Result wabt::WastParser::ParseMemoryExpr<wabt::MemoryExpr<(wabt::ExprType)33> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2138 | 22.8k | std::unique_ptr<Expr>* out_expr) { | 2139 | 22.8k | Var memidx; | 2140 | 22.8k | CHECK_RESULT(ParseMemidx(loc, &memidx)); | 2141 | 21.0k | out_expr->reset(new T(memidx, loc)); | 2142 | 21.0k | return Result::Ok; | 2143 | 22.8k | } |
wabt::Result wabt::WastParser::ParseMemoryExpr<wabt::MemoryExpr<(wabt::ExprType)31> >(wabt::Location, std::__1::unique_ptr<wabt::Expr, std::__1::default_delete<wabt::Expr> >*) Line | Count | Source | 2138 | 842 | std::unique_ptr<Expr>* out_expr) { | 2139 | 842 | Var memidx; | 2140 | 842 | CHECK_RESULT(ParseMemidx(loc, &memidx)); | 2141 | 606 | out_expr->reset(new T(memidx, loc)); | 2142 | 606 | return Result::Ok; | 2143 | 842 | } |
|
2144 | | |
2145 | | template <typename T> |
2146 | | Result WastParser::ParseMemoryBinaryExpr(Location loc, |
2147 | 908 | std::unique_ptr<Expr>* out_expr) { |
2148 | 908 | Var destmemidx; |
2149 | 908 | Var srcmemidx; |
2150 | 908 | CHECK_RESULT(ParseMemidx(loc, &destmemidx)); |
2151 | 568 | CHECK_RESULT(ParseMemidx(loc, &srcmemidx)); |
2152 | 568 | out_expr->reset(new T(destmemidx, srcmemidx, loc)); |
2153 | 568 | return Result::Ok; |
2154 | 568 | } |
2155 | | |
2156 | 48.0k | Result WastParser::ParseSimdLane(Location loc, uint64_t* lane_idx) { |
2157 | 48.0k | if (!PeekMatch(TokenType::Nat) && !PeekMatch(TokenType::Int)) { |
2158 | 11.9k | return ErrorExpected({"a natural number in range [0, 32)"}); |
2159 | 11.9k | } |
2160 | | |
2161 | 36.0k | Literal literal = Consume().literal(); |
2162 | | |
2163 | 36.0k | Result result = |
2164 | 36.0k | ParseInt64(literal.text, lane_idx, ParseIntType::UnsignedOnly); |
2165 | | |
2166 | 36.0k | if (Failed(result)) { |
2167 | 11.8k | Error(loc, "invalid literal \"" PRIstringview "\"", |
2168 | 11.8k | WABT_PRINTF_STRING_VIEW_ARG(literal.text)); |
2169 | 11.8k | return Result::Error; |
2170 | 11.8k | } |
2171 | | |
2172 | | // The valid range is only [0, 32), but it's only malformed if it can't |
2173 | | // fit in a byte. |
2174 | 24.2k | if (*lane_idx > 255) { |
2175 | 871 | Error(loc, "lane index \"" PRIstringview "\" out-of-range [0, 32)", |
2176 | 871 | WABT_PRINTF_STRING_VIEW_ARG(literal.text)); |
2177 | 871 | return Result::Error; |
2178 | 871 | } |
2179 | | |
2180 | 23.3k | return Result::Ok; |
2181 | 24.2k | } |
2182 | | |
2183 | 835k | Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) { |
2184 | 835k | WABT_TRACE(ParsePlainInstr); |
2185 | 835k | Location loc = GetLocation(); |
2186 | 835k | switch (Peek()) { |
2187 | 684 | case TokenType::Unreachable: |
2188 | 684 | Consume(); |
2189 | 684 | out_expr->reset(new UnreachableExpr(loc)); |
2190 | 684 | break; |
2191 | | |
2192 | 152k | case TokenType::Nop: |
2193 | 152k | Consume(); |
2194 | 152k | out_expr->reset(new NopExpr(loc)); |
2195 | 152k | break; |
2196 | | |
2197 | 569 | case TokenType::Drop: |
2198 | 569 | Consume(); |
2199 | 569 | out_expr->reset(new DropExpr(loc)); |
2200 | 569 | break; |
2201 | | |
2202 | 1.76k | case TokenType::Select: { |
2203 | 1.76k | Consume(); |
2204 | 1.76k | TypeVector result; |
2205 | 1.76k | if (options_->features.reference_types_enabled() && |
2206 | 1.76k | PeekMatchLpar(TokenType::Result)) { |
2207 | 524 | CHECK_RESULT(ParseResultList(&result, nullptr)); |
2208 | 524 | } |
2209 | 1.55k | out_expr->reset(new SelectExpr(result, loc)); |
2210 | 1.55k | break; |
2211 | 1.76k | } |
2212 | | |
2213 | 6.58k | case TokenType::Br: |
2214 | 6.58k | Consume(); |
2215 | 6.58k | CHECK_RESULT(ParsePlainInstrVar<BrExpr>(loc, out_expr)); |
2216 | 4.46k | break; |
2217 | | |
2218 | 4.46k | case TokenType::BrIf: |
2219 | 783 | Consume(); |
2220 | 783 | CHECK_RESULT(ParsePlainInstrVar<BrIfExpr>(loc, out_expr)); |
2221 | 422 | break; |
2222 | | |
2223 | 10.8k | case TokenType::BrTable: { |
2224 | 10.8k | Consume(); |
2225 | 10.8k | auto expr = std::make_unique<BrTableExpr>(loc); |
2226 | 10.8k | CHECK_RESULT(ParseVarList(&expr->targets)); |
2227 | 1.14k | expr->default_target = expr->targets.back(); |
2228 | 1.14k | expr->targets.pop_back(); |
2229 | 1.14k | *out_expr = std::move(expr); |
2230 | 1.14k | break; |
2231 | 10.8k | } |
2232 | | |
2233 | 8.58k | case TokenType::Return: |
2234 | 8.58k | Consume(); |
2235 | 8.58k | out_expr->reset(new ReturnExpr(loc)); |
2236 | 8.58k | break; |
2237 | | |
2238 | 2.71k | case TokenType::Call: |
2239 | 2.71k | Consume(); |
2240 | 2.71k | CHECK_RESULT(ParsePlainInstrVar<CallExpr>(loc, out_expr)); |
2241 | 2.14k | break; |
2242 | | |
2243 | 8.39k | case TokenType::CallIndirect: { |
2244 | 8.39k | Consume(); |
2245 | 8.39k | auto expr = std::make_unique<CallIndirectExpr>(loc); |
2246 | 8.39k | ParseVarOpt(&expr->table, Var(0, loc)); |
2247 | 8.39k | CHECK_RESULT(ParseTypeUseOpt(&expr->decl)); |
2248 | 7.93k | CHECK_RESULT(ParseUnboundFuncSignature(&expr->decl.sig)); |
2249 | 7.72k | *out_expr = std::move(expr); |
2250 | 7.72k | break; |
2251 | 7.93k | } |
2252 | | |
2253 | 442 | case TokenType::CallRef: { |
2254 | 442 | ErrorUnlessOpcodeEnabled(Consume()); |
2255 | 442 | out_expr->reset(new CallRefExpr(loc)); |
2256 | 442 | break; |
2257 | 7.93k | } |
2258 | | |
2259 | 1.28k | case TokenType::ReturnCall: |
2260 | 1.28k | ErrorUnlessOpcodeEnabled(Consume()); |
2261 | 1.28k | CHECK_RESULT(ParsePlainInstrVar<ReturnCallExpr>(loc, out_expr)); |
2262 | 912 | break; |
2263 | | |
2264 | 8.89k | case TokenType::ReturnCallIndirect: { |
2265 | 8.89k | ErrorUnlessOpcodeEnabled(Consume()); |
2266 | 8.89k | auto expr = std::make_unique<ReturnCallIndirectExpr>(loc); |
2267 | 8.89k | ParseVarOpt(&expr->table, Var(0, loc)); |
2268 | 8.89k | CHECK_RESULT(ParseTypeUseOpt(&expr->decl)); |
2269 | 8.34k | CHECK_RESULT(ParseUnboundFuncSignature(&expr->decl.sig)); |
2270 | 8.13k | *out_expr = std::move(expr); |
2271 | 8.13k | break; |
2272 | 8.34k | } |
2273 | | |
2274 | 1.43k | case TokenType::LocalGet: |
2275 | 1.43k | Consume(); |
2276 | 1.43k | CHECK_RESULT(ParsePlainInstrVar<LocalGetExpr>(loc, out_expr)); |
2277 | 1.10k | break; |
2278 | | |
2279 | 1.82k | case TokenType::LocalSet: |
2280 | 1.82k | Consume(); |
2281 | 1.82k | CHECK_RESULT(ParsePlainInstrVar<LocalSetExpr>(loc, out_expr)); |
2282 | 1.47k | break; |
2283 | | |
2284 | 3.62k | case TokenType::LocalTee: |
2285 | 3.62k | Consume(); |
2286 | 3.62k | CHECK_RESULT(ParsePlainInstrVar<LocalTeeExpr>(loc, out_expr)); |
2287 | 2.17k | break; |
2288 | | |
2289 | 2.17k | case TokenType::GlobalGet: |
2290 | 1.52k | Consume(); |
2291 | 1.52k | CHECK_RESULT(ParsePlainInstrVar<GlobalGetExpr>(loc, out_expr)); |
2292 | 1.09k | break; |
2293 | | |
2294 | 1.41k | case TokenType::GlobalSet: |
2295 | 1.41k | Consume(); |
2296 | 1.41k | CHECK_RESULT(ParsePlainInstrVar<GlobalSetExpr>(loc, out_expr)); |
2297 | 1.02k | break; |
2298 | | |
2299 | 23.0k | case TokenType::Load: |
2300 | 23.0k | CHECK_RESULT(ParseLoadStoreInstr<LoadExpr>(loc, Consume(), out_expr)); |
2301 | 22.6k | break; |
2302 | | |
2303 | 22.6k | case TokenType::Store: |
2304 | 6.63k | CHECK_RESULT(ParseLoadStoreInstr<StoreExpr>(loc, Consume(), out_expr)); |
2305 | 6.41k | break; |
2306 | | |
2307 | 417k | case TokenType::Const: { |
2308 | 417k | Const const_; |
2309 | 417k | CHECK_RESULT(ParseConst(&const_, ConstType::Normal)); |
2310 | 326k | out_expr->reset(new ConstExpr(const_, loc)); |
2311 | 326k | break; |
2312 | 417k | } |
2313 | | |
2314 | 22.6k | case TokenType::Unary: { |
2315 | 22.6k | Token token = Consume(); |
2316 | 22.6k | ErrorUnlessOpcodeEnabled(token); |
2317 | 22.6k | out_expr->reset(new UnaryExpr(token.opcode(), loc)); |
2318 | 22.6k | break; |
2319 | 417k | } |
2320 | | |
2321 | 14.2k | case TokenType::Binary: { |
2322 | 14.2k | Token token = Consume(); |
2323 | 14.2k | ErrorUnlessOpcodeEnabled(token); |
2324 | 14.2k | out_expr->reset(new BinaryExpr(token.opcode(), loc)); |
2325 | 14.2k | break; |
2326 | 417k | } |
2327 | | |
2328 | 1.10k | case TokenType::Compare: |
2329 | 1.10k | out_expr->reset(new CompareExpr(Consume().opcode(), loc)); |
2330 | 1.10k | break; |
2331 | | |
2332 | 5.84k | case TokenType::Convert: { |
2333 | 5.84k | Token token = Consume(); |
2334 | 5.84k | ErrorUnlessOpcodeEnabled(token); |
2335 | 5.84k | out_expr->reset(new ConvertExpr(token.opcode(), loc)); |
2336 | 5.84k | break; |
2337 | 417k | } |
2338 | | |
2339 | 908 | case TokenType::MemoryCopy: |
2340 | 908 | ErrorUnlessOpcodeEnabled(Consume()); |
2341 | 908 | CHECK_RESULT(ParseMemoryBinaryExpr<MemoryCopyExpr>(loc, out_expr)); |
2342 | 568 | break; |
2343 | | |
2344 | 777 | case TokenType::MemoryFill: |
2345 | 777 | ErrorUnlessOpcodeEnabled(Consume()); |
2346 | 777 | CHECK_RESULT(ParseMemoryExpr<MemoryFillExpr>(loc, out_expr)); |
2347 | 579 | break; |
2348 | | |
2349 | 1.58k | case TokenType::DataDrop: |
2350 | 1.58k | ErrorUnlessOpcodeEnabled(Consume()); |
2351 | 1.58k | CHECK_RESULT(ParsePlainInstrVar<DataDropExpr>(loc, out_expr)); |
2352 | 994 | break; |
2353 | | |
2354 | 2.22k | case TokenType::MemoryInit: |
2355 | 2.22k | ErrorUnlessOpcodeEnabled(Consume()); |
2356 | 2.22k | CHECK_RESULT(ParseMemoryInstrVar<MemoryInitExpr>(loc, out_expr)); |
2357 | 1.20k | break; |
2358 | | |
2359 | 22.8k | case TokenType::MemorySize: |
2360 | 22.8k | Consume(); |
2361 | 22.8k | CHECK_RESULT(ParseMemoryExpr<MemorySizeExpr>(loc, out_expr)); |
2362 | 21.0k | break; |
2363 | | |
2364 | 21.0k | case TokenType::MemoryGrow: |
2365 | 842 | Consume(); |
2366 | 842 | CHECK_RESULT(ParseMemoryExpr<MemoryGrowExpr>(loc, out_expr)); |
2367 | 606 | break; |
2368 | | |
2369 | 3.41k | case TokenType::TableCopy: { |
2370 | 3.41k | ErrorUnlessOpcodeEnabled(Consume()); |
2371 | 3.41k | Var dst(0, loc); |
2372 | 3.41k | Var src(0, loc); |
2373 | 3.41k | if (options_->features.reference_types_enabled()) { |
2374 | 3.41k | ParseVarOpt(&dst, dst); |
2375 | 3.41k | ParseVarOpt(&src, src); |
2376 | 3.41k | } |
2377 | 3.41k | out_expr->reset(new TableCopyExpr(dst, src, loc)); |
2378 | 3.41k | break; |
2379 | 842 | } |
2380 | | |
2381 | 1.40k | case TokenType::ElemDrop: |
2382 | 1.40k | ErrorUnlessOpcodeEnabled(Consume()); |
2383 | 1.40k | CHECK_RESULT(ParsePlainInstrVar<ElemDropExpr>(loc, out_expr)); |
2384 | 1.04k | break; |
2385 | | |
2386 | 2.41k | case TokenType::TableInit: { |
2387 | 2.41k | ErrorUnlessOpcodeEnabled(Consume()); |
2388 | 2.41k | Var segment_index(0, loc); |
2389 | 2.41k | CHECK_RESULT(ParseVar(&segment_index)); |
2390 | 1.97k | Var table_index(0, loc); |
2391 | 1.97k | if (ParseVarOpt(&table_index, table_index)) { |
2392 | | // Here are the two forms: |
2393 | | // |
2394 | | // table.init $elemidx ... |
2395 | | // table.init $tableidx $elemidx ... |
2396 | | // |
2397 | | // So if both indexes are provided, we need to swap them. |
2398 | 995 | std::swap(segment_index, table_index); |
2399 | 995 | } |
2400 | 1.97k | out_expr->reset(new TableInitExpr(segment_index, table_index, loc)); |
2401 | 1.97k | break; |
2402 | 2.41k | } |
2403 | | |
2404 | 1.14k | case TokenType::TableGet: { |
2405 | 1.14k | ErrorUnlessOpcodeEnabled(Consume()); |
2406 | 1.14k | Var table_index(0, loc); |
2407 | 1.14k | ParseVarOpt(&table_index, table_index); |
2408 | 1.14k | out_expr->reset(new TableGetExpr(table_index, loc)); |
2409 | 1.14k | break; |
2410 | 2.41k | } |
2411 | | |
2412 | 1.17k | case TokenType::TableSet: { |
2413 | 1.17k | ErrorUnlessOpcodeEnabled(Consume()); |
2414 | 1.17k | Var table_index(0, loc); |
2415 | 1.17k | ParseVarOpt(&table_index, table_index); |
2416 | 1.17k | out_expr->reset(new TableSetExpr(table_index, loc)); |
2417 | 1.17k | break; |
2418 | 2.41k | } |
2419 | | |
2420 | 2.89k | case TokenType::TableGrow: { |
2421 | 2.89k | ErrorUnlessOpcodeEnabled(Consume()); |
2422 | 2.89k | Var table_index(0, loc); |
2423 | 2.89k | ParseVarOpt(&table_index, table_index); |
2424 | 2.89k | out_expr->reset(new TableGrowExpr(table_index, loc)); |
2425 | 2.89k | break; |
2426 | 2.41k | } |
2427 | | |
2428 | 2.07k | case TokenType::TableSize: { |
2429 | 2.07k | ErrorUnlessOpcodeEnabled(Consume()); |
2430 | 2.07k | Var table_index(0, loc); |
2431 | 2.07k | ParseVarOpt(&table_index, table_index); |
2432 | 2.07k | out_expr->reset(new TableSizeExpr(table_index, loc)); |
2433 | 2.07k | break; |
2434 | 2.41k | } |
2435 | | |
2436 | 2.00k | case TokenType::TableFill: { |
2437 | 2.00k | ErrorUnlessOpcodeEnabled(Consume()); |
2438 | 2.00k | Var table_index(0, loc); |
2439 | 2.00k | ParseVarOpt(&table_index, table_index); |
2440 | 2.00k | out_expr->reset(new TableFillExpr(table_index, loc)); |
2441 | 2.00k | break; |
2442 | 2.41k | } |
2443 | | |
2444 | 1.52k | case TokenType::RefFunc: |
2445 | 1.52k | ErrorUnlessOpcodeEnabled(Consume()); |
2446 | 1.52k | CHECK_RESULT(ParsePlainInstrVar<RefFuncExpr>(loc, out_expr)); |
2447 | 1.04k | break; |
2448 | | |
2449 | 1.58k | case TokenType::RefNull: { |
2450 | 1.58k | ErrorUnlessOpcodeEnabled(Consume()); |
2451 | 1.58k | Type type; |
2452 | 1.58k | CHECK_RESULT(ParseRefKind(&type)); |
2453 | 728 | out_expr->reset(new RefNullExpr(type, loc)); |
2454 | 728 | break; |
2455 | 1.58k | } |
2456 | | |
2457 | 426 | case TokenType::RefIsNull: |
2458 | 426 | ErrorUnlessOpcodeEnabled(Consume()); |
2459 | 426 | out_expr->reset(new RefIsNullExpr(loc)); |
2460 | 426 | break; |
2461 | | |
2462 | 2.10k | case TokenType::Throw: |
2463 | 2.10k | ErrorUnlessOpcodeEnabled(Consume()); |
2464 | 2.10k | CHECK_RESULT(ParsePlainInstrVar<ThrowExpr>(loc, out_expr)); |
2465 | 1.58k | break; |
2466 | | |
2467 | 1.58k | case TokenType::Rethrow: |
2468 | 925 | ErrorUnlessOpcodeEnabled(Consume()); |
2469 | 925 | CHECK_RESULT(ParsePlainInstrVar<RethrowExpr>(loc, out_expr)); |
2470 | 474 | break; |
2471 | | |
2472 | 799 | case TokenType::AtomicNotify: { |
2473 | 799 | Token token = Consume(); |
2474 | 799 | ErrorUnlessOpcodeEnabled(token); |
2475 | 799 | CHECK_RESULT(ParseLoadStoreInstr<AtomicNotifyExpr>(loc, token, out_expr)); |
2476 | 351 | break; |
2477 | 799 | } |
2478 | | |
2479 | 422 | case TokenType::AtomicFence: { |
2480 | 422 | Token token = Consume(); |
2481 | 422 | ErrorUnlessOpcodeEnabled(token); |
2482 | 422 | uint32_t consistency_model = 0x0; |
2483 | 422 | out_expr->reset(new AtomicFenceExpr(consistency_model, loc)); |
2484 | 422 | break; |
2485 | 799 | } |
2486 | | |
2487 | 744 | case TokenType::AtomicWait: { |
2488 | 744 | Token token = Consume(); |
2489 | 744 | ErrorUnlessOpcodeEnabled(token); |
2490 | 744 | CHECK_RESULT(ParseLoadStoreInstr<AtomicWaitExpr>(loc, token, out_expr)); |
2491 | 366 | break; |
2492 | 744 | } |
2493 | | |
2494 | 2.02k | case TokenType::AtomicLoad: { |
2495 | 2.02k | Token token = Consume(); |
2496 | 2.02k | ErrorUnlessOpcodeEnabled(token); |
2497 | 2.02k | CHECK_RESULT(ParseLoadStoreInstr<AtomicLoadExpr>(loc, token, out_expr)); |
2498 | 1.72k | break; |
2499 | 2.02k | } |
2500 | | |
2501 | 21.2k | case TokenType::AtomicStore: { |
2502 | 21.2k | Token token = Consume(); |
2503 | 21.2k | ErrorUnlessOpcodeEnabled(token); |
2504 | 21.2k | CHECK_RESULT(ParseLoadStoreInstr<AtomicStoreExpr>(loc, token, out_expr)); |
2505 | 1.88k | break; |
2506 | 21.2k | } |
2507 | | |
2508 | 10.9k | case TokenType::AtomicRmw: { |
2509 | 10.9k | Token token = Consume(); |
2510 | 10.9k | ErrorUnlessOpcodeEnabled(token); |
2511 | 10.9k | CHECK_RESULT(ParseLoadStoreInstr<AtomicRmwExpr>(loc, token, out_expr)); |
2512 | 10.3k | break; |
2513 | 10.9k | } |
2514 | | |
2515 | 10.3k | case TokenType::AtomicRmwCmpxchg: { |
2516 | 2.65k | Token token = Consume(); |
2517 | 2.65k | ErrorUnlessOpcodeEnabled(token); |
2518 | 2.65k | CHECK_RESULT( |
2519 | 2.65k | ParseLoadStoreInstr<AtomicRmwCmpxchgExpr>(loc, token, out_expr)); |
2520 | 2.39k | break; |
2521 | 2.65k | } |
2522 | | |
2523 | 9.72k | case TokenType::Ternary: { |
2524 | 9.72k | Token token = Consume(); |
2525 | 9.72k | ErrorUnlessOpcodeEnabled(token); |
2526 | 9.72k | out_expr->reset(new TernaryExpr(token.opcode(), loc)); |
2527 | 9.72k | break; |
2528 | 2.65k | } |
2529 | | |
2530 | 3.72k | case TokenType::SimdLaneOp: { |
2531 | 3.72k | Token token = Consume(); |
2532 | 3.72k | ErrorUnlessOpcodeEnabled(token); |
2533 | | |
2534 | 3.72k | uint64_t lane_idx = 0; |
2535 | 3.72k | Result result = ParseSimdLane(loc, &lane_idx); |
2536 | | |
2537 | 3.72k | if (Failed(result)) { |
2538 | 3.13k | return Result::Error; |
2539 | 3.13k | } |
2540 | | |
2541 | 586 | out_expr->reset(new SimdLaneOpExpr(token.opcode(), lane_idx, loc)); |
2542 | 586 | break; |
2543 | 3.72k | } |
2544 | | |
2545 | 10.0k | case TokenType::SimdLoadLane: { |
2546 | 10.0k | CHECK_RESULT( |
2547 | 10.0k | ParseSIMDLoadStoreInstr<SimdLoadLaneExpr>(loc, Consume(), out_expr)); |
2548 | 3.56k | break; |
2549 | 10.0k | } |
2550 | | |
2551 | 3.56k | case TokenType::SimdStoreLane: { |
2552 | 1.22k | CHECK_RESULT( |
2553 | 1.22k | ParseSIMDLoadStoreInstr<SimdStoreLaneExpr>(loc, Consume(), out_expr)); |
2554 | 309 | break; |
2555 | 1.22k | } |
2556 | | |
2557 | 15.1k | case TokenType::SimdShuffleOp: { |
2558 | 15.1k | Token token = Consume(); |
2559 | 15.1k | ErrorUnlessOpcodeEnabled(token); |
2560 | 15.1k | v128 values; |
2561 | 34.0k | for (int lane = 0; lane < 16; ++lane) { |
2562 | 33.0k | Location loc = GetLocation(); |
2563 | 33.0k | uint64_t lane_idx; |
2564 | 33.0k | Result result = ParseSimdLane(loc, &lane_idx); |
2565 | 33.0k | if (Failed(result)) { |
2566 | 14.1k | return Result::Error; |
2567 | 14.1k | } |
2568 | | |
2569 | 18.9k | values.set_u8(lane, static_cast<uint8_t>(lane_idx)); |
2570 | 18.9k | } |
2571 | | |
2572 | 970 | out_expr->reset(new SimdShuffleOpExpr(token.opcode(), values, loc)); |
2573 | 970 | break; |
2574 | 15.1k | } |
2575 | | |
2576 | 0 | default: |
2577 | 0 | assert( |
2578 | 0 | !"ParsePlainInstr should only be called when IsPlainInstr() is true"); |
2579 | 0 | return Result::Error; |
2580 | 835k | } |
2581 | | |
2582 | 672k | return Result::Ok; |
2583 | 835k | } |
2584 | | |
2585 | | Result WastParser::ParseSimdV128Const(Const* const_, |
2586 | | TokenType token_type, |
2587 | 36.5k | ConstType const_type) { |
2588 | 36.5k | WABT_TRACE(ParseSimdV128Const); |
2589 | | |
2590 | 36.5k | uint8_t lane_count = 0; |
2591 | 36.5k | bool integer = true; |
2592 | 36.5k | switch (token_type) { |
2593 | 1.24k | case TokenType::I8X16: { lane_count = 16; break; } |
2594 | 9.14k | case TokenType::I16X8: { lane_count = 8; break; } |
2595 | 580 | case TokenType::I32X4: { lane_count = 4; break; } |
2596 | 375 | case TokenType::I64X2: { lane_count = 2; break; } |
2597 | 537 | case TokenType::F32X4: { lane_count = 4; integer = false; break; } |
2598 | 20.3k | case TokenType::F64X2: { lane_count = 2; integer = false; break; } |
2599 | 4.35k | default: { |
2600 | 4.35k | Error(const_->loc, |
2601 | 4.35k | "Unexpected type at start of simd constant. " |
2602 | 4.35k | "Expected one of: i8x16, i16x8, i32x4, i64x2, f32x4, f64x2. " |
2603 | 4.35k | "Found \"%s\".", |
2604 | 4.35k | GetTokenTypeName(token_type)); |
2605 | 4.35k | return Result::Error; |
2606 | 0 | } |
2607 | 36.5k | } |
2608 | 32.2k | Consume(); |
2609 | | |
2610 | 32.2k | const_->loc = GetLocation(); |
2611 | | |
2612 | 81.7k | for (int lane = 0; lane < lane_count; ++lane) { |
2613 | 61.8k | Location loc = GetLocation(); |
2614 | | |
2615 | | // Check that the lane literal type matches the element type of the v128: |
2616 | 61.8k | Token token = GetToken(); |
2617 | 61.8k | switch (token.token_type()) { |
2618 | 11.6k | case TokenType::Nat: |
2619 | 15.7k | case TokenType::Int: |
2620 | | // OK. |
2621 | 15.7k | break; |
2622 | | |
2623 | 40.0k | case TokenType::Float: |
2624 | 40.2k | case TokenType::NanArithmetic: |
2625 | 40.5k | case TokenType::NanCanonical: |
2626 | 40.5k | if (integer) { |
2627 | 485 | goto error; |
2628 | 485 | } |
2629 | 40.0k | break; |
2630 | | |
2631 | 40.0k | error: |
2632 | 5.98k | default: |
2633 | 5.98k | if (integer) { |
2634 | 5.15k | return ErrorExpected({"a Nat or Integer literal"}, "123"); |
2635 | 5.15k | } else { |
2636 | 825 | return ErrorExpected({"a Float literal"}, "42.0"); |
2637 | 825 | } |
2638 | 61.8k | } |
2639 | | |
2640 | 55.8k | Result result; |
2641 | | |
2642 | | // For each type, parse the next literal, bound check it, and write it to |
2643 | | // the array of bytes: |
2644 | 55.8k | if (integer) { |
2645 | 14.6k | std::string_view sv = Consume().literal().text; |
2646 | | |
2647 | 14.6k | switch (lane_count) { |
2648 | 2.81k | case 16: { |
2649 | 2.81k | uint8_t value = 0; |
2650 | 2.81k | result = ParseInt8(sv, &value, ParseIntType::SignedAndUnsigned); |
2651 | 2.81k | const_->set_v128_u8(lane, value); |
2652 | 2.81k | break; |
2653 | 0 | } |
2654 | 10.9k | case 8: { |
2655 | 10.9k | uint16_t value = 0; |
2656 | 10.9k | result = ParseInt16(sv, &value, ParseIntType::SignedAndUnsigned); |
2657 | 10.9k | const_->set_v128_u16(lane, value); |
2658 | 10.9k | break; |
2659 | 0 | } |
2660 | 431 | case 4: { |
2661 | 431 | uint32_t value = 0; |
2662 | 431 | result = ParseInt32(sv, &value, ParseIntType::SignedAndUnsigned); |
2663 | 431 | const_->set_v128_u32(lane, value); |
2664 | 431 | break; |
2665 | 0 | } |
2666 | 510 | case 2: { |
2667 | 510 | uint64_t value = 0; |
2668 | 510 | result = ParseInt64(sv, &value, ParseIntType::SignedAndUnsigned); |
2669 | 510 | const_->set_v128_u64(lane, value); |
2670 | 510 | break; |
2671 | 0 | } |
2672 | 14.6k | } |
2673 | 41.1k | } else { |
2674 | 41.1k | Const lane_const_; |
2675 | 41.1k | switch (lane_count) { |
2676 | 1.22k | case 4: |
2677 | 1.22k | result = ParseF32(&lane_const_, const_type); |
2678 | 1.22k | const_->set_v128_f32(lane, lane_const_.f32_bits()); |
2679 | 1.22k | break; |
2680 | | |
2681 | 39.9k | case 2: |
2682 | 39.9k | result = ParseF64(&lane_const_, const_type); |
2683 | 39.9k | const_->set_v128_f64(lane, lane_const_.f64_bits()); |
2684 | 39.9k | break; |
2685 | 41.1k | } |
2686 | | |
2687 | 41.1k | const_->set_expected_nan(lane, lane_const_.expected_nan()); |
2688 | 41.1k | } |
2689 | | |
2690 | 55.8k | if (Failed(result)) { |
2691 | 6.26k | Error(loc, "invalid literal \"%s\"", token.to_string().c_str()); |
2692 | 6.26k | return Result::Error; |
2693 | 6.26k | } |
2694 | 55.8k | } |
2695 | | |
2696 | 19.9k | return Result::Ok; |
2697 | 32.2k | } |
2698 | | |
2699 | 0 | Result WastParser::ParseExpectedNan(ExpectedNan* expected) { |
2700 | 0 | WABT_TRACE(ParseExpectedNan); |
2701 | 0 | TokenType token_type = Peek(); |
2702 | 0 | switch (token_type) { |
2703 | 0 | case TokenType::NanArithmetic: |
2704 | 0 | *expected = ExpectedNan::Arithmetic; |
2705 | 0 | break; |
2706 | 0 | case TokenType::NanCanonical: |
2707 | 0 | *expected = ExpectedNan::Canonical; |
2708 | 0 | break; |
2709 | 0 | default: |
2710 | 0 | return Result::Error; |
2711 | 0 | } |
2712 | 0 | Consume(); |
2713 | 0 | return Result::Ok; |
2714 | 0 | } |
2715 | | |
2716 | 209k | Result WastParser::ParseF32(Const* const_, ConstType const_type) { |
2717 | 209k | ExpectedNan expected; |
2718 | 209k | if (const_type == ConstType::Expectation && |
2719 | 209k | Succeeded(ParseExpectedNan(&expected))) { |
2720 | 0 | const_->set_f32(expected); |
2721 | 0 | return Result::Ok; |
2722 | 0 | } |
2723 | | |
2724 | 209k | auto token = Consume(); |
2725 | 209k | if (!token.HasLiteral()) { |
2726 | 195 | return Result::Error; |
2727 | 195 | } |
2728 | | |
2729 | 208k | auto literal = token.literal(); |
2730 | 208k | uint32_t f32_bits; |
2731 | 208k | Result result = ParseFloat(literal.type, literal.text, &f32_bits); |
2732 | 208k | const_->set_f32(f32_bits); |
2733 | 208k | return result; |
2734 | 209k | } |
2735 | | |
2736 | 149k | Result WastParser::ParseF64(Const* const_, ConstType const_type) { |
2737 | 149k | ExpectedNan expected; |
2738 | 149k | if (const_type == ConstType::Expectation && |
2739 | 149k | Succeeded(ParseExpectedNan(&expected))) { |
2740 | 0 | const_->set_f64(expected); |
2741 | 0 | return Result::Ok; |
2742 | 0 | } |
2743 | | |
2744 | 149k | auto token = Consume(); |
2745 | 149k | if (!token.HasLiteral()) { |
2746 | 350 | return Result::Error; |
2747 | 350 | } |
2748 | | |
2749 | 149k | auto literal = token.literal(); |
2750 | 149k | uint64_t f64_bits; |
2751 | 149k | Result result = ParseDouble(literal.type, literal.text, &f64_bits); |
2752 | 149k | const_->set_f64(f64_bits); |
2753 | 149k | return result; |
2754 | 149k | } |
2755 | | |
2756 | 417k | Result WastParser::ParseConst(Const* const_, ConstType const_type) { |
2757 | 417k | WABT_TRACE(ParseConst); |
2758 | 417k | Token opcode_token = Consume(); |
2759 | 417k | Opcode opcode = opcode_token.opcode(); |
2760 | 417k | const_->loc = GetLocation(); |
2761 | 417k | Token token = GetToken(); |
2762 | | |
2763 | | // V128 is fully handled by ParseSimdV128Const: |
2764 | 417k | if (opcode != Opcode::V128Const) { |
2765 | 381k | switch (token.token_type()) { |
2766 | 35.0k | case TokenType::Nat: |
2767 | 36.7k | case TokenType::Int: |
2768 | 326k | case TokenType::Float: |
2769 | | // OK. |
2770 | 326k | break; |
2771 | 396 | case TokenType::NanArithmetic: |
2772 | 794 | case TokenType::NanCanonical: |
2773 | 794 | break; |
2774 | 53.7k | default: |
2775 | 53.7k | return ErrorExpected({"a numeric literal"}, "123, -45, 6.7e8"); |
2776 | 381k | } |
2777 | 381k | } |
2778 | | |
2779 | 363k | Result result; |
2780 | 363k | switch (opcode) { |
2781 | 8.46k | case Opcode::I32Const: { |
2782 | 8.46k | auto token = Consume(); |
2783 | 8.46k | if (!token.HasLiteral()) { |
2784 | 327 | return Result::Error; |
2785 | 327 | } |
2786 | 8.13k | auto sv = token.literal().text; |
2787 | 8.13k | uint32_t u32; |
2788 | 8.13k | result = ParseInt32(sv, &u32, ParseIntType::SignedAndUnsigned); |
2789 | 8.13k | const_->set_u32(u32); |
2790 | 8.13k | break; |
2791 | 8.46k | } |
2792 | | |
2793 | 1.14k | case Opcode::I64Const: { |
2794 | 1.14k | auto token = Consume(); |
2795 | 1.14k | if (!token.HasLiteral()) { |
2796 | 206 | return Result::Error; |
2797 | 206 | } |
2798 | 940 | auto sv = token.literal().text; |
2799 | 940 | uint64_t u64; |
2800 | 940 | result = ParseInt64(sv, &u64, ParseIntType::SignedAndUnsigned); |
2801 | 940 | const_->set_u64(u64); |
2802 | 940 | break; |
2803 | 1.14k | } |
2804 | | |
2805 | 207k | case Opcode::F32Const: |
2806 | 207k | result = ParseF32(const_, const_type); |
2807 | 207k | break; |
2808 | | |
2809 | 109k | case Opcode::F64Const: |
2810 | 109k | result = ParseF64(const_, const_type); |
2811 | 109k | break; |
2812 | | |
2813 | 36.5k | case Opcode::V128Const: |
2814 | 36.5k | ErrorUnlessOpcodeEnabled(opcode_token); |
2815 | | // Parse V128 Simd Const (16 bytes). |
2816 | 36.5k | result = ParseSimdV128Const(const_, token.token_type(), const_type); |
2817 | | // ParseSimdV128Const report error already, just return here if parser get |
2818 | | // errors. |
2819 | 36.5k | if (Failed(result)) { |
2820 | 16.6k | return Result::Error; |
2821 | 16.6k | } |
2822 | 19.9k | break; |
2823 | | |
2824 | 19.9k | default: |
2825 | 0 | assert(!"ParseConst called with invalid opcode"); |
2826 | 0 | return Result::Error; |
2827 | 363k | } |
2828 | | |
2829 | 346k | if (Failed(result)) { |
2830 | 20.2k | Error(const_->loc, "invalid literal \"%s\"", token.to_string().c_str()); |
2831 | | // Return if parser get errors. |
2832 | 20.2k | return Result::Error; |
2833 | 20.2k | } |
2834 | | |
2835 | 326k | return Result::Ok; |
2836 | 346k | } |
2837 | | |
2838 | 0 | Result WastParser::ParseExternref(Const* const_) { |
2839 | 0 | WABT_TRACE(ParseExternref); |
2840 | 0 | Token token = Consume(); |
2841 | 0 | if (!options_->features.reference_types_enabled()) { |
2842 | 0 | Error(token.loc, "externref not allowed"); |
2843 | 0 | return Result::Error; |
2844 | 0 | } |
2845 | | |
2846 | 0 | Literal literal; |
2847 | 0 | std::string_view sv; |
2848 | 0 | const_->loc = GetLocation(); |
2849 | 0 | TokenType token_type = Peek(); |
2850 | |
|
2851 | 0 | switch (token_type) { |
2852 | 0 | case TokenType::Nat: |
2853 | 0 | case TokenType::Int: { |
2854 | 0 | literal = Consume().literal(); |
2855 | 0 | sv = literal.text; |
2856 | 0 | break; |
2857 | 0 | } |
2858 | 0 | default: |
2859 | 0 | return ErrorExpected({"a numeric literal"}, "123"); |
2860 | 0 | } |
2861 | | |
2862 | 0 | uint64_t ref_bits; |
2863 | 0 | Result result = ParseInt64(sv, &ref_bits, ParseIntType::UnsignedOnly); |
2864 | |
|
2865 | 0 | const_->set_externref(static_cast<uintptr_t>(ref_bits)); |
2866 | |
|
2867 | 0 | if (Failed(result)) { |
2868 | 0 | Error(const_->loc, "invalid literal \"" PRIstringview "\"", |
2869 | 0 | WABT_PRINTF_STRING_VIEW_ARG(literal.text)); |
2870 | | // Return if parser get errors. |
2871 | 0 | return Result::Error; |
2872 | 0 | } |
2873 | | |
2874 | 0 | return Result::Ok; |
2875 | 0 | } |
2876 | | |
2877 | 0 | Result WastParser::ParseConstList(ConstVector* consts, ConstType type) { |
2878 | 0 | WABT_TRACE(ParseConstList); |
2879 | 0 | while (PeekMatchLpar(TokenType::Const) || PeekMatchLpar(TokenType::RefNull) || |
2880 | 0 | PeekMatchLpar(TokenType::RefExtern) || |
2881 | 0 | PeekMatchLpar(TokenType::RefFunc)) { |
2882 | 0 | Consume(); |
2883 | 0 | Const const_; |
2884 | 0 | switch (Peek()) { |
2885 | 0 | case TokenType::Const: |
2886 | 0 | CHECK_RESULT(ParseConst(&const_, type)); |
2887 | 0 | break; |
2888 | 0 | case TokenType::RefNull: { |
2889 | 0 | auto token = Consume(); |
2890 | 0 | Type type; |
2891 | 0 | CHECK_RESULT(ParseRefKind(&type)); |
2892 | 0 | ErrorUnlessOpcodeEnabled(token); |
2893 | 0 | const_.loc = GetLocation(); |
2894 | 0 | const_.set_null(type); |
2895 | 0 | break; |
2896 | 0 | } |
2897 | 0 | case TokenType::RefFunc: { |
2898 | 0 | auto token = Consume(); |
2899 | 0 | ErrorUnlessOpcodeEnabled(token); |
2900 | 0 | const_.loc = GetLocation(); |
2901 | 0 | const_.set_funcref(); |
2902 | 0 | break; |
2903 | 0 | } |
2904 | 0 | case TokenType::RefExtern: |
2905 | 0 | CHECK_RESULT(ParseExternref(&const_)); |
2906 | 0 | break; |
2907 | 0 | default: |
2908 | 0 | assert(!"unreachable"); |
2909 | 0 | return Result::Error; |
2910 | 0 | } |
2911 | 0 | EXPECT(Rpar); |
2912 | 0 | consts->push_back(const_); |
2913 | 0 | } |
2914 | | |
2915 | 0 | return Result::Ok; |
2916 | 0 | } |
2917 | | |
2918 | 46.8k | Result WastParser::ParseBlockInstr(std::unique_ptr<Expr>* out_expr) { |
2919 | 46.8k | WABT_TRACE(ParseBlockInstr); |
2920 | 46.8k | Location loc = GetLocation(); |
2921 | | |
2922 | 46.8k | switch (Peek()) { |
2923 | 2.25k | case TokenType::Block: { |
2924 | 2.25k | Consume(); |
2925 | 2.25k | auto expr = std::make_unique<BlockExpr>(loc); |
2926 | 2.25k | CHECK_RESULT(ParseLabelOpt(&expr->block.label)); |
2927 | 2.25k | CHECK_RESULT(ParseBlock(&expr->block)); |
2928 | 1.34k | EXPECT(End); |
2929 | 197 | CHECK_RESULT(ParseEndLabelOpt(expr->block.label)); |
2930 | 197 | *out_expr = std::move(expr); |
2931 | 197 | break; |
2932 | 197 | } |
2933 | | |
2934 | 1.41k | case TokenType::Loop: { |
2935 | 1.41k | Consume(); |
2936 | 1.41k | auto expr = std::make_unique<LoopExpr>(loc); |
2937 | 1.41k | CHECK_RESULT(ParseLabelOpt(&expr->block.label)); |
2938 | 1.41k | CHECK_RESULT(ParseBlock(&expr->block)); |
2939 | 906 | EXPECT(End); |
2940 | 194 | CHECK_RESULT(ParseEndLabelOpt(expr->block.label)); |
2941 | 194 | *out_expr = std::move(expr); |
2942 | 194 | break; |
2943 | 194 | } |
2944 | | |
2945 | 21.8k | case TokenType::If: { |
2946 | 21.8k | Consume(); |
2947 | 21.8k | auto expr = std::make_unique<IfExpr>(loc); |
2948 | 21.8k | CHECK_RESULT(ParseLabelOpt(&expr->true_.label)); |
2949 | 21.8k | CHECK_RESULT(ParseBlock(&expr->true_)); |
2950 | 11.0k | if (Match(TokenType::Else)) { |
2951 | 1.67k | CHECK_RESULT(ParseEndLabelOpt(expr->true_.label)); |
2952 | 1.67k | CHECK_RESULT(ParseTerminatingInstrList(&expr->false_)); |
2953 | 368 | expr->false_end_loc = GetLocation(); |
2954 | 368 | } |
2955 | 9.71k | EXPECT(End); |
2956 | 4.31k | CHECK_RESULT(ParseEndLabelOpt(expr->true_.label)); |
2957 | 4.31k | *out_expr = std::move(expr); |
2958 | 4.31k | break; |
2959 | 4.31k | } |
2960 | | |
2961 | 21.2k | case TokenType::Try: { |
2962 | 21.2k | ErrorUnlessOpcodeEnabled(Consume()); |
2963 | 21.2k | auto expr = std::make_unique<TryExpr>(loc); |
2964 | 21.2k | CatchVector catches; |
2965 | 21.2k | CHECK_RESULT(ParseLabelOpt(&expr->block.label)); |
2966 | 21.2k | CHECK_RESULT(ParseBlock(&expr->block)); |
2967 | 19.4k | if (IsCatch(Peek())) { |
2968 | 1.87k | CHECK_RESULT(ParseCatchInstrList(&expr->catches)); |
2969 | 625 | expr->kind = TryKind::Catch; |
2970 | 17.5k | } else if (PeekMatch(TokenType::Delegate)) { |
2971 | 0 | Consume(); |
2972 | 0 | Var var; |
2973 | 0 | CHECK_RESULT(ParseVar(&var)); |
2974 | 0 | expr->delegate_target = var; |
2975 | 0 | expr->kind = TryKind::Delegate; |
2976 | 0 | } |
2977 | 18.1k | CHECK_RESULT(ErrorIfLpar({"a valid try clause"})); |
2978 | 13.8k | expr->block.end_loc = GetLocation(); |
2979 | 13.8k | if (expr->kind != TryKind::Delegate) { |
2980 | 13.8k | EXPECT(End); |
2981 | 13.8k | } |
2982 | 743 | CHECK_RESULT(ParseEndLabelOpt(expr->block.label)); |
2983 | 743 | *out_expr = std::move(expr); |
2984 | 743 | break; |
2985 | 743 | } |
2986 | | |
2987 | 0 | default: |
2988 | 0 | assert( |
2989 | 0 | !"ParseBlockInstr should only be called when IsBlockInstr() is true"); |
2990 | 0 | return Result::Error; |
2991 | 46.8k | } |
2992 | | |
2993 | 5.45k | return Result::Ok; |
2994 | 46.8k | } |
2995 | | |
2996 | 223k | Result WastParser::ParseLabelOpt(std::string* out_label) { |
2997 | 223k | WABT_TRACE(ParseLabelOpt); |
2998 | 223k | if (PeekMatch(TokenType::Var)) { |
2999 | 13.9k | *out_label = std::string(Consume().text()); |
3000 | 209k | } else { |
3001 | 209k | out_label->clear(); |
3002 | 209k | } |
3003 | 223k | return Result::Ok; |
3004 | 223k | } |
3005 | | |
3006 | 7.13k | Result WastParser::ParseEndLabelOpt(const std::string& begin_label) { |
3007 | 7.13k | WABT_TRACE(ParseEndLabelOpt); |
3008 | 7.13k | Location loc = GetLocation(); |
3009 | 7.13k | std::string end_label; |
3010 | 7.13k | CHECK_RESULT(ParseLabelOpt(&end_label)); |
3011 | 7.13k | if (!end_label.empty()) { |
3012 | 2.63k | if (begin_label.empty()) { |
3013 | 412 | Error(loc, "unexpected label \"%s\"", end_label.c_str()); |
3014 | 2.22k | } else if (begin_label != end_label) { |
3015 | 1.88k | Error(loc, "mismatching label \"%s\" != \"%s\"", begin_label.c_str(), |
3016 | 1.88k | end_label.c_str()); |
3017 | 1.88k | } |
3018 | 2.63k | } |
3019 | 7.13k | return Result::Ok; |
3020 | 7.13k | } |
3021 | | |
3022 | 216k | Result WastParser::ParseBlockDeclaration(BlockDeclaration* decl) { |
3023 | 216k | WABT_TRACE(ParseBlockDeclaration); |
3024 | 216k | FuncDeclaration func_decl; |
3025 | 216k | CHECK_RESULT(ParseTypeUseOpt(&func_decl)); |
3026 | 207k | CHECK_RESULT(ParseUnboundFuncSignature(&func_decl.sig)); |
3027 | 206k | decl->has_func_type = func_decl.has_func_type; |
3028 | 206k | decl->type_var = func_decl.type_var; |
3029 | 206k | decl->sig = func_decl.sig; |
3030 | 206k | return Result::Ok; |
3031 | 207k | } |
3032 | | |
3033 | 118k | Result WastParser::ParseBlock(Block* block) { |
3034 | 118k | WABT_TRACE(ParseBlock); |
3035 | 118k | CHECK_RESULT(ParseBlockDeclaration(&block->decl)); |
3036 | 115k | CHECK_RESULT(ParseInstrList(&block->exprs)); |
3037 | 90.4k | block->end_loc = GetLocation(); |
3038 | 90.4k | return Result::Ok; |
3039 | 115k | } |
3040 | | |
3041 | 494k | Result WastParser::ParseExprList(ExprList* exprs) { |
3042 | 494k | WABT_TRACE(ParseExprList); |
3043 | 494k | ExprList new_exprs; |
3044 | 815k | while (PeekMatchExpr()) { |
3045 | 426k | if (Succeeded(ParseExpr(&new_exprs))) { |
3046 | 151k | exprs->splice(exprs->end(), new_exprs); |
3047 | 274k | } else { |
3048 | 274k | CHECK_RESULT(Synchronize(IsExpr)); |
3049 | 274k | } |
3050 | 426k | } |
3051 | 389k | return Result::Ok; |
3052 | 494k | } |
3053 | | |
3054 | 762k | Result WastParser::ParseExpr(ExprList* exprs) { |
3055 | 762k | WABT_TRACE(ParseExpr); |
3056 | 762k | if (!PeekMatch(TokenType::Lpar)) { |
3057 | 0 | return Result::Error; |
3058 | 0 | } |
3059 | | |
3060 | 762k | if (IsPlainInstr(Peek(1))) { |
3061 | 592k | Consume(); |
3062 | 592k | std::unique_ptr<Expr> expr; |
3063 | 592k | CHECK_RESULT(ParsePlainInstr(&expr)); |
3064 | 494k | CHECK_RESULT(ParseExprList(exprs)); |
3065 | 389k | CHECK_RESULT(ErrorIfLpar({"an expr"})); |
3066 | 241k | exprs->push_back(std::move(expr)); |
3067 | 241k | } else { |
3068 | 169k | Location loc = GetLocation(); |
3069 | | |
3070 | 169k | switch (Peek(1)) { |
3071 | 14.0k | case TokenType::Block: { |
3072 | 14.0k | Consume(); |
3073 | 14.0k | Consume(); |
3074 | 14.0k | auto expr = std::make_unique<BlockExpr>(loc); |
3075 | 14.0k | CHECK_RESULT(ParseLabelOpt(&expr->block.label)); |
3076 | 14.0k | CHECK_RESULT(ParseBlock(&expr->block)); |
3077 | 12.6k | exprs->push_back(std::move(expr)); |
3078 | 12.6k | break; |
3079 | 14.0k | } |
3080 | | |
3081 | 57.7k | case TokenType::Loop: { |
3082 | 57.7k | Consume(); |
3083 | 57.7k | Consume(); |
3084 | 57.7k | auto expr = std::make_unique<LoopExpr>(loc); |
3085 | 57.7k | CHECK_RESULT(ParseLabelOpt(&expr->block.label)); |
3086 | 57.7k | CHECK_RESULT(ParseBlock(&expr->block)); |
3087 | 45.0k | exprs->push_back(std::move(expr)); |
3088 | 45.0k | break; |
3089 | 57.7k | } |
3090 | | |
3091 | 84.7k | case TokenType::If: { |
3092 | 84.7k | Consume(); |
3093 | 84.7k | Consume(); |
3094 | 84.7k | auto expr = std::make_unique<IfExpr>(loc); |
3095 | | |
3096 | 84.7k | CHECK_RESULT(ParseLabelOpt(&expr->true_.label)); |
3097 | 84.7k | CHECK_RESULT(ParseBlockDeclaration(&expr->true_.decl)); |
3098 | | |
3099 | 82.3k | while (PeekMatchExpr()) { |
3100 | 62.6k | ExprList cond; |
3101 | 62.6k | CHECK_RESULT(ParseExpr(&cond)); |
3102 | 4.05k | exprs->splice(exprs->end(), cond); |
3103 | 4.05k | } |
3104 | | |
3105 | 19.6k | EXPECT(Lpar); |
3106 | 17.5k | if (!Match(TokenType::Then)) { |
3107 | 13.2k | return ErrorExpected({"then block"}, "(then ...)"); |
3108 | 13.2k | } |
3109 | | |
3110 | 4.27k | CHECK_RESULT(ParseTerminatingInstrList(&expr->true_.exprs)); |
3111 | 1.90k | expr->true_.end_loc = GetLocation(); |
3112 | 1.90k | EXPECT(Rpar); |
3113 | | |
3114 | 1.30k | if (MatchLpar(TokenType::Else)) { |
3115 | 726 | CHECK_RESULT(ParseTerminatingInstrList(&expr->false_)); |
3116 | 531 | EXPECT(Rpar); |
3117 | 531 | } |
3118 | 902 | expr->false_end_loc = GetLocation(); |
3119 | | |
3120 | 902 | exprs->push_back(std::move(expr)); |
3121 | 902 | break; |
3122 | 1.30k | } |
3123 | | |
3124 | 12.8k | case TokenType::Try: { |
3125 | 12.8k | Consume(); |
3126 | 12.8k | ErrorUnlessOpcodeEnabled(Consume()); |
3127 | | |
3128 | 12.8k | auto expr = std::make_unique<TryExpr>(loc); |
3129 | 12.8k | CHECK_RESULT(ParseLabelOpt(&expr->block.label)); |
3130 | 12.8k | CHECK_RESULT(ParseBlockDeclaration(&expr->block.decl)); |
3131 | 12.4k | EXPECT(Lpar); |
3132 | 11.4k | EXPECT(Do); |
3133 | 7.45k | CHECK_RESULT(ParseInstrList(&expr->block.exprs)); |
3134 | 7.22k | EXPECT(Rpar); |
3135 | 6.92k | if (PeekMatch(TokenType::Lpar)) { |
3136 | 5.64k | Consume(); |
3137 | 5.64k | TokenType type = Peek(); |
3138 | 5.64k | switch (type) { |
3139 | 2.88k | case TokenType::Catch: |
3140 | 3.72k | case TokenType::CatchAll: |
3141 | 3.72k | CHECK_RESULT(ParseCatchExprList(&expr->catches)); |
3142 | 1.65k | expr->kind = TryKind::Catch; |
3143 | 1.65k | break; |
3144 | 0 | case TokenType::Delegate: { |
3145 | 0 | Consume(); |
3146 | 0 | Var var; |
3147 | 0 | CHECK_RESULT(ParseVar(&var)); |
3148 | 0 | expr->delegate_target = var; |
3149 | 0 | expr->kind = TryKind::Delegate; |
3150 | 0 | EXPECT(Rpar); |
3151 | 0 | break; |
3152 | 0 | } |
3153 | 1.92k | default: |
3154 | 1.92k | ErrorExpected({"catch", "catch_all", "delegate"}); |
3155 | 1.92k | break; |
3156 | 5.64k | } |
3157 | 5.64k | } |
3158 | 4.86k | CHECK_RESULT(ErrorIfLpar({"a valid try clause"})); |
3159 | 4.56k | expr->block.end_loc = GetLocation(); |
3160 | 4.56k | exprs->push_back(std::move(expr)); |
3161 | 4.56k | break; |
3162 | 4.86k | } |
3163 | | |
3164 | 0 | default: |
3165 | 0 | assert(!"ParseExpr should only be called when IsExpr() is true"); |
3166 | 0 | return Result::Error; |
3167 | 169k | } |
3168 | 169k | } |
3169 | | |
3170 | 304k | EXPECT(Rpar); |
3171 | 179k | return Result::Ok; |
3172 | 304k | } |
3173 | | |
3174 | 1.87k | Result WastParser::ParseCatchInstrList(CatchVector* catches) { |
3175 | 1.87k | WABT_TRACE(ParseCatchInstrList); |
3176 | 1.87k | bool parsedCatch = false; |
3177 | 1.87k | bool parsedCatchAll = false; |
3178 | | |
3179 | 3.99k | while (IsCatch(Peek())) { |
3180 | 3.37k | Catch catch_(GetLocation()); |
3181 | | |
3182 | 3.37k | auto token = Consume(); |
3183 | 3.37k | if (token.token_type() == TokenType::Catch) { |
3184 | 2.63k | CHECK_RESULT(ParseVar(&catch_.var)); |
3185 | 2.63k | } else { |
3186 | 738 | if (parsedCatchAll) { |
3187 | 199 | Error(token.loc, "multiple catch_all clauses not allowed"); |
3188 | 199 | return Result::Error; |
3189 | 199 | } |
3190 | 539 | parsedCatchAll = true; |
3191 | 539 | } |
3192 | | |
3193 | 2.95k | CHECK_RESULT(ParseInstrList(&catch_.exprs)); |
3194 | 2.12k | catches->push_back(std::move(catch_)); |
3195 | 2.12k | parsedCatch = true; |
3196 | 2.12k | } |
3197 | | |
3198 | 625 | if (!parsedCatch) { |
3199 | 0 | return ErrorExpected({"catch"}); |
3200 | 0 | } |
3201 | | |
3202 | 625 | return Result::Ok; |
3203 | 625 | } |
3204 | | |
3205 | 3.72k | Result WastParser::ParseCatchExprList(CatchVector* catches) { |
3206 | 3.72k | WABT_TRACE(ParseCatchExprList); |
3207 | 3.72k | bool parsedCatchAll = false; |
3208 | | |
3209 | 22.8k | do { |
3210 | 22.8k | Catch catch_(GetLocation()); |
3211 | | |
3212 | 22.8k | auto token = Consume(); |
3213 | 22.8k | if (token.token_type() == TokenType::Catch) { |
3214 | 21.7k | CHECK_RESULT(ParseVar(&catch_.var)); |
3215 | 21.7k | } else { |
3216 | 1.10k | if (parsedCatchAll) { |
3217 | 270 | Error(token.loc, "multiple catch_all clauses not allowed"); |
3218 | 270 | return Result::Error; |
3219 | 270 | } |
3220 | 839 | parsedCatchAll = true; |
3221 | 839 | } |
3222 | | |
3223 | 22.3k | CHECK_RESULT(ParseTerminatingInstrList(&catch_.exprs)); |
3224 | 21.4k | EXPECT(Rpar); |
3225 | 20.8k | catches->push_back(std::move(catch_)); |
3226 | 20.8k | } while (Match(TokenType::Lpar) && IsCatch(Peek())); |
3227 | | |
3228 | 1.65k | return Result::Ok; |
3229 | 3.72k | } |
3230 | | |
3231 | 68.7k | Result WastParser::ParseGlobalType(Global* global) { |
3232 | 68.7k | WABT_TRACE(ParseGlobalType); |
3233 | 68.7k | if (MatchLpar(TokenType::Mut)) { |
3234 | 1.40k | global->mutable_ = true; |
3235 | 1.40k | Var type; |
3236 | 1.40k | CHECK_RESULT(ParseValueType(&type)); |
3237 | 1.11k | global->type = Type(type.index()); |
3238 | 1.11k | CHECK_RESULT(ErrorIfLpar({"i32", "i64", "f32", "f64"})); |
3239 | 851 | EXPECT(Rpar); |
3240 | 67.3k | } else { |
3241 | 67.3k | Var type; |
3242 | 67.3k | CHECK_RESULT(ParseValueType(&type)); |
3243 | 56.7k | global->type = Type(type.index()); |
3244 | 56.7k | } |
3245 | | |
3246 | 56.9k | return Result::Ok; |
3247 | 68.7k | } |
3248 | | |
3249 | | Result WastParser::ParseCommandList(Script* script, |
3250 | 0 | CommandPtrVector* commands) { |
3251 | 0 | WABT_TRACE(ParseCommandList); |
3252 | 0 | while (IsCommand(PeekPair())) { |
3253 | 0 | CommandPtr command; |
3254 | 0 | if (Succeeded(ParseCommand(script, &command))) { |
3255 | 0 | commands->push_back(std::move(command)); |
3256 | 0 | } else { |
3257 | 0 | CHECK_RESULT(Synchronize(IsCommand)); |
3258 | 0 | } |
3259 | 0 | } |
3260 | 0 | return Result::Ok; |
3261 | 0 | } |
3262 | | |
3263 | 0 | Result WastParser::ParseCommand(Script* script, CommandPtr* out_command) { |
3264 | 0 | WABT_TRACE(ParseCommand); |
3265 | 0 | switch (Peek(1)) { |
3266 | 0 | case TokenType::AssertException: |
3267 | 0 | return ParseAssertExceptionCommand(out_command); |
3268 | | |
3269 | 0 | case TokenType::AssertExhaustion: |
3270 | 0 | return ParseAssertExhaustionCommand(out_command); |
3271 | | |
3272 | 0 | case TokenType::AssertInvalid: |
3273 | 0 | return ParseAssertInvalidCommand(out_command); |
3274 | | |
3275 | 0 | case TokenType::AssertMalformed: |
3276 | 0 | return ParseAssertMalformedCommand(out_command); |
3277 | | |
3278 | 0 | case TokenType::AssertReturn: |
3279 | 0 | return ParseAssertReturnCommand(out_command); |
3280 | | |
3281 | 0 | case TokenType::AssertTrap: |
3282 | 0 | return ParseAssertTrapCommand(out_command); |
3283 | | |
3284 | 0 | case TokenType::AssertUnlinkable: |
3285 | 0 | return ParseAssertUnlinkableCommand(out_command); |
3286 | | |
3287 | 0 | case TokenType::Get: |
3288 | 0 | case TokenType::Invoke: |
3289 | 0 | return ParseActionCommand(out_command); |
3290 | | |
3291 | 0 | case TokenType::Module: |
3292 | 0 | return ParseModuleCommand(script, out_command); |
3293 | | |
3294 | 0 | case TokenType::Register: |
3295 | 0 | return ParseRegisterCommand(out_command); |
3296 | | |
3297 | 0 | case TokenType::Input: |
3298 | 0 | return ParseInputCommand(out_command); |
3299 | | |
3300 | 0 | case TokenType::Output: |
3301 | 0 | return ParseOutputCommand(out_command); |
3302 | | |
3303 | 0 | default: |
3304 | 0 | assert(!"ParseCommand should only be called when IsCommand() is true"); |
3305 | 0 | return Result::Error; |
3306 | 0 | } |
3307 | 0 | } |
3308 | | |
3309 | 0 | Result WastParser::ParseAssertExceptionCommand(CommandPtr* out_command) { |
3310 | 0 | WABT_TRACE(ParseAssertExceptionCommand); |
3311 | 0 | return ParseAssertActionCommand<AssertExceptionCommand>( |
3312 | 0 | TokenType::AssertException, out_command); |
3313 | 0 | } |
3314 | | |
3315 | 0 | Result WastParser::ParseAssertExhaustionCommand(CommandPtr* out_command) { |
3316 | 0 | WABT_TRACE(ParseAssertExhaustionCommand); |
3317 | 0 | return ParseAssertActionTextCommand<AssertExhaustionCommand>( |
3318 | 0 | TokenType::AssertExhaustion, out_command); |
3319 | 0 | } |
3320 | | |
3321 | 0 | Result WastParser::ParseAssertInvalidCommand(CommandPtr* out_command) { |
3322 | 0 | WABT_TRACE(ParseAssertInvalidCommand); |
3323 | 0 | return ParseAssertScriptModuleCommand<AssertInvalidCommand>( |
3324 | 0 | TokenType::AssertInvalid, out_command); |
3325 | 0 | } |
3326 | | |
3327 | 0 | Result WastParser::ParseAssertMalformedCommand(CommandPtr* out_command) { |
3328 | 0 | WABT_TRACE(ParseAssertMalformedCommand); |
3329 | 0 | return ParseAssertScriptModuleCommand<AssertMalformedCommand>( |
3330 | 0 | TokenType::AssertMalformed, out_command); |
3331 | 0 | } |
3332 | | |
3333 | 0 | Result WastParser::ParseAssertReturnCommand(CommandPtr* out_command) { |
3334 | 0 | WABT_TRACE(ParseAssertReturnCommand); |
3335 | 0 | EXPECT(Lpar); |
3336 | 0 | EXPECT(AssertReturn); |
3337 | 0 | auto command = std::make_unique<AssertReturnCommand>(); |
3338 | 0 | CHECK_RESULT(ParseAction(&command->action)); |
3339 | 0 | CHECK_RESULT(ParseExpectedValues(&command->expected)); |
3340 | 0 | EXPECT(Rpar); |
3341 | 0 | *out_command = std::move(command); |
3342 | 0 | return Result::Ok; |
3343 | 0 | } |
3344 | | |
3345 | 0 | Result WastParser::ParseAssertTrapCommand(CommandPtr* out_command) { |
3346 | 0 | WABT_TRACE(ParseAssertTrapCommand); |
3347 | 0 | EXPECT(Lpar); |
3348 | 0 | EXPECT(AssertTrap); |
3349 | 0 | if (PeekMatchLpar(TokenType::Module)) { |
3350 | 0 | auto command = std::make_unique<AssertUninstantiableCommand>(); |
3351 | 0 | CHECK_RESULT(ParseScriptModule(&command->module)); |
3352 | 0 | CHECK_RESULT(ParseQuotedText(&command->text)); |
3353 | 0 | *out_command = std::move(command); |
3354 | 0 | } else { |
3355 | 0 | auto command = std::make_unique<AssertTrapCommand>(); |
3356 | 0 | CHECK_RESULT(ParseAction(&command->action)); |
3357 | 0 | CHECK_RESULT(ParseQuotedText(&command->text)); |
3358 | 0 | *out_command = std::move(command); |
3359 | 0 | } |
3360 | 0 | EXPECT(Rpar); |
3361 | 0 | return Result::Ok; |
3362 | 0 | } |
3363 | | |
3364 | 0 | Result WastParser::ParseAssertUnlinkableCommand(CommandPtr* out_command) { |
3365 | 0 | WABT_TRACE(ParseAssertUnlinkableCommand); |
3366 | 0 | return ParseAssertScriptModuleCommand<AssertUnlinkableCommand>( |
3367 | 0 | TokenType::AssertUnlinkable, out_command); |
3368 | 0 | } |
3369 | | |
3370 | 0 | Result WastParser::ParseActionCommand(CommandPtr* out_command) { |
3371 | 0 | WABT_TRACE(ParseActionCommand); |
3372 | 0 | auto command = std::make_unique<ActionCommand>(); |
3373 | 0 | CHECK_RESULT(ParseAction(&command->action)); |
3374 | 0 | *out_command = std::move(command); |
3375 | 0 | return Result::Ok; |
3376 | 0 | } |
3377 | | |
3378 | 128 | Result WastParser::ParseModuleCommand(Script* script, CommandPtr* out_command) { |
3379 | 128 | WABT_TRACE(ParseModuleCommand); |
3380 | 128 | std::unique_ptr<ScriptModule> script_module; |
3381 | 128 | CHECK_RESULT(ParseScriptModule(&script_module)); |
3382 | | |
3383 | 71 | Module* module = nullptr; |
3384 | | |
3385 | 71 | switch (script_module->type()) { |
3386 | 71 | case ScriptModuleType::Text: { |
3387 | 71 | auto command = std::make_unique<ModuleCommand>(); |
3388 | 71 | module = &command->module; |
3389 | 71 | *module = std::move(cast<TextScriptModule>(script_module.get())->module); |
3390 | 71 | *out_command = std::move(command); |
3391 | 71 | break; |
3392 | 0 | } |
3393 | | |
3394 | 0 | case ScriptModuleType::Binary: { |
3395 | 0 | auto command = std::make_unique<ScriptModuleCommand>(); |
3396 | 0 | module = &command->module; |
3397 | 0 | auto* bsm = cast<BinaryScriptModule>(script_module.get()); |
3398 | 0 | ReadBinaryOptions options; |
3399 | | #if WABT_TRACING |
3400 | | auto log_stream = FileStream::CreateStdout(); |
3401 | | options.log_stream = log_stream.get(); |
3402 | | #endif |
3403 | 0 | options.features = options_->features; |
3404 | 0 | Errors errors; |
3405 | 0 | const char* filename = "<text>"; |
3406 | 0 | ReadBinaryIr(filename, bsm->data.data(), bsm->data.size(), options, |
3407 | 0 | &errors, module); |
3408 | 0 | module->name = bsm->name; |
3409 | 0 | module->loc = bsm->loc; |
3410 | 0 | for (const auto& error : errors) { |
3411 | 0 | if (error.loc.offset == kInvalidOffset) { |
3412 | 0 | Error(bsm->loc, "error in binary module: %s", error.message.c_str()); |
3413 | 0 | } else { |
3414 | 0 | Error(bsm->loc, "error in binary module: @0x%08" PRIzx ": %s", |
3415 | 0 | error.loc.offset, error.message.c_str()); |
3416 | 0 | } |
3417 | 0 | } |
3418 | |
|
3419 | 0 | command->script_module = std::move(script_module); |
3420 | 0 | *out_command = std::move(command); |
3421 | 0 | break; |
3422 | 0 | } |
3423 | | |
3424 | 0 | case ScriptModuleType::Quoted: |
3425 | 0 | auto command = std::make_unique<ModuleCommand>(); |
3426 | 0 | module = &command->module; |
3427 | 0 | auto* qsm = cast<QuotedScriptModule>(script_module.get()); |
3428 | 0 | Errors errors; |
3429 | 0 | const char* filename = "<text>"; |
3430 | 0 | std::unique_ptr<Module> m; |
3431 | 0 | std::unique_ptr<WastLexer> lexer = WastLexer::CreateBufferLexer( |
3432 | 0 | filename, qsm->data.data(), qsm->data.size(), &errors); |
3433 | 0 | ParseWatModule(lexer.get(), &m, &errors, options_); |
3434 | 0 | for (const auto& error : errors) { |
3435 | 0 | if (error.loc.offset == kInvalidOffset) { |
3436 | 0 | Error(qsm->loc, "error in quoted module: %s", error.message.c_str()); |
3437 | 0 | } else { |
3438 | 0 | Error(qsm->loc, "error in quoted module: @0x%08" PRIzx ": %s", |
3439 | 0 | error.loc.offset, error.message.c_str()); |
3440 | 0 | } |
3441 | 0 | } |
3442 | 0 | *module = std::move(*m.get()); |
3443 | 0 | *out_command = std::move(command); |
3444 | 0 | break; |
3445 | 71 | } |
3446 | | |
3447 | | // script is nullptr when ParseModuleCommand is called from ParseModule. |
3448 | 71 | if (script) { |
3449 | 0 | Index command_index = script->commands.size(); |
3450 | |
|
3451 | 0 | if (!module->name.empty()) { |
3452 | 0 | script->module_bindings.emplace(module->name, |
3453 | 0 | Binding(module->loc, command_index)); |
3454 | 0 | } |
3455 | |
|
3456 | 0 | last_module_index_ = command_index; |
3457 | 0 | } |
3458 | | |
3459 | 71 | return Result::Ok; |
3460 | 71 | } |
3461 | | |
3462 | 0 | Result WastParser::ParseRegisterCommand(CommandPtr* out_command) { |
3463 | 0 | WABT_TRACE(ParseRegisterCommand); |
3464 | 0 | EXPECT(Lpar); |
3465 | 0 | Location loc = GetLocation(); |
3466 | 0 | EXPECT(Register); |
3467 | 0 | std::string text; |
3468 | 0 | Var var; |
3469 | 0 | CHECK_RESULT(ParseQuotedText(&text)); |
3470 | 0 | ParseVarOpt(&var, Var(last_module_index_, loc)); |
3471 | 0 | EXPECT(Rpar); |
3472 | 0 | out_command->reset(new RegisterCommand(text, var)); |
3473 | 0 | return Result::Ok; |
3474 | 0 | } |
3475 | | |
3476 | 0 | Result WastParser::ParseInputCommand(CommandPtr*) { |
3477 | | // Parse the input command, but always fail since this command is not |
3478 | | // actually supported. |
3479 | 0 | WABT_TRACE(ParseInputCommand); |
3480 | 0 | EXPECT(Lpar); |
3481 | 0 | Location loc = GetLocation(); |
3482 | 0 | EXPECT(Input); |
3483 | 0 | Error(loc, "input command is not supported"); |
3484 | 0 | Var var; |
3485 | 0 | std::string text; |
3486 | 0 | ParseVarOpt(&var); |
3487 | 0 | CHECK_RESULT(ParseQuotedText(&text)); |
3488 | 0 | EXPECT(Rpar); |
3489 | 0 | return Result::Error; |
3490 | 0 | } |
3491 | | |
3492 | 0 | Result WastParser::ParseOutputCommand(CommandPtr*) { |
3493 | | // Parse the output command, but always fail since this command is not |
3494 | | // actually supported. |
3495 | 0 | WABT_TRACE(ParseOutputCommand); |
3496 | 0 | EXPECT(Lpar); |
3497 | 0 | Location loc = GetLocation(); |
3498 | 0 | EXPECT(Output); |
3499 | 0 | Error(loc, "output command is not supported"); |
3500 | 0 | Var var; |
3501 | 0 | std::string text; |
3502 | 0 | ParseVarOpt(&var); |
3503 | 0 | if (Peek() == TokenType::Text) { |
3504 | 0 | CHECK_RESULT(ParseQuotedText(&text)); |
3505 | 0 | } |
3506 | 0 | EXPECT(Rpar); |
3507 | 0 | return Result::Error; |
3508 | 0 | } |
3509 | | |
3510 | 0 | Result WastParser::ParseAction(ActionPtr* out_action) { |
3511 | 0 | WABT_TRACE(ParseAction); |
3512 | 0 | EXPECT(Lpar); |
3513 | 0 | Location loc = GetLocation(); |
3514 | |
|
3515 | 0 | switch (Peek()) { |
3516 | 0 | case TokenType::Invoke: { |
3517 | 0 | Consume(); |
3518 | 0 | auto action = std::make_unique<InvokeAction>(loc); |
3519 | 0 | ParseVarOpt(&action->module_var, Var(last_module_index_, loc)); |
3520 | 0 | CHECK_RESULT(ParseQuotedText(&action->name)); |
3521 | 0 | CHECK_RESULT(ParseConstList(&action->args, ConstType::Normal)); |
3522 | 0 | *out_action = std::move(action); |
3523 | 0 | break; |
3524 | 0 | } |
3525 | | |
3526 | 0 | case TokenType::Get: { |
3527 | 0 | Consume(); |
3528 | 0 | auto action = std::make_unique<GetAction>(loc); |
3529 | 0 | ParseVarOpt(&action->module_var, Var(last_module_index_, loc)); |
3530 | 0 | CHECK_RESULT(ParseQuotedText(&action->name)); |
3531 | 0 | *out_action = std::move(action); |
3532 | 0 | break; |
3533 | 0 | } |
3534 | | |
3535 | 0 | default: |
3536 | 0 | return ErrorExpected({"invoke", "get"}); |
3537 | 0 | } |
3538 | 0 | EXPECT(Rpar); |
3539 | 0 | return Result::Ok; |
3540 | 0 | } |
3541 | | |
3542 | 0 | Result WastParser::ParseExpectedValues(ExpectationPtr* expectation) { |
3543 | 0 | WABT_TRACE(ParseExpectedValues); |
3544 | 0 | Location loc = GetLocation(); |
3545 | 0 | if (PeekMatchLpar(TokenType::Either)) { |
3546 | 0 | auto either = std::make_unique<EitherExpectation>(loc); |
3547 | 0 | CHECK_RESULT(ParseEither(&either->expected)); |
3548 | 0 | *expectation = std::move(either); |
3549 | 0 | } else { |
3550 | 0 | auto values = std::make_unique<ValueExpectation>(loc); |
3551 | 0 | CHECK_RESULT(ParseConstList(&values->expected, ConstType::Expectation)); |
3552 | 0 | *expectation = std::move(values); |
3553 | 0 | } |
3554 | 0 | return Result::Ok; |
3555 | 0 | } |
3556 | | |
3557 | 0 | Result WastParser::ParseEither(ConstVector* alternatives) { |
3558 | 0 | WABT_TRACE(ParseEither); |
3559 | 0 | MatchLpar(TokenType::Either); |
3560 | 0 | CHECK_RESULT(ParseConstList(alternatives, ConstType::Expectation)); |
3561 | 0 | EXPECT(Rpar); |
3562 | 0 | return Result::Ok; |
3563 | 0 | } |
3564 | | |
3565 | | Result WastParser::ParseScriptModule( |
3566 | 128 | std::unique_ptr<ScriptModule>* out_module) { |
3567 | 128 | WABT_TRACE(ParseScriptModule); |
3568 | 128 | EXPECT(Lpar); |
3569 | 128 | Location loc = GetLocation(); |
3570 | 128 | EXPECT(Module); |
3571 | 128 | std::string name; |
3572 | 128 | ParseBindVarOpt(&name); |
3573 | | |
3574 | 128 | switch (Peek()) { |
3575 | 0 | case TokenType::Bin: { |
3576 | 0 | Consume(); |
3577 | 0 | std::vector<uint8_t> data; |
3578 | | // TODO(binji): The spec allows this to be empty, switch to |
3579 | | // ParseTextListOpt. |
3580 | 0 | CHECK_RESULT(ParseTextList(&data)); |
3581 | | |
3582 | 0 | auto bsm = std::make_unique<BinaryScriptModule>(); |
3583 | 0 | bsm->name = name; |
3584 | 0 | bsm->loc = loc; |
3585 | 0 | bsm->data = std::move(data); |
3586 | 0 | *out_module = std::move(bsm); |
3587 | 0 | break; |
3588 | 0 | } |
3589 | | |
3590 | 0 | case TokenType::Quote: { |
3591 | 0 | Consume(); |
3592 | 0 | std::vector<uint8_t> data; |
3593 | | // TODO(binji): The spec allows this to be empty, switch to |
3594 | | // ParseTextListOpt. |
3595 | 0 | CHECK_RESULT(ParseTextList(&data)); |
3596 | | |
3597 | 0 | auto qsm = std::make_unique<QuotedScriptModule>(); |
3598 | 0 | qsm->name = name; |
3599 | 0 | qsm->loc = loc; |
3600 | 0 | qsm->data = std::move(data); |
3601 | 0 | *out_module = std::move(qsm); |
3602 | 0 | break; |
3603 | 0 | } |
3604 | | |
3605 | 128 | default: { |
3606 | 128 | auto tsm = std::make_unique<TextScriptModule>(); |
3607 | 128 | tsm->module.name = name; |
3608 | 128 | tsm->module.loc = loc; |
3609 | 128 | if (IsModuleField(PeekPair()) || PeekIsCustom()) { |
3610 | 113 | CHECK_RESULT(ParseModuleFieldList(&tsm->module)); |
3611 | 113 | } else if (!PeekMatch(TokenType::Rpar)) { |
3612 | 14 | ConsumeIfLpar(); |
3613 | 14 | return ErrorExpected({"a module field"}); |
3614 | 14 | } |
3615 | 72 | *out_module = std::move(tsm); |
3616 | 72 | break; |
3617 | 128 | } |
3618 | 128 | } |
3619 | | |
3620 | 72 | EXPECT(Rpar); |
3621 | 71 | return Result::Ok; |
3622 | 72 | } |
3623 | | |
3624 | | template <typename T> |
3625 | | Result WastParser::ParseAssertActionCommand(TokenType token_type, |
3626 | 0 | CommandPtr* out_command) { |
3627 | 0 | WABT_TRACE(ParseAssertActionCommand); |
3628 | 0 | EXPECT(Lpar); |
3629 | 0 | CHECK_RESULT(Expect(token_type)); |
3630 | 0 | auto command = std::make_unique<T>(); |
3631 | 0 | CHECK_RESULT(ParseAction(&command->action)); |
3632 | 0 | EXPECT(Rpar); |
3633 | 0 | *out_command = std::move(command); |
3634 | 0 | return Result::Ok; |
3635 | 0 | } |
3636 | | |
3637 | | template <typename T> |
3638 | | Result WastParser::ParseAssertActionTextCommand(TokenType token_type, |
3639 | 0 | CommandPtr* out_command) { |
3640 | 0 | WABT_TRACE(ParseAssertActionTextCommand); |
3641 | 0 | EXPECT(Lpar); |
3642 | 0 | CHECK_RESULT(Expect(token_type)); |
3643 | 0 | auto command = std::make_unique<T>(); |
3644 | 0 | CHECK_RESULT(ParseAction(&command->action)); |
3645 | 0 | CHECK_RESULT(ParseQuotedText(&command->text)); |
3646 | 0 | EXPECT(Rpar); |
3647 | 0 | *out_command = std::move(command); |
3648 | 0 | return Result::Ok; |
3649 | 0 | } |
3650 | | |
3651 | | template <typename T> |
3652 | | Result WastParser::ParseAssertScriptModuleCommand(TokenType token_type, |
3653 | 0 | CommandPtr* out_command) { |
3654 | 0 | WABT_TRACE(ParseAssertScriptModuleCommand); |
3655 | 0 | EXPECT(Lpar); |
3656 | 0 | CHECK_RESULT(Expect(token_type)); |
3657 | 0 | auto command = std::make_unique<T>(); |
3658 | 0 | CHECK_RESULT(ParseScriptModule(&command->module)); |
3659 | 0 | CHECK_RESULT(ParseQuotedText(&command->text)); |
3660 | 0 | EXPECT(Rpar); |
3661 | 0 | *out_command = std::move(command); |
3662 | 0 | return Result::Ok; |
3663 | 0 | } Unexecuted instantiation: wabt::Result wabt::WastParser::ParseAssertScriptModuleCommand<wabt::AssertModuleCommand<(wabt::CommandType)5> >(wabt::TokenType, std::__1::unique_ptr<wabt::Command, std::__1::default_delete<wabt::Command> >*) Unexecuted instantiation: wabt::Result wabt::WastParser::ParseAssertScriptModuleCommand<wabt::AssertModuleCommand<(wabt::CommandType)4> >(wabt::TokenType, std::__1::unique_ptr<wabt::Command, std::__1::default_delete<wabt::Command> >*) Unexecuted instantiation: wabt::Result wabt::WastParser::ParseAssertScriptModuleCommand<wabt::AssertModuleCommand<(wabt::CommandType)6> >(wabt::TokenType, std::__1::unique_ptr<wabt::Command, std::__1::default_delete<wabt::Command> >*) |
3664 | | |
3665 | 175k | void WastParser::CheckImportOrdering(Module* module) { |
3666 | 175k | if (module->funcs.size() != module->num_func_imports || |
3667 | 175k | module->tables.size() != module->num_table_imports || |
3668 | 175k | module->memories.size() != module->num_memory_imports || |
3669 | 175k | module->globals.size() != module->num_global_imports || |
3670 | 175k | module->tags.size() != module->num_tag_imports) { |
3671 | 77.1k | Error(GetLocation(), |
3672 | 77.1k | "imports must occur before all non-import definitions"); |
3673 | 77.1k | } |
3674 | 175k | } |
3675 | | |
3676 | 3.38k | bool WastParser::HasError() const { |
3677 | 3.38k | return std::any_of(errors_->begin(), errors_->end(), [](const auto& x) { |
3678 | 2.39k | return x.error_level == ErrorLevel::Error; |
3679 | 2.39k | }); |
3680 | 3.38k | } |
3681 | | |
3682 | 24.8M | void WastParser::TokenQueue::push_back(Token t) { |
3683 | 24.8M | assert(!tokens[!i]); |
3684 | 24.8M | tokens[!i] = t; |
3685 | 24.8M | if (empty()) { |
3686 | 10.8M | i = !i; |
3687 | 10.8M | } |
3688 | 24.8M | } |
3689 | | |
3690 | 24.8M | void WastParser::TokenQueue::pop_front() { |
3691 | 24.8M | assert(tokens[i]); |
3692 | 24.8M | tokens[i].reset(); |
3693 | 24.8M | i = !i; |
3694 | 24.8M | } |
3695 | | |
3696 | 121M | const Token& WastParser::TokenQueue::at(size_t n) const { |
3697 | 121M | assert(n <= 1); |
3698 | 121M | return tokens[i ^ static_cast<bool>(n)].value(); |
3699 | 121M | } |
3700 | | |
3701 | 33.7M | const Token& WastParser::TokenQueue::front() const { |
3702 | 33.7M | return at(0); |
3703 | 33.7M | } |
3704 | | |
3705 | 171M | bool WastParser::TokenQueue::empty() const { |
3706 | 171M | return !tokens[i]; |
3707 | 171M | } |
3708 | | |
3709 | 112M | size_t WastParser::TokenQueue::size() const { |
3710 | 112M | return empty() ? 0 : 1 + tokens[!i].has_value(); |
3711 | 112M | } |
3712 | | |
3713 | | Result ParseWatModule(WastLexer* lexer, |
3714 | | std::unique_ptr<Module>* out_module, |
3715 | | Errors* errors, |
3716 | 22.7k | WastParseOptions* options) { |
3717 | 22.7k | assert(out_module != nullptr); |
3718 | 22.7k | assert(options != nullptr); |
3719 | 22.7k | WastParser parser(lexer, errors, options); |
3720 | 22.7k | CHECK_RESULT(parser.ParseModule(out_module)); |
3721 | 1.66k | return Result::Ok; |
3722 | 22.7k | } |
3723 | | |
3724 | | Result ParseWastScript(WastLexer* lexer, |
3725 | | std::unique_ptr<Script>* out_script, |
3726 | | Errors* errors, |
3727 | 0 | WastParseOptions* options) { |
3728 | 0 | assert(out_script != nullptr); |
3729 | 0 | assert(options != nullptr); |
3730 | 0 | WastParser parser(lexer, errors, options); |
3731 | 0 | CHECK_RESULT(parser.ParseScript(out_script)); |
3732 | 0 | CHECK_RESULT(ResolveNamesScript(out_script->get(), errors)); |
3733 | 0 | return Result::Ok; |
3734 | 0 | } |
3735 | | |
3736 | | } // namespace wabt |