/src/solidity/liblangutil/Token.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2006-2012, the V8 project authors. All rights reserved. |
2 | | // Redistribution and use in source and binary forms, with or without |
3 | | // modification, are permitted provided that the following conditions are |
4 | | // met: |
5 | | // |
6 | | // * Redistributions of source code must retain the above copyright |
7 | | // notice, this list of conditions and the following disclaimer. |
8 | | // * Redistributions in binary form must reproduce the above |
9 | | // copyright notice, this list of conditions and the following |
10 | | // disclaimer in the documentation and/or other materials provided |
11 | | // with the distribution. |
12 | | // * Neither the name of Google Inc. nor the names of its |
13 | | // contributors may be used to endorse or promote products derived |
14 | | // from this software without specific prior written permission. |
15 | | // |
16 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
20 | | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21 | | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 | | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 | | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | | // |
28 | | // Modifications as part of solidity under the following license: |
29 | | // |
30 | | // solidity is free software: you can redistribute it and/or modify |
31 | | // it under the terms of the GNU General Public License as published by |
32 | | // the Free Software Foundation, either version 3 of the License, or |
33 | | // (at your option) any later version. |
34 | | // |
35 | | // solidity is distributed in the hope that it will be useful, |
36 | | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
37 | | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
38 | | // GNU General Public License for more details. |
39 | | // |
40 | | // You should have received a copy of the GNU General Public License |
41 | | // along with solidity. If not, see <http://www.gnu.org/licenses/>. |
42 | | |
43 | | #pragma once |
44 | | |
45 | | #include <liblangutil/UndefMacros.h> |
46 | | |
47 | | #include <iosfwd> |
48 | | #include <string> |
49 | | #include <tuple> |
50 | | |
51 | | namespace solidity::langutil |
52 | | { |
53 | | |
54 | | // TOKEN_LIST takes a list of 3 macros M, all of which satisfy the |
55 | | // same signature M(name, string, precedence), where name is the |
56 | | // symbolic token name, string is the corresponding syntactic symbol |
57 | | // (or nullptr, for literals), and precedence is the precedence (or 0). |
58 | | // The parameters are invoked for token categories as follows: |
59 | | // |
60 | | // T: Non-keyword tokens |
61 | | // K: Keyword tokens |
62 | | |
63 | | // IGNORE_TOKEN is a convenience macro that can be supplied as |
64 | | // an argument (at any position) for a TOKEN_LIST call. It does |
65 | | // nothing with tokens belonging to the respective category. |
66 | | |
67 | | #define IGNORE_TOKEN(name, string, precedence) |
68 | | |
69 | | #define TOKEN_LIST(T, K) \ |
70 | | /* End of source indicator. */ \ |
71 | 0 | T(EOS, "EOS", 0) \ |
72 | 0 | \ |
73 | 0 | /* Punctuators (ECMA-262, section 7.7, page 15). */ \ |
74 | 0 | T(LParen, "(", 0) \ |
75 | 0 | T(RParen, ")", 0) \ |
76 | 0 | T(LBrack, "[", 0) \ |
77 | 0 | T(RBrack, "]", 0) \ |
78 | 0 | T(LBrace, "{", 0) \ |
79 | 0 | T(RBrace, "}", 0) \ |
80 | 0 | T(Colon, ":", 0) \ |
81 | 0 | T(Semicolon, ";", 0) \ |
82 | 0 | T(Period, ".", 0) \ |
83 | 0 | T(Conditional, "?", 3) \ |
84 | 0 | T(DoubleArrow, "=>", 0) \ |
85 | 0 | T(RightArrow, "->", 0) \ |
86 | 0 | \ |
87 | 0 | /* Assignment operators. */ \ |
88 | 0 | /* IsAssignmentOp() relies on this block of enum values being */ \ |
89 | 0 | /* contiguous and sorted in the same order!*/ \ |
90 | 0 | T(Assign, "=", 2) \ |
91 | 0 | /* The following have to be in exactly the same order as the simple binary operators*/ \ |
92 | 0 | T(AssignBitOr, "|=", 2) \ |
93 | 0 | T(AssignBitXor, "^=", 2) \ |
94 | 0 | T(AssignBitAnd, "&=", 2) \ |
95 | 0 | T(AssignShl, "<<=", 2) \ |
96 | 0 | T(AssignSar, ">>=", 2) \ |
97 | 0 | T(AssignShr, ">>>=", 2) \ |
98 | 0 | T(AssignAdd, "+=", 2) \ |
99 | 0 | T(AssignSub, "-=", 2) \ |
100 | 0 | T(AssignMul, "*=", 2) \ |
101 | 0 | T(AssignDiv, "/=", 2) \ |
102 | 0 | T(AssignMod, "%=", 2) \ |
103 | 0 | \ |
104 | 0 | /* Binary operators sorted by precedence. */ \ |
105 | 0 | /* IsBinaryOp() relies on this block of enum values */ \ |
106 | 0 | /* being contiguous and sorted in the same order! */ \ |
107 | 0 | T(Comma, ",", 1) \ |
108 | 0 | T(Or, "||", 4) \ |
109 | 0 | T(And, "&&", 5) \ |
110 | 0 | T(BitOr, "|", 8) \ |
111 | 0 | T(BitXor, "^", 9) \ |
112 | 0 | T(BitAnd, "&", 10) \ |
113 | 0 | T(SHL, "<<", 11) \ |
114 | 0 | T(SAR, ">>", 11) \ |
115 | 0 | T(SHR, ">>>", 11) \ |
116 | 0 | T(Add, "+", 12) \ |
117 | 0 | T(Sub, "-", 12) \ |
118 | 0 | T(Mul, "*", 13) \ |
119 | 0 | T(Div, "/", 13) \ |
120 | 0 | T(Mod, "%", 13) \ |
121 | 0 | T(Exp, "**", 14) \ |
122 | 0 | \ |
123 | 0 | /* Compare operators sorted by precedence. */ \ |
124 | 0 | /* IsCompareOp() relies on this block of enum values */ \ |
125 | 0 | /* being contiguous and sorted in the same order! */ \ |
126 | 0 | T(Equal, "==", 6) \ |
127 | 0 | T(NotEqual, "!=", 6) \ |
128 | 0 | T(LessThan, "<", 7) \ |
129 | 0 | T(GreaterThan, ">", 7) \ |
130 | 0 | T(LessThanOrEqual, "<=", 7) \ |
131 | 0 | T(GreaterThanOrEqual, ">=", 7) \ |
132 | 0 | \ |
133 | 0 | /* Unary operators. */ \ |
134 | 0 | /* IsUnaryOp() relies on this block of enum values */ \ |
135 | 0 | /* being contiguous and sorted in the same order! */ \ |
136 | 0 | T(Not, "!", 0) \ |
137 | 0 | T(BitNot, "~", 0) \ |
138 | 0 | T(Inc, "++", 0) \ |
139 | 0 | T(Dec, "--", 0) \ |
140 | 0 | K(Delete, "delete", 0) \ |
141 | 0 | \ |
142 | 0 | /* Inline Assembly Operators */ \ |
143 | 0 | T(AssemblyAssign, ":=", 2) \ |
144 | 0 | /* Keywords */ \ |
145 | 0 | K(Abstract, "abstract", 0) \ |
146 | 0 | K(Anonymous, "anonymous", 0) \ |
147 | 0 | K(As, "as", 0) \ |
148 | 0 | K(Assembly, "assembly", 0) \ |
149 | 0 | K(Break, "break", 0) \ |
150 | 0 | K(Catch, "catch", 0) \ |
151 | 0 | K(Constant, "constant", 0) \ |
152 | 0 | K(Constructor, "constructor", 0) \ |
153 | 0 | K(Continue, "continue", 0) \ |
154 | 0 | K(Contract, "contract", 0) \ |
155 | 0 | K(Do, "do", 0) \ |
156 | 0 | K(Else, "else", 0) \ |
157 | 0 | K(Enum, "enum", 0) \ |
158 | 0 | K(Emit, "emit", 0) \ |
159 | 0 | K(Event, "event", 0) \ |
160 | 0 | K(External, "external", 0) \ |
161 | 0 | K(Fallback, "fallback", 0) \ |
162 | 0 | K(For, "for", 0) \ |
163 | 0 | K(Function, "function", 0) \ |
164 | 0 | K(Hex, "hex", 0) \ |
165 | 0 | K(If, "if", 0) \ |
166 | 0 | K(Indexed, "indexed", 0) \ |
167 | 0 | K(Interface, "interface", 0) \ |
168 | 0 | K(Internal, "internal", 0) \ |
169 | 0 | K(Immutable, "immutable", 0) \ |
170 | 0 | K(Import, "import", 0) \ |
171 | 0 | K(Is, "is", 0) \ |
172 | 0 | K(Library, "library", 0) \ |
173 | 0 | K(Mapping, "mapping", 0) \ |
174 | 0 | K(Memory, "memory", 0) \ |
175 | 0 | K(Modifier, "modifier", 0) \ |
176 | 0 | K(New, "new", 0) \ |
177 | 0 | K(Override, "override", 0) \ |
178 | 0 | K(Payable, "payable", 0) \ |
179 | 0 | K(Public, "public", 0) \ |
180 | 0 | K(Pragma, "pragma", 0) \ |
181 | 0 | K(Private, "private", 0) \ |
182 | 0 | K(Pure, "pure", 0) \ |
183 | 0 | K(Receive, "receive", 0) \ |
184 | 0 | K(Return, "return", 0) \ |
185 | 0 | K(Returns, "returns", 0) \ |
186 | 0 | K(Storage, "storage", 0) \ |
187 | 0 | K(CallData, "calldata", 0) \ |
188 | 0 | K(Struct, "struct", 0) \ |
189 | 0 | K(Throw, "throw", 0) \ |
190 | 0 | K(Try, "try", 0) \ |
191 | 0 | K(Type, "type", 0) \ |
192 | 0 | K(Unchecked, "unchecked", 0) \ |
193 | 0 | K(Unicode, "unicode", 0) \ |
194 | 0 | K(Using, "using", 0) \ |
195 | 0 | K(View, "view", 0) \ |
196 | 0 | K(Virtual, "virtual", 0) \ |
197 | 0 | K(While, "while", 0) \ |
198 | 0 | \ |
199 | 0 | /* Ether subdenominations */ \ |
200 | 0 | K(SubWei, "wei", 0) \ |
201 | 0 | K(SubGwei, "gwei", 0) \ |
202 | 0 | K(SubEther, "ether", 0) \ |
203 | 0 | K(SubSecond, "seconds", 0) \ |
204 | 0 | K(SubMinute, "minutes", 0) \ |
205 | 0 | K(SubHour, "hours", 0) \ |
206 | 0 | K(SubDay, "days", 0) \ |
207 | 0 | K(SubWeek, "weeks", 0) \ |
208 | 0 | K(SubYear, "years", 0) \ |
209 | 0 | /* type keywords*/ \ |
210 | 0 | K(Int, "int", 0) \ |
211 | 0 | K(UInt, "uint", 0) \ |
212 | 0 | K(Bytes, "bytes", 0) \ |
213 | 0 | K(String, "string", 0) \ |
214 | 0 | K(Address, "address", 0) \ |
215 | 0 | K(Bool, "bool", 0) \ |
216 | 0 | K(Fixed, "fixed", 0) \ |
217 | 0 | K(UFixed, "ufixed", 0) \ |
218 | 0 | T(IntM, "intM", 0) \ |
219 | 0 | T(UIntM, "uintM", 0) \ |
220 | 0 | T(BytesM, "bytesM", 0) \ |
221 | 0 | T(FixedMxN, "fixedMxN", 0) \ |
222 | 0 | T(UFixedMxN, "ufixedMxN", 0) \ |
223 | 0 | T(TypesEnd, nullptr, 0) /* used as type enum end marker */ \ |
224 | 0 | \ |
225 | 0 | /* Literals */ \ |
226 | 0 | K(TrueLiteral, "true", 0) \ |
227 | 0 | K(FalseLiteral, "false", 0) \ |
228 | 0 | T(Number, nullptr, 0) \ |
229 | 0 | T(StringLiteral, nullptr, 0) \ |
230 | 0 | T(UnicodeStringLiteral, nullptr, 0) \ |
231 | 0 | T(HexStringLiteral, nullptr, 0) \ |
232 | 0 | T(CommentLiteral, nullptr, 0) \ |
233 | 0 | \ |
234 | 0 | /* Identifiers (not keywords or future reserved words). */ \ |
235 | 0 | T(Identifier, nullptr, 0) \ |
236 | 0 | \ |
237 | 0 | /* Keywords reserved for future use. */ \ |
238 | 0 | K(After, "after", 0) \ |
239 | 0 | K(Alias, "alias", 0) \ |
240 | 0 | K(Apply, "apply", 0) \ |
241 | 0 | K(Auto, "auto", 0) \ |
242 | 0 | K(Byte, "byte", 0) \ |
243 | 0 | K(Case, "case", 0) \ |
244 | 0 | K(CopyOf, "copyof", 0) \ |
245 | 0 | K(Default, "default", 0) \ |
246 | 0 | K(Define, "define", 0) \ |
247 | 0 | K(Final, "final", 0) \ |
248 | 0 | K(Implements, "implements", 0) \ |
249 | 0 | K(In, "in", 0) \ |
250 | 0 | K(Inline, "inline", 0) \ |
251 | 0 | K(Let, "let", 0) \ |
252 | 0 | K(Macro, "macro", 0) \ |
253 | 0 | K(Match, "match", 0) \ |
254 | 0 | K(Mutable, "mutable", 0) \ |
255 | 0 | K(NullLiteral, "null", 0) \ |
256 | 0 | K(Of, "of", 0) \ |
257 | 0 | K(Partial, "partial", 0) \ |
258 | 0 | K(Promise, "promise", 0) \ |
259 | 0 | K(Reference, "reference", 0) \ |
260 | 0 | K(Relocatable, "relocatable", 0) \ |
261 | 0 | K(Sealed, "sealed", 0) \ |
262 | 0 | K(Sizeof, "sizeof", 0) \ |
263 | 0 | K(Static, "static", 0) \ |
264 | 0 | K(Supports, "supports", 0) \ |
265 | 0 | K(Switch, "switch", 0) \ |
266 | 0 | K(Typedef, "typedef", 0) \ |
267 | 0 | K(TypeOf, "typeof", 0) \ |
268 | 0 | K(Var, "var", 0) \ |
269 | 0 | \ |
270 | 0 | /* Yul-specific tokens, but not keywords. */ \ |
271 | 0 | T(Leave, "leave", 0) \ |
272 | 0 | \ |
273 | 0 | /* Illegal token - not able to scan. */ \ |
274 | 0 | T(Illegal, "ILLEGAL", 0) \ |
275 | 0 | \ |
276 | 0 | /* Scanner-internal use only. */ \ |
277 | 0 | T(Whitespace, nullptr, 0) |
278 | | |
279 | | // All token values. |
280 | | // attention! msvc issue: |
281 | | // http://stackoverflow.com/questions/9567868/compile-errors-after-adding-v8-to-my-project-c2143-c2059 |
282 | | // @todo: avoid TOKEN_LIST macro |
283 | | enum class Token : unsigned int { |
284 | | #define T(name, string, precedence) name, |
285 | | TOKEN_LIST(T, T) |
286 | | NUM_TOKENS |
287 | | #undef T |
288 | | }; |
289 | | |
290 | | namespace TokenTraits |
291 | | { |
292 | 0 | constexpr size_t count() { return static_cast<size_t>(Token::NUM_TOKENS); } |
293 | | |
294 | | // Predicates |
295 | 0 | constexpr bool isElementaryTypeName(Token tok) { return Token::Int <= tok && tok < Token::TypesEnd; } |
296 | 0 | constexpr bool isAssignmentOp(Token tok) { return Token::Assign <= tok && tok <= Token::AssignMod; } |
297 | 0 | constexpr bool isBinaryOp(Token op) { return Token::Comma <= op && op <= Token::Exp; } |
298 | 0 | constexpr bool isCommutativeOp(Token op) { return op == Token::BitOr || op == Token::BitXor || op == Token::BitAnd || |
299 | 0 | op == Token::Add || op == Token::Mul || op == Token::Equal || op == Token::NotEqual; } |
300 | 0 | constexpr bool isArithmeticOp(Token op) { return Token::Add <= op && op <= Token::Exp; } |
301 | 0 | constexpr bool isCompareOp(Token op) { return Token::Equal <= op && op <= Token::GreaterThanOrEqual; } |
302 | | |
303 | 0 | constexpr bool isBitOp(Token op) { return (Token::BitOr <= op && op <= Token::BitAnd) || op == Token::BitNot; } |
304 | 0 | constexpr bool isBooleanOp(Token op) { return (Token::Or <= op && op <= Token::And) || op == Token::Not; } |
305 | 0 | constexpr bool isUnaryOp(Token op) { return (Token::Not <= op && op <= Token::Delete) || op == Token::Add || op == Token::Sub; } |
306 | 0 | constexpr bool isCountOp(Token op) { return op == Token::Inc || op == Token::Dec; } |
307 | 0 | constexpr bool isShiftOp(Token op) { return (Token::SHL <= op) && (op <= Token::SHR); } |
308 | 0 | constexpr bool isVariableVisibilitySpecifier(Token op) { return op == Token::Public || op == Token::Private || op == Token::Internal; } |
309 | 0 | constexpr bool isVisibilitySpecifier(Token op) { return isVariableVisibilitySpecifier(op) || op == Token::External; } |
310 | 0 | constexpr bool isLocationSpecifier(Token op) { return op == Token::Memory || op == Token::Storage || op == Token::CallData; } |
311 | | |
312 | | constexpr bool isStateMutabilitySpecifier(Token op) |
313 | 0 | { |
314 | 0 | return op == Token::Pure || op == Token::View || op == Token::Payable; |
315 | 0 | } |
316 | | |
317 | 0 | constexpr bool isEtherSubdenomination(Token op) { return op >= Token::SubWei && op <= Token::SubEther; } |
318 | 0 | constexpr bool isTimeSubdenomination(Token op) { return op == Token::SubSecond || op == Token::SubMinute || op == Token::SubHour || op == Token::SubDay || op == Token::SubWeek || op == Token::SubYear; } |
319 | 0 | constexpr bool isReservedKeyword(Token op) { return (Token::After <= op && op <= Token::Var); } |
320 | | |
321 | | constexpr bool isYulKeyword(Token tok) |
322 | 0 | { |
323 | 0 | return tok == Token::Function || tok == Token::Let || tok == Token::If || tok == Token::Switch || tok == Token::Case || |
324 | 0 | tok == Token::Default || tok == Token::For || tok == Token::Break || tok == Token::Continue || tok == Token::Leave || |
325 | 0 | tok == Token::TrueLiteral || tok == Token::FalseLiteral || tok == Token::HexStringLiteral || tok == Token::Hex; |
326 | 0 | } |
327 | | |
328 | | bool isYulKeyword(std::string const& _literal); |
329 | | |
330 | | Token AssignmentToBinaryOp(Token op); |
331 | | |
332 | | // @returns the precedence > 0 for binary and compare |
333 | | // operators; returns 0 otherwise. |
334 | | constexpr int precedence(Token tok) |
335 | 0 | { |
336 | 0 | int8_t constexpr precs[TokenTraits::count()] = |
337 | 0 | { |
338 | 0 | #define T(name, string, precedence) precedence, |
339 | 0 | TOKEN_LIST(T, T) |
340 | 0 | #undef T |
341 | 0 | }; |
342 | 0 | return precs[static_cast<size_t>(tok)]; |
343 | 0 | } |
344 | | |
345 | | constexpr bool hasExpHighestPrecedence() |
346 | 0 | { |
347 | 0 | constexpr int expPrecedence = TokenTraits::precedence(Token::Exp); |
348 | 0 | static_assert(expPrecedence == 14, "Exp precedence changed."); |
349 | 0 |
|
350 | 0 | #define T(name, string, precedence) ((Token::name == Token::Exp) || precedence < expPrecedence) && |
351 | 0 | return |
352 | 0 | TOKEN_LIST(T, T) |
353 | 0 | true; |
354 | 0 | #undef T |
355 | 0 | } |
356 | | |
357 | | std::tuple<Token, unsigned int, unsigned int> fromIdentifierOrKeyword(std::string const& _literal); |
358 | | |
359 | | // @returns a string corresponding to the C++ token name |
360 | | // (e.g. "LT" for the token LT). |
361 | | char const* name(Token tok); |
362 | | |
363 | | // @returns a string corresponding to the JS token string |
364 | | // (.e., "<" for the token LT) or nullptr if the token doesn't |
365 | | // have a (unique) string (e.g. an IDENTIFIER). |
366 | | char const* toString(Token tok); |
367 | | |
368 | | std::string friendlyName(Token tok); |
369 | | } |
370 | | |
371 | | inline std::ostream& operator<<(std::ostream& os, Token token) |
372 | 0 | { |
373 | 0 | os << TokenTraits::friendlyName(token); |
374 | 0 | return os; |
375 | 0 | } |
376 | | |
377 | | class ElementaryTypeNameToken |
378 | | { |
379 | | public: |
380 | | ElementaryTypeNameToken(Token _token, unsigned const& _firstNumber, unsigned const& _secondNumber) |
381 | 0 | { |
382 | 0 | assertDetails(_token, _firstNumber, _secondNumber); |
383 | 0 | } |
384 | | |
385 | 0 | unsigned int firstNumber() const { return m_firstNumber; } |
386 | 0 | unsigned int secondNumber() const { return m_secondNumber; } |
387 | 0 | Token token() const { return m_token; } |
388 | | |
389 | | ///if tokValue is set to true, then returns the actual token type name, otherwise, returns full type |
390 | | std::string toString(bool const& tokenValue = false) const; |
391 | | |
392 | | private: |
393 | | Token m_token; |
394 | | unsigned int m_firstNumber; |
395 | | unsigned int m_secondNumber; |
396 | | /// throws if type is not properly sized |
397 | | void assertDetails(Token _baseType, unsigned const& _first, unsigned const& _second); |
398 | | }; |
399 | | |
400 | | } |