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