aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/codegen/ExpressionCompiler.h
blob: 9a695b4c98b32b479698bff50febb4177abd8464 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
    This file is part of solidity.

    solidity is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    solidity is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with solidity.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @author Gav Wood <g@ethdev.com>
 * @date 2014
 * Solidity AST to EVM bytecode compiler for expressions.
 */

#include <functional>
#include <memory>
#include <boost/noncopyable.hpp>
#include <libdevcore/Common.h>
#include <libevmasm/SourceLocation.h>
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/codegen/LValue.h>
#include <libsolidity/interface/Exceptions.h>

namespace dev {
namespace eth
{
class AssemblyItem; // forward
}
namespace solidity {

// forward declarations
class CompilerContext;
class CompilerUtils;
class Type;
class IntegerType;
class ArrayType;

/**
 * Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream
 * of EVM instructions. It needs a compiler context that is the same for the whole compilation
 * unit.
 */
class ExpressionCompiler: private ASTConstVisitor
{
public:
    /// Appends code for a State Variable accessor function
    static void appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false);

    explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false):
        m_optimize(_optimize), m_context(_compilerContext) {}

    /// Compile the given @a _expression and leave its value on the stack.
    void compile(Expression const& _expression);

    /// Appends code to set a state variable to its initial value/expression.
    void appendStateVariableInitialization(VariableDeclaration const& _varDecl);

    /// Appends code for a State Variable accessor function
    void appendStateVariableAccessor(VariableDeclaration const& _varDecl);

    /// Appends code for a Constant State Variable accessor function
    void appendConstStateVariableAccessor(const VariableDeclaration& _varDecl);

private:
    bool visit(Conditional const& _condition) override;
    bool visit(Assignment const& _assignment) override;
    bool visit(TupleExpression const& _tuple) override;
    bool visit(UnaryOperation const& _unaryOperation) override;
    bool visit(BinaryOperation const& _binaryOperation) override;
    bool visit(FunctionCall const& _functionCall) override;
    bool visit(NewExpression const& _newExpression) override;
    bool visit(MemberAccess const& _memberAccess) override;
    bool visit(IndexAccess const& _indexAccess) override;
    void endVisit(Identifier const& _identifier) override;
    void endVisit(Literal const& _literal) override;

    ///@{
    ///@name Append code for various operator types
    void appendAndOrOperatorCode(BinaryOperation const& _binaryOperation);
    void appendCompareOperatorCode(Token _operator, Type const& _type);
    void appendOrdinaryBinaryOperatorCode(Token _operator, Type const& _type);

    void appendArithmeticOperatorCode(Token _operator, Type const& _type);
    void appendBitOperatorCode(Token _operator);
    void appendShiftOperatorCode(Token _operator, Type const& _valueType, Type const& _shiftAmountType);
    /// @}

    /// Appends code to call a function of the given type with the given arguments.
    void appendExternalFunctionCall(
        FunctionType const& _functionType,
        std::vector<ASTPointer<Expression const>> const& _arguments
    );
    /// Appends code that evaluates a single expression and moves the result to memory. The memory offset is
    /// expected to be on the stack and is updated by this call.
    void appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression);

    /// Appends code for a variable that might be a constant or not
    void appendVariable(VariableDeclaration const& _variable, Expression const& _expression);
    /// Sets the current LValue to a new one (of the appropriate type) from the given declaration.
    /// Also retrieves the value if it was not requested by @a _expression.
    void setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression);
    /// Sets the current LValue to a StorageItem holding the type of @a _expression. The reference is assumed
    /// to be on the stack.
    /// Also retrieves the value if it was not requested by @a _expression.
    void setLValueToStorageItem(Expression const& _expression);
    /// Sets the current LValue to a new LValue constructed from the arguments.
    /// Also retrieves the value if it was not requested by @a _expression.
    template <class _LValueType, class... _Arguments>
    void setLValue(Expression const& _expression, _Arguments const&... _arguments);

    /// @returns true if the operator applied to the given type requires a cleanup prior to the
    /// operation.
    static bool cleanupNeededForOp(Type::Category _type, Token _op);

    /// @returns the CompilerUtils object containing the current context.
    CompilerUtils utils();

    bool m_optimize;
    CompilerContext& m_context;
    std::unique_ptr<LValue> m_currentLValue;

};

template <class _LValueType, class... _Arguments>
void ExpressionCompiler::setLValue(Expression const& _expression, _Arguments const&... _arguments)
{
    solAssert(!m_currentLValue, "Current LValue not reset before trying to set new one.");
    std::unique_ptr<_LValueType> lvalue(new _LValueType(m_context, _arguments...));
    if (_expression.annotation().lValueRequested)
        m_currentLValue = move(lvalue);
    else
        lvalue->retrieveValue(_expression.location(), true);
}

}
}