aboutsummaryrefslogtreecommitdiffstats
path: root/ExpressionCompiler.h
blob: bd5a9f8662e8ded35589bba2d8d0ca196967f5ed (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
/*
    This file is part of cpp-ethereum.

    cpp-ethereum 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.

    cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Solidity AST to EVM bytecode compiler for expressions.
 */

#include <libdevcore/Common.h>
#include <libsolidity/ASTVisitor.h>

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

class CompilerContext; // forward
class Type; // forward
class IntegerType; // forward

/**
 * 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 ASTVisitor
{
public:
    /// Compile the given @a _expression into the @a _context.
    static void compileExpression(CompilerContext& _context, Expression& _expression);

    /// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type.
    static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType);

private:
    ExpressionCompiler(CompilerContext& _compilerContext): m_context(_compilerContext) {}

    virtual bool visit(Assignment& _assignment) override;
    virtual void endVisit(UnaryOperation& _unaryOperation) override;
    virtual bool visit(BinaryOperation& _binaryOperation) override;
    virtual bool visit(FunctionCall& _functionCall) override;
    virtual void endVisit(MemberAccess& _memberAccess) override;
    virtual void endVisit(IndexAccess& _indexAccess) override;
    virtual void endVisit(Identifier& _identifier) override;
    virtual void endVisit(Literal& _literal) override;

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

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

    /// Appends an implicit or explicit type conversion. For now this comprises only erasing
    /// higher-order bits (@see appendHighBitCleanup) when widening integer types.
    /// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be
    /// necessary.
    void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false);
    //// Appends code that cleans higher-order bits for integer types.
    void appendHighBitsCleanup(IntegerType const& _typeOnStack);

    /// Copies the value of the current lvalue to the top of the stack.
    void retrieveLValueValue(Expression const& _expression);
    /// Stores the value on top of the stack in the current lvalue. Removes it from the stack if
    /// @a _move is true.
    void storeInLValue(Expression const& _expression, bool _move = false);

    /**
     * Location of an lvalue, either in code (for a function) on the stack, in the storage or memory.
     */
    struct LValueLocation
    {
        enum LocationType { INVALID, CODE, STACK, MEMORY, STORAGE };

        LValueLocation() { reset(); }
        LValueLocation(LocationType _type, u256 const& _location): locationType(_type), location(_location) {}
        void reset() { locationType = INVALID; location = 0; }
        bool isValid() const { return locationType != INVALID; }
        bool isInCode() const { return locationType == CODE; }
        bool isInOnStack() const { return locationType == STACK; }
        bool isInMemory() const { return locationType == MEMORY; }
        bool isInStorage() const { return locationType == STORAGE; }

        LocationType locationType;
        /// Depending on the type, this is the id of a tag (code), the base offset of a stack
        /// variable (@see CompilerContext::getBaseStackOffsetOfVariable) or the offset in
        /// storage or memory.
        u256 location;
    };

    LValueLocation m_currentLValue;
    CompilerContext& m_context;
};


}
}