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 * @author Christian <c@ethdev.com>
20 * @date 2016
21 * Parsed inline assembly to be used by the AST
22 */
23
24 #pragma once
25
26 #include <libyul/ASTForward.h>
27 #include <libyul/YulString.h>
28
29 #include <liblangutil/SourceLocation.h>
30
31 #include <memory>
32 #include <optional>
33
34 namespace solidity::yul
35 {
36
37 using Type = YulString;
38
39 struct DebugData
40 {
41 explicit DebugData(
42 langutil::SourceLocation _nativeLocation,
43 langutil::SourceLocation _originLocation = {},
44 std::optional<int64_t> _astID = {}
45 ):
nativeLocationDebugData46 nativeLocation(std::move(_nativeLocation)),
47 originLocation(std::move(_originLocation)),
48 astID(std::move(_astID))
49 {}
50
51 static std::shared_ptr<DebugData const> create(
52 langutil::SourceLocation _nativeLocation = {},
53 langutil::SourceLocation _originLocation = {},
54 std::optional<int64_t> _astID = {}
55 )
56 {
57 return std::make_shared<DebugData const>(
58 std::move(_nativeLocation),
59 std::move(_originLocation),
60 std::move(_astID)
61 );
62 }
63
64 /// Location in the Yul code.
65 langutil::SourceLocation nativeLocation;
66 /// Location in the original source that the Yul code was produced from.
67 /// Optional. Only present if the Yul source contains location annotations.
68 langutil::SourceLocation originLocation;
69 /// ID in the (Solidity) source AST.
70 std::optional<int64_t> astID;
71 };
72
73 struct TypedName { std::shared_ptr<DebugData const> debugData; YulString name; Type type; };
74 using TypedNameList = std::vector<TypedName>;
75
76 /// Literal number or string (up to 32 bytes)
77 enum class LiteralKind { Number, Boolean, String };
78 struct Literal { std::shared_ptr<DebugData const> debugData; LiteralKind kind; YulString value; Type type; };
79 /// External / internal identifier or label reference
80 struct Identifier { std::shared_ptr<DebugData const> debugData; YulString name; };
81 /// Assignment ("x := mload(20:u256)", expects push-1-expression on the right hand
82 /// side and requires x to occupy exactly one stack slot.
83 ///
84 /// Multiple assignment ("x, y := f()"), where the left hand side variables each occupy
85 /// a single stack slot and expects a single expression on the right hand returning
86 /// the same amount of items as the number of variables.
87 struct Assignment { std::shared_ptr<DebugData const> debugData; std::vector<Identifier> variableNames; std::unique_ptr<Expression> value; };
88 struct FunctionCall { std::shared_ptr<DebugData const> debugData; Identifier functionName; std::vector<Expression> arguments; };
89 /// Statement that contains only a single expression
90 struct ExpressionStatement { std::shared_ptr<DebugData const> debugData; Expression expression; };
91 /// Block-scope variable declaration ("let x:u256 := mload(20:u256)"), non-hoisted
92 struct VariableDeclaration { std::shared_ptr<DebugData const> debugData; TypedNameList variables; std::unique_ptr<Expression> value; };
93 /// Block that creates a scope (frees declared stack variables)
94 struct Block { std::shared_ptr<DebugData const> debugData; std::vector<Statement> statements; };
95 /// Function definition ("function f(a, b) -> (d, e) { ... }")
96 struct FunctionDefinition { std::shared_ptr<DebugData const> debugData; YulString name; TypedNameList parameters; TypedNameList returnVariables; Block body; };
97 /// Conditional execution without "else" part.
98 struct If { std::shared_ptr<DebugData const> debugData; std::unique_ptr<Expression> condition; Block body; };
99 /// Switch case or default case
100 struct Case { std::shared_ptr<DebugData const> debugData; std::unique_ptr<Literal> value; Block body; };
101 /// Switch statement
102 struct Switch { std::shared_ptr<DebugData const> debugData; std::unique_ptr<Expression> expression; std::vector<Case> cases; };
103 struct ForLoop { std::shared_ptr<DebugData const> debugData; Block pre; std::unique_ptr<Expression> condition; Block post; Block body; };
104 /// Break statement (valid within for loop)
105 struct Break { std::shared_ptr<DebugData const> debugData; };
106 /// Continue statement (valid within for loop)
107 struct Continue { std::shared_ptr<DebugData const> debugData; };
108 /// Leave statement (valid within function)
109 struct Leave { std::shared_ptr<DebugData const> debugData; };
110
111 /// Extracts the IR source location from a Yul node.
nativeLocationOf(T const & _node)112 template <class T> inline langutil::SourceLocation nativeLocationOf(T const& _node)
113 {
114 return _node.debugData ? _node.debugData->nativeLocation : langutil::SourceLocation{};
115 }
116
117 /// Extracts the IR source location from a Yul node.
nativeLocationOf(std::variant<Args...> const & _node)118 template <class... Args> inline langutil::SourceLocation nativeLocationOf(std::variant<Args...> const& _node)
119 {
120 return std::visit([](auto const& _arg) { return nativeLocationOf(_arg); }, _node);
121 }
122
123 /// Extracts the original source location from a Yul node.
originLocationOf(T const & _node)124 template <class T> inline langutil::SourceLocation originLocationOf(T const& _node)
125 {
126 return _node.debugData ? _node.debugData->originLocation : langutil::SourceLocation{};
127 }
128
129 /// Extracts the original source location from a Yul node.
originLocationOf(std::variant<Args...> const & _node)130 template <class... Args> inline langutil::SourceLocation originLocationOf(std::variant<Args...> const& _node)
131 {
132 return std::visit([](auto const& _arg) { return originLocationOf(_arg); }, _node);
133 }
134
135 /// Extracts the debug data from a Yul node.
debugDataOf(T const & _node)136 template <class T> inline std::shared_ptr<DebugData const> debugDataOf(T const& _node)
137 {
138 return _node.debugData;
139 }
140
141 /// Extracts the debug data from a Yul node.
debugDataOf(std::variant<Args...> const & _node)142 template <class... Args> inline std::shared_ptr<DebugData const> debugDataOf(std::variant<Args...> const& _node)
143 {
144 return std::visit([](auto const& _arg) { return debugDataOf(_arg); }, _node);
145 }
146
147 }
148