#pragma once
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/codegen/ir/IRLValue.h>
#include <libsolidity/codegen/ir/IRVariable.h>
#include <functional>
namespace solidity::frontend
{
class IRGenerationContext;
class YulUtilFunctions;
class IRGeneratorForStatementsBase: public ASTConstVisitor
{
public:
IRGeneratorForStatementsBase(IRGenerationContext& _context):
m_context(_context)
{}
virtual std::string code() const;
std::ostringstream& appendCode(bool _addLocationComment = true);
protected:
void setLocation(ASTNode const& _node);
langutil::SourceLocation m_currentLocation = {};
langutil::SourceLocation m_lastLocation = {};
IRGenerationContext& m_context;
private:
std::ostringstream m_code;
};
class IRGeneratorForStatements: public IRGeneratorForStatementsBase
{
public:
IRGeneratorForStatements(
IRGenerationContext& _context,
YulUtilFunctions& _utils,
std::function<std::string()> _placeholderCallback = {}
):
IRGeneratorForStatementsBase(_context),
m_placeholderCallback(std::move(_placeholderCallback)),
m_utils(_utils)
{}
std::string code() const override;
void generate(Block const& _block);
void initializeStateVar(VariableDeclaration const& _varDecl);
void initializeLocalVar(VariableDeclaration const& _varDecl);
IRVariable evaluateExpression(Expression const& _expression, Type const& _to);
void define(IRVariable const& _var, IRVariable const& _value)
{
bool _declare = true;
declareAssign(_var, _value, _declare);
}
void defineAndCleanup(IRVariable const& _var, IRVariable const& _value)
{
bool _forceCleanup = true;
bool _declare = true;
declareAssign(_var, _value, _declare, _forceCleanup);
}
std::string constantValueFunction(VariableDeclaration const& _constant);
void endVisit(VariableDeclarationStatement const& _variableDeclaration) override;
bool visit(Conditional const& _conditional) override;
bool visit(Assignment const& _assignment) override;
bool visit(TupleExpression const& _tuple) override;
void endVisit(PlaceholderStatement const& _placeholder) override;
bool visit(Block const& _block) override;
void endVisit(Block const& _block) override;
bool visit(IfStatement const& _ifStatement) override;
bool visit(ForStatement const& _forStatement) override;
bool visit(WhileStatement const& _whileStatement) override;
bool visit(Continue const& _continueStatement) override;
bool visit(Break const& _breakStatement) override;
void endVisit(Return const& _return) override;
bool visit(UnaryOperation const& _unaryOperation) override;
bool visit(BinaryOperation const& _binOp) override;
void endVisit(FunctionCall const& _funCall) override;
void endVisit(FunctionCallOptions const& _funCallOptions) override;
bool visit(MemberAccess const& _memberAccess) override;
void endVisit(MemberAccess const& _memberAccess) override;
bool visit(InlineAssembly const& _inlineAsm) override;
void endVisit(IndexAccess const& _indexAccess) override;
void endVisit(IndexRangeAccess const& _indexRangeAccess) override;
void endVisit(Identifier const& _identifier) override;
bool visit(Literal const& _literal) override;
bool visit(TryStatement const& _tryStatement) override;
bool visit(TryCatchClause const& _tryCatchClause) override;
private:
void handleCatch(TryStatement const& _tryStatement);
void handleCatchFallback(TryCatchClause const& _fallback);
void revertWithError(
std::string const& _signature,
std::vector<Type const*> const& _parameterTypes,
std::vector<ASTPointer<Expression const>> const& _errorArguments
);
void handleVariableReference(
VariableDeclaration const& _variable,
Expression const& _referencingExpression
);
void appendExternalFunctionCall(
FunctionCall const& _functionCall,
std::vector<ASTPointer<Expression const>> const& _arguments
);
void appendBareCall(
FunctionCall const& _functionCall,
std::vector<ASTPointer<Expression const>> const& _arguments
);
void assignInternalFunctionIDIfNotCalledDirectly(
Expression const& _expression,
FunctionDefinition const& _referencedFunction
);
IRVariable convert(IRVariable const& _variable, Type const& _to);
IRVariable convertAndCleanup(IRVariable const& _from, Type const& _to);
std::string expressionAsType(Expression const& _expression, Type const& _to);
std::string expressionAsCleanedType(Expression const& _expression, Type const& _to);
std::ostream& define(IRVariable const& _var);
void assign(IRVariable const& _var, IRVariable const& _value) { declareAssign(_var, _value, false); }
void declare(IRVariable const& _var);
void declareAssign(IRVariable const& _var, IRVariable const& _value, bool _define, bool _forceCleanup = false);
IRVariable zeroValue(Type const& _type, bool _splitFunctionTypes = true);
void appendAndOrOperatorCode(BinaryOperation const& _binOp);
void appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr);
std::string binaryOperation(
langutil::Token _op,
Type const& _type,
std::string const& _left,
std::string const& _right
);
std::string shiftOperation(langutil::Token _op, IRVariable const& _value, IRVariable const& _shiftAmount);
void writeToLValue(IRLValue const& _lvalue, IRVariable const& _value);
IRVariable readFromLValue(IRLValue const& _lvalue);
void setLValue(Expression const& _expression, IRLValue _lvalue);
void generateLoop(
Statement const& _body,
Expression const* _conditionExpression,
Statement const* _initExpression = nullptr,
ExpressionStatement const* _loopExpression = nullptr,
bool _isDoWhile = false
);
static Type const& type(Expression const& _expression);
std::string linkerSymbol(ContractDefinition const& _library) const;
std::function<std::string()> m_placeholderCallback;
YulUtilFunctions& m_utils;
std::optional<IRLValue> m_currentLValue;
};
}