/src/solidity/libyul/Utilities.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | This file is part of solidity. |
3 | | |
4 | | solidity is free software: you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation, either version 3 of the License, or |
7 | | (at your option) any later version. |
8 | | |
9 | | solidity is distributed in the hope that it will be useful, |
10 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | GNU General Public License for more details. |
13 | | |
14 | | You should have received a copy of the GNU General Public License |
15 | | along with solidity. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | // SPDX-License-Identifier: GPL-3.0 |
18 | | /** |
19 | | * Some useful snippets for the optimiser. |
20 | | */ |
21 | | |
22 | | #include <libyul/Utilities.h> |
23 | | |
24 | | #include <libyul/AST.h> |
25 | | #include <libyul/Exceptions.h> |
26 | | |
27 | | #include <libsolutil/CommonData.h> |
28 | | #include <libsolutil/FixedHash.h> |
29 | | |
30 | | #include <boost/algorithm/string.hpp> |
31 | | |
32 | | #include <algorithm> |
33 | | #include <sstream> |
34 | | #include <vector> |
35 | | |
36 | | using namespace std; |
37 | | using namespace solidity; |
38 | | using namespace solidity::yul; |
39 | | using namespace solidity::util; |
40 | | |
41 | | string solidity::yul::reindent(string const& _code) |
42 | 0 | { |
43 | 0 | int constexpr indentationWidth = 4; |
44 | |
|
45 | 0 | auto constexpr static countBraces = [](string const& _s) noexcept -> int |
46 | 0 | { |
47 | 0 | auto const i = _s.find("//"); |
48 | 0 | auto const e = i == _s.npos ? end(_s) : next(begin(_s), static_cast<ptrdiff_t>(i)); |
49 | 0 | auto const opening = count_if(begin(_s), e, [](auto ch) { return ch == '{' || ch == '('; }); |
50 | 0 | auto const closing = count_if(begin(_s), e, [](auto ch) { return ch == '}' || ch == ')'; }); |
51 | 0 | return int(opening - closing); |
52 | 0 | }; |
53 | |
|
54 | 0 | vector<string> lines; |
55 | 0 | boost::split(lines, _code, boost::is_any_of("\n")); |
56 | 0 | for (string& line: lines) |
57 | 0 | boost::trim(line); |
58 | | |
59 | | // Reduce multiple consecutive empty lines. |
60 | 0 | lines = fold(lines, vector<string>{}, [](auto&& _lines, auto&& _line) { |
61 | 0 | if (!(_line.empty() && !_lines.empty() && _lines.back().empty())) |
62 | 0 | _lines.emplace_back(std::move(_line)); |
63 | 0 | return std::move(_lines); |
64 | 0 | }); |
65 | |
|
66 | 0 | stringstream out; |
67 | 0 | int depth = 0; |
68 | |
|
69 | 0 | for (string const& line: lines) |
70 | 0 | { |
71 | 0 | int const diff = countBraces(line); |
72 | 0 | if (diff < 0) |
73 | 0 | depth += diff; |
74 | |
|
75 | 0 | if (!line.empty()) |
76 | 0 | { |
77 | 0 | for (int i = 0; i < depth * indentationWidth; ++i) |
78 | 0 | out << ' '; |
79 | 0 | out << line; |
80 | 0 | } |
81 | 0 | out << '\n'; |
82 | |
|
83 | 0 | if (diff > 0) |
84 | 0 | depth += diff; |
85 | 0 | } |
86 | |
|
87 | 0 | return out.str(); |
88 | 0 | } |
89 | | |
90 | | u256 solidity::yul::valueOfNumberLiteral(Literal const& _literal) |
91 | 286M | { |
92 | 286M | yulAssert(_literal.kind == LiteralKind::Number, "Expected number literal!"); |
93 | | |
94 | 286M | std::string const& literalString = _literal.value.str(); |
95 | 286M | yulAssert(isValidDecimal(literalString) || isValidHex(literalString), "Invalid number literal!"); |
96 | 286M | return u256(literalString); |
97 | 286M | } |
98 | | |
99 | | u256 solidity::yul::valueOfStringLiteral(Literal const& _literal) |
100 | 33.0k | { |
101 | 33.0k | yulAssert(_literal.kind == LiteralKind::String, "Expected string literal!"); |
102 | 33.0k | yulAssert(_literal.value.str().size() <= 32, "Literal string too long!"); |
103 | | |
104 | 33.0k | return u256(h256(_literal.value.str(), h256::FromBinary, h256::AlignLeft)); |
105 | 33.0k | } |
106 | | |
107 | | u256 yul::valueOfBoolLiteral(Literal const& _literal) |
108 | 700k | { |
109 | 700k | yulAssert(_literal.kind == LiteralKind::Boolean, "Expected bool literal!"); |
110 | | |
111 | 700k | if (_literal.value == "true"_yulstring) |
112 | 684k | return u256(1); |
113 | 15.3k | else if (_literal.value == "false"_yulstring) |
114 | 15.3k | return u256(0); |
115 | | |
116 | 0 | yulAssert(false, "Unexpected bool literal value!"); |
117 | 0 | } |
118 | | |
119 | | u256 solidity::yul::valueOfLiteral(Literal const& _literal) |
120 | 35.3M | { |
121 | 35.3M | switch (_literal.kind) |
122 | 35.3M | { |
123 | 34.6M | case LiteralKind::Number: |
124 | 34.6M | return valueOfNumberLiteral(_literal); |
125 | 700k | case LiteralKind::Boolean: |
126 | 700k | return valueOfBoolLiteral(_literal); |
127 | 33.0k | case LiteralKind::String: |
128 | 33.0k | return valueOfStringLiteral(_literal); |
129 | 0 | default: |
130 | 0 | yulAssert(false, "Unexpected literal kind!"); |
131 | 35.3M | } |
132 | 35.3M | } |
133 | | |
134 | | template<> |
135 | | bool Less<Literal>::operator()(Literal const& _lhs, Literal const& _rhs) const |
136 | 201k | { |
137 | 201k | if (std::make_tuple(_lhs.kind, _lhs.type) != std::make_tuple(_rhs.kind, _rhs.type)) |
138 | 11.1k | return std::make_tuple(_lhs.kind, _lhs.type) < std::make_tuple(_rhs.kind, _rhs.type); |
139 | | |
140 | 190k | if (_lhs.kind == LiteralKind::Number) |
141 | 190k | return valueOfNumberLiteral(_lhs) < valueOfNumberLiteral(_rhs); |
142 | 394 | else |
143 | 394 | return _lhs.value < _rhs.value; |
144 | 190k | } |
145 | | |
146 | | bool SwitchCaseCompareByLiteralValue::operator()(Case const* _lhs, Case const* _rhs) const |
147 | 227k | { |
148 | 227k | yulAssert(_lhs && _rhs, ""); |
149 | 227k | return Less<Literal*>{}(_lhs->value.get(), _rhs->value.get()); |
150 | 227k | } |