Logical operators.

This commit is contained in:
chriseth 2019-05-02 18:09:19 +02:00
parent 055254847e
commit c604481cef
3 changed files with 50 additions and 5 deletions

View File

@ -199,16 +199,23 @@ void IRGeneratorForStatements::endVisit(UnaryOperation const& _unaryOperation)
solUnimplementedAssert(false, "");
}
void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp)
bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
{
solAssert(!!_binOp.annotation().commonType, "");
TypePointer commonType = _binOp.annotation().commonType;
langutil::Token op = _binOp.getOperator();
if (op == Token::And || op == Token::Or)
// special case: short-circuiting
solUnimplementedAssert(false, "");
else if (commonType->category() == Type::Category::RationalNumber)
{
// This can short-circuit!
appendAndOrOperatorCode(_binOp);
return false;
}
_binOp.leftExpression().accept(*this);
_binOp.rightExpression().accept(*this);
if (commonType->category() == Type::Category::RationalNumber)
defineExpression(_binOp) <<
toCompactHexWithPrefix(commonType->literalValue(nullptr)) <<
"\n";
@ -259,6 +266,7 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp)
else
solUnimplementedAssert(false, "");
}
return false;
}
void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
@ -429,6 +437,24 @@ ostream& IRGeneratorForStatements::defineExpression(Expression const& _expressio
return m_code << "let " << m_context.variable(_expression) << " := ";
}
void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp)
{
langutil::Token const op = _binOp.getOperator();
solAssert(op == Token::Or || op == Token::And, "");
_binOp.leftExpression().accept(*this);
string value = m_context.variable(_binOp);
m_code << "let " << value << " := " << m_context.variable(_binOp.leftExpression()) << "\n";
if (op == Token::Or)
m_code << "if iszero(" << value << ") {\n";
else
m_code << "if " << value << " {\n";
_binOp.rightExpression().accept(*this);
m_code << value << " := " + m_context.variable(_binOp.rightExpression()) << "\n";
m_code << "}\n";
}
void IRGeneratorForStatements::setLValue(Expression const& _expression, unique_ptr<IRLValue> _lvalue)
{
solAssert(!m_currentLValue, "");

View File

@ -52,7 +52,7 @@ public:
bool visit(Break const& _breakStatement) override;
void endVisit(Return const& _return) override;
void endVisit(UnaryOperation const& _unaryOperation) override;
void endVisit(BinaryOperation const& _binOp) override;
bool visit(BinaryOperation const& _binOp) override;
void endVisit(FunctionCall const& _funCall) override;
bool visit(InlineAssembly const& _inlineAsm) override;
bool visit(Identifier const& _identifier) override;
@ -64,6 +64,8 @@ private:
std::string expressionAsType(Expression const& _expression, Type const& _to);
std::ostream& defineExpression(Expression const& _expression);
void appendAndOrOperatorCode(BinaryOperation const& _binOp);
void setLValue(Expression const& _expression, std::unique_ptr<IRLValue> _lvalue);
static Type const& type(Expression const& _expression);

View File

@ -0,0 +1,17 @@
contract C {
function or(uint x) public returns (bool t, uint y) {
t = (x == 0 || ((x = 8) > 0));
y = x;
}
function and(uint x) public returns (bool t, uint y) {
t = (x == 0 && ((x = 8) > 0));
y = x;
}
}
// ====
// compileViaYul: true
// ----
// or(uint256): 0 -> true, 0
// and(uint256): 0 -> true, 8
// or(uint256): 1 -> true, 8
// and(uint256): 1 -> false, 1