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  * Component that translates Solidity code into Yul at statement level and below.
20  */
21 
22 #pragma once
23 
24 #include <libsolidity/ast/ASTVisitor.h>
25 #include <libsolidity/codegen/ir/IRLValue.h>
26 #include <libsolidity/codegen/ir/IRVariable.h>
27 
28 #include <functional>
29 
30 namespace solidity::frontend
31 {
32 
33 class IRGenerationContext;
34 class YulUtilFunctions;
35 
36 /**
37  * Base class for the statement generator.
38  * Encapsulates access to the yul code stream and handles source code locations.
39  */
40 class IRGeneratorForStatementsBase: public ASTConstVisitor
41 {
42 public:
IRGeneratorForStatementsBase(IRGenerationContext & _context)43 	IRGeneratorForStatementsBase(IRGenerationContext& _context):
44 		m_context(_context)
45 	{}
46 
47 	virtual std::string code() const;
48 	std::ostringstream& appendCode(bool _addLocationComment = true);
49 protected:
50 	void setLocation(ASTNode const& _node);
51 	langutil::SourceLocation m_currentLocation = {};
52 	langutil::SourceLocation m_lastLocation = {};
53 	IRGenerationContext& m_context;
54 private:
55 	std::ostringstream m_code;
56 };
57 
58 /**
59  * Component that translates Solidity's AST into Yul at statement level and below.
60  * It is an AST visitor that appends to an internal string buffer.
61  */
62 class IRGeneratorForStatements: public IRGeneratorForStatementsBase
63 {
64 public:
65 	IRGeneratorForStatements(
66 		IRGenerationContext& _context,
67 		YulUtilFunctions& _utils,
68 		std::function<std::string()> _placeholderCallback = {}
69 	):
IRGeneratorForStatementsBase(_context)70 		IRGeneratorForStatementsBase(_context),
71 		m_placeholderCallback(std::move(_placeholderCallback)),
72 		m_utils(_utils)
73 	{}
74 
75 	std::string code() const override;
76 
77 	/// Generate the code for the statements in the block;
78 	void generate(Block const& _block);
79 
80 	/// Generates code to initialize the given state variable.
81 	void initializeStateVar(VariableDeclaration const& _varDecl);
82 	/// Generates code to initialize the given local variable.
83 	void initializeLocalVar(VariableDeclaration const& _varDecl);
84 
85 	/// Calculates expression's value and returns variable where it was stored
86 	IRVariable evaluateExpression(Expression const& _expression, Type const& _to);
87 
88 	/// Defines @a _var using the value of @a _value while performing type conversions, if required.
define(IRVariable const & _var,IRVariable const & _value)89 	void define(IRVariable const& _var, IRVariable const& _value) { declareAssign(_var, _value, true); }
90 
91 	/// @returns the name of a function that computes the value of the given constant
92 	/// and also generates the function.
93 	std::string constantValueFunction(VariableDeclaration const& _constant);
94 
95 	void endVisit(VariableDeclarationStatement const& _variableDeclaration) override;
96 	bool visit(Conditional const& _conditional) override;
97 	bool visit(Assignment const& _assignment) override;
98 	bool visit(TupleExpression const& _tuple) override;
99 	void endVisit(PlaceholderStatement const& _placeholder) override;
100 	bool visit(Block const& _block) override;
101 	void endVisit(Block const& _block) override;
102 	bool visit(IfStatement const& _ifStatement) override;
103 	bool visit(ForStatement const& _forStatement) override;
104 	bool visit(WhileStatement const& _whileStatement) override;
105 	bool visit(Continue const& _continueStatement) override;
106 	bool visit(Break const& _breakStatement) override;
107 	void endVisit(Return const& _return) override;
108 	bool visit(UnaryOperation const& _unaryOperation) override;
109 	bool visit(BinaryOperation const& _binOp) override;
110 	void endVisit(FunctionCall const& _funCall) override;
111 	void endVisit(FunctionCallOptions const& _funCallOptions) override;
112 	bool visit(MemberAccess const& _memberAccess) override;
113 	void endVisit(MemberAccess const& _memberAccess) override;
114 	bool visit(InlineAssembly const& _inlineAsm) override;
115 	void endVisit(IndexAccess const& _indexAccess) override;
116 	void endVisit(IndexRangeAccess const& _indexRangeAccess) override;
117 	void endVisit(Identifier const& _identifier) override;
118 	bool visit(Literal const& _literal) override;
119 
120 	bool visit(TryStatement const& _tryStatement) override;
121 	bool visit(TryCatchClause const& _tryCatchClause) override;
122 
123 private:
124 	/// Handles all catch cases of a try statement, except the success-case.
125 	void handleCatch(TryStatement const& _tryStatement);
126 	void handleCatchFallback(TryCatchClause const& _fallback);
127 
128 	/// Generates code to revert with an error. The error arguments are assumed to
129 	/// be already evaluated and available in local IRVariables, but not yet
130 	/// converted.
131 	void revertWithError(
132 		std::string const& _signature,
133 		std::vector<Type const*> const& _parameterTypes,
134 		std::vector<ASTPointer<Expression const>> const& _errorArguments
135 	);
136 
137 	void handleVariableReference(
138 		VariableDeclaration const& _variable,
139 		Expression const& _referencingExpression
140 	);
141 
142 	/// Appends code to call an external function with the given arguments.
143 	/// All involved expressions have already been visited.
144 	void appendExternalFunctionCall(
145 		FunctionCall const& _functionCall,
146 		std::vector<ASTPointer<Expression const>> const& _arguments
147 	);
148 
149 	/// Appends code for .call / .delegatecall / .staticcall.
150 	/// All involved expressions have already been visited.
151 	void appendBareCall(
152 		FunctionCall const& _functionCall,
153 		std::vector<ASTPointer<Expression const>> const& _arguments
154 	);
155 
156 	/// Requests and assigns the internal ID of the referenced function to the referencing
157 	/// expression and adds the function to the internal dispatch.
158 	/// If the function is called right away, it does nothing.
159 	void assignInternalFunctionIDIfNotCalledDirectly(
160 		Expression const& _expression,
161 		FunctionDefinition const& _referencedFunction
162 	);
163 
164 	/// Generates the required conversion code and @returns an IRVariable referring to the value of @a _variable
165 	/// converted to type @a _to.
166 	IRVariable convert(IRVariable const& _variable, Type const& _to);
167 
168 	/// @returns a Yul expression representing the current value of @a _expression,
169 	/// converted to type @a _to if it does not yet have that type.
170 	/// If @a _forceCleanup is set to true, it also cleans the value, in case it already has type @a _to.
171 	std::string expressionAsType(Expression const& _expression, Type const& _to, bool _forceCleanup = false);
172 
173 	/// @returns an output stream that can be used to define @a _var using a function call or
174 	/// single stack slot expression.
175 	std::ostream& define(IRVariable const& _var);
176 
177 	/// Assigns @a _var to the value of @a _value while performing type conversions, if required.
assign(IRVariable const & _var,IRVariable const & _value)178 	void assign(IRVariable const& _var, IRVariable const& _value) { declareAssign(_var, _value, false); }
179 	/// Declares variable @a _var.
180 	void declare(IRVariable const& _var);
181 
182 	void declareAssign(IRVariable const& _var, IRVariable const& _value, bool _define);
183 
184 	/// @returns an IRVariable with the zero
185 	/// value of @a _type.
186 	/// @param _splitFunctionTypes if false, returns two zeroes
187 	IRVariable zeroValue(Type const& _type, bool _splitFunctionTypes = true);
188 
189 	void appendAndOrOperatorCode(BinaryOperation const& _binOp);
190 	void appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr);
191 
192 	/// @returns code to perform the given binary operation in the given type on the two values.
193 	std::string binaryOperation(
194 		langutil::Token _op,
195 		Type const& _type,
196 		std::string const& _left,
197 		std::string const& _right
198 	);
199 
200 	/// @returns code to perform the given shift operation.
201 	/// The operation itself will be performed in the type of the value,
202 	/// while the amount to shift can have its own type.
203 	std::string shiftOperation(langutil::Token _op, IRVariable const& _value, IRVariable const& _shiftAmount);
204 
205 	/// Assigns the value of @a _value to the lvalue @a _lvalue.
206 	void writeToLValue(IRLValue const& _lvalue, IRVariable const& _value);
207 	/// @returns a fresh IR variable containing the value of the lvalue @a _lvalue.
208 	IRVariable readFromLValue(IRLValue const& _lvalue);
209 
210 	/// Stores the given @a _lvalue in m_currentLValue, if it will be written to (willBeWrittenTo). Otherwise
211 	/// defines the expression @a _expression by reading the value from @a _lvalue.
212 	void setLValue(Expression const& _expression, IRLValue _lvalue);
213 	void generateLoop(
214 		Statement const& _body,
215 		Expression const* _conditionExpression,
216 		Statement const*  _initExpression = nullptr,
217 		ExpressionStatement const* _loopExpression = nullptr,
218 		bool _isDoWhile = false
219 	);
220 
221 	static Type const& type(Expression const& _expression);
222 
223 	std::string linkerSymbol(ContractDefinition const& _library) const;
224 
225 	std::function<std::string()> m_placeholderCallback;
226 	YulUtilFunctions& m_utils;
227 	std::optional<IRLValue> m_currentLValue;
228 };
229 
230 }
231