1 /*
2  * Copyright 2015 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 #ifndef wasm_parsing_h
18 #define wasm_parsing_h
19 
20 #include <cmath>
21 #include <ostream>
22 #include <sstream>
23 #include <string>
24 
25 #include "asmjs/shared-constants.h"
26 #include "mixed_arena.h"
27 #include "shared-constants.h"
28 #include "support/colors.h"
29 #include "support/utilities.h"
30 #include "wasm-printing.h"
31 #include "wasm.h"
32 
33 namespace wasm {
34 
35 struct ParseException {
36   std::string text;
37   size_t line, col;
38 
ParseExceptionParseException39   ParseException() : text("unknown parse error"), line(-1), col(-1) {}
ParseExceptionParseException40   ParseException(std::string text) : text(text), line(-1), col(-1) {}
ParseExceptionParseException41   ParseException(std::string text, size_t line, size_t col)
42     : text(text), line(line), col(col) {}
43 
dumpParseException44   void dump(std::ostream& o) const {
45     Colors::magenta(o);
46     o << "[";
47     Colors::red(o);
48     o << "parse exception: ";
49     Colors::green(o);
50     o << text;
51     if (line != size_t(-1)) {
52       Colors::normal(o);
53       o << " (at " << line << ":" << col << ")";
54     }
55     Colors::magenta(o);
56     o << "]";
57     Colors::normal(o);
58   }
59 };
60 
61 struct MapParseException {
62   std::string text;
63 
MapParseExceptionMapParseException64   MapParseException() : text("unknown parse error") {}
MapParseExceptionMapParseException65   MapParseException(std::string text) : text(text) {}
66 
dumpMapParseException67   void dump(std::ostream& o) const {
68     Colors::magenta(o);
69     o << "[";
70     Colors::red(o);
71     o << "map parse exception: ";
72     Colors::green(o);
73     o << text;
74     Colors::magenta(o);
75     o << "]";
76     Colors::normal(o);
77   }
78 };
79 
80 inline Expression*
parseConst(cashew::IString s,Type type,MixedArena & allocator)81 parseConst(cashew::IString s, Type type, MixedArena& allocator) {
82   const char* str = s.str;
83   auto ret = allocator.alloc<Const>();
84   ret->type = type;
85   if (type.isFloat()) {
86     if (s == _INFINITY) {
87       switch (type.getBasic()) {
88         case Type::f32:
89           ret->value = Literal(std::numeric_limits<float>::infinity());
90           break;
91         case Type::f64:
92           ret->value = Literal(std::numeric_limits<double>::infinity());
93           break;
94         default:
95           return nullptr;
96       }
97       // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
98       return ret;
99     }
100     if (s == NEG_INFINITY) {
101       switch (type.getBasic()) {
102         case Type::f32:
103           ret->value = Literal(-std::numeric_limits<float>::infinity());
104           break;
105         case Type::f64:
106           ret->value = Literal(-std::numeric_limits<double>::infinity());
107           break;
108         default:
109           return nullptr;
110       }
111       // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
112       return ret;
113     }
114     if (s == _NAN) {
115       switch (type.getBasic()) {
116         case Type::f32:
117           ret->value = Literal(float(std::nan("")));
118           break;
119         case Type::f64:
120           ret->value = Literal(double(std::nan("")));
121           break;
122         default:
123           return nullptr;
124       }
125       // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
126       return ret;
127     }
128     bool negative = str[0] == '-';
129     const char* positive = negative ? str + 1 : str;
130     if (!negative) {
131       if (positive[0] == '+') {
132         positive++;
133       }
134     }
135     if (positive[0] == 'n' && positive[1] == 'a' && positive[2] == 'n') {
136       const char* modifier = positive[3] == ':' ? positive + 4 : nullptr;
137       if (!(modifier ? positive[4] == '0' && positive[5] == 'x' : 1)) {
138         throw ParseException("bad nan input");
139       }
140       switch (type.getBasic()) {
141         case Type::f32: {
142           uint32_t pattern;
143           if (modifier) {
144             std::istringstream istr(modifier);
145             istr >> std::hex >> pattern;
146             if (istr.fail()) {
147               throw ParseException("invalid f32 format");
148             }
149             pattern |= 0x7f800000U;
150           } else {
151             pattern = 0x7fc00000U;
152           }
153           if (negative) {
154             pattern |= 0x80000000U;
155           }
156           if (!std::isnan(bit_cast<float>(pattern))) {
157             pattern |= 1U;
158           }
159           ret->value = Literal(pattern).castToF32();
160           break;
161         }
162         case Type::f64: {
163           uint64_t pattern;
164           if (modifier) {
165             std::istringstream istr(modifier);
166             istr >> std::hex >> pattern;
167             if (istr.fail()) {
168               throw ParseException("invalid f64 format");
169             }
170             pattern |= 0x7ff0000000000000ULL;
171           } else {
172             pattern = 0x7ff8000000000000UL;
173           }
174           if (negative) {
175             pattern |= 0x8000000000000000ULL;
176           }
177           if (!std::isnan(bit_cast<double>(pattern))) {
178             pattern |= 1ULL;
179           }
180           ret->value = Literal(pattern).castToF64();
181           break;
182         }
183         default:
184           return nullptr;
185       }
186       // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
187       return ret;
188     }
189     if (s == NEG_NAN) {
190       switch (type.getBasic()) {
191         case Type::f32:
192           ret->value = Literal(float(-std::nan("")));
193           break;
194         case Type::f64:
195           ret->value = Literal(double(-std::nan("")));
196           break;
197         default:
198           return nullptr;
199       }
200       // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
201       return ret;
202     }
203   }
204   switch (type.getBasic()) {
205     case Type::i32: {
206       if ((str[0] == '0' && str[1] == 'x') ||
207           (str[0] == '-' && str[1] == '0' && str[2] == 'x')) {
208         bool negative = str[0] == '-';
209         if (negative) {
210           str++;
211         }
212         std::istringstream istr(str);
213         uint32_t temp;
214         istr >> std::hex >> temp;
215         if (istr.fail()) {
216           throw ParseException("invalid i32 format");
217         }
218         ret->value = Literal(negative ? -temp : temp);
219       } else {
220         std::istringstream istr(str[0] == '-' ? str + 1 : str);
221         uint32_t temp;
222         istr >> temp;
223         if (istr.fail()) {
224           throw ParseException("invalid i32 format");
225         }
226         ret->value = Literal(str[0] == '-' ? -temp : temp);
227       }
228       break;
229     }
230     case Type::i64: {
231       if ((str[0] == '0' && str[1] == 'x') ||
232           (str[0] == '-' && str[1] == '0' && str[2] == 'x')) {
233         bool negative = str[0] == '-';
234         if (negative) {
235           str++;
236         }
237         std::istringstream istr(str);
238         uint64_t temp;
239         istr >> std::hex >> temp;
240         if (istr.fail()) {
241           throw ParseException("invalid i64 format");
242         }
243         ret->value = Literal(negative ? -temp : temp);
244       } else {
245         std::istringstream istr(str[0] == '-' ? str + 1 : str);
246         uint64_t temp;
247         istr >> temp;
248         if (istr.fail()) {
249           throw ParseException("invalid i64 format");
250         }
251         ret->value = Literal(str[0] == '-' ? -temp : temp);
252       }
253       break;
254     }
255     case Type::f32: {
256       char* end;
257       ret->value = Literal(strtof(str, &end));
258       break;
259     }
260     case Type::f64: {
261       char* end;
262       ret->value = Literal(strtod(str, &end));
263       break;
264     }
265     case Type::v128:
266     case Type::funcref:
267     case Type::externref:
268     case Type::exnref:
269     case Type::anyref:
270     case Type::eqref:
271     case Type::i31ref:
272       WASM_UNREACHABLE("unexpected const type");
273     case Type::none:
274     case Type::unreachable: {
275       return nullptr;
276     }
277   }
278   if (ret->value.type != type) {
279     throw ParseException("parsed type does not match expected type");
280   }
281   // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
282   return ret;
283 }
284 
285 // Helper for parsers that may not have unique label names. This transforms
286 // the names into unique ones, as required by Binaryen IR.
287 struct UniqueNameMapper {
288   std::vector<Name> labelStack;
289   // name in source => stack of uniquified names
290   std::map<Name, std::vector<Name>> labelMappings;
291   std::map<Name, Name> reverseLabelMapping; // uniquified name => name in source
292 
293   Index otherIndex = 0;
294 
getPrefixedNameUniqueNameMapper295   Name getPrefixedName(Name prefix) {
296     if (reverseLabelMapping.find(prefix) == reverseLabelMapping.end()) {
297       return prefix;
298     }
299     // make sure to return a unique name not already on the stack
300     while (1) {
301       Name ret = Name(prefix.str + std::to_string(otherIndex++));
302       if (reverseLabelMapping.find(ret) == reverseLabelMapping.end()) {
303         return ret;
304       }
305     }
306   }
307 
308   // receives a source name. generates a unique name, pushes it, and returns it
pushLabelNameUniqueNameMapper309   Name pushLabelName(Name sName) {
310     Name name = getPrefixedName(sName);
311     labelStack.push_back(name);
312     labelMappings[sName].push_back(name);
313     reverseLabelMapping[name] = sName;
314     return name;
315   }
316 
popLabelNameUniqueNameMapper317   void popLabelName(Name name) {
318     assert(labelStack.back() == name);
319     labelStack.pop_back();
320     labelMappings[reverseLabelMapping[name]].pop_back();
321   }
322 
sourceToUniqueUniqueNameMapper323   Name sourceToUnique(Name sName) {
324     if (labelMappings.find(sName) == labelMappings.end()) {
325       throw ParseException("bad label in sourceToUnique");
326     }
327     if (labelMappings[sName].empty()) {
328       throw ParseException("use of popped label in sourceToUnique");
329     }
330     return labelMappings[sName].back();
331   }
332 
uniqueToSourceUniqueNameMapper333   Name uniqueToSource(Name name) {
334     if (reverseLabelMapping.find(name) == reverseLabelMapping.end()) {
335       throw ParseException("label mismatch in uniqueToSource");
336     }
337     return reverseLabelMapping[name];
338   }
339 
clearUniqueNameMapper340   void clear() {
341     labelStack.clear();
342     labelMappings.clear();
343     reverseLabelMapping.clear();
344   }
345 
346   // Given an expression, ensures all names are unique
uniquifyUniqueNameMapper347   static void uniquify(Expression* curr) {
348     struct Walker : public ControlFlowWalker<Walker, Visitor<Walker>> {
349       UniqueNameMapper mapper;
350 
351       static void doPreVisitControlFlow(Walker* self, Expression** currp) {
352         auto* curr = *currp;
353         if (auto* block = curr->dynCast<Block>()) {
354           if (block->name.is()) {
355             block->name = self->mapper.pushLabelName(block->name);
356           }
357         } else if (auto* loop = curr->dynCast<Loop>()) {
358           if (loop->name.is()) {
359             loop->name = self->mapper.pushLabelName(loop->name);
360           }
361         }
362       }
363       static void doPostVisitControlFlow(Walker* self, Expression** currp) {
364         auto* curr = *currp;
365         if (auto* block = curr->dynCast<Block>()) {
366           if (block->name.is()) {
367             self->mapper.popLabelName(block->name);
368           }
369         } else if (auto* loop = curr->dynCast<Loop>()) {
370           if (loop->name.is()) {
371             self->mapper.popLabelName(loop->name);
372           }
373         }
374       }
375 
376       void visitBreak(Break* curr) {
377         curr->name = mapper.sourceToUnique(curr->name);
378       }
379       void visitBrOnExn(BrOnExn* curr) {
380         curr->name = mapper.sourceToUnique(curr->name);
381       }
382       void visitSwitch(Switch* curr) {
383         for (auto& target : curr->targets) {
384           target = mapper.sourceToUnique(target);
385         }
386         curr->default_ = mapper.sourceToUnique(curr->default_);
387       }
388     };
389 
390     Walker walker;
391     walker.walk(curr);
392   }
393 };
394 
395 } // namespace wasm
396 
397 #endif // wasm_parsing_h
398