Lu Guanqun 10 years ago
parent
commit
e85fe2348f
  1. 3
      libsolidity/ExpressionCompiler.cpp
  2. 10
      libsolidity/Scanner.cpp
  3. 5
      libsolidity/Token.h
  4. 10
      libsolidity/Types.cpp
  5. 30
      test/SolidityEndToEndTest.cpp
  6. 11
      test/SolidityParser.cpp

3
libsolidity/ExpressionCompiler.cpp

@ -650,6 +650,9 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty
case Token::Mod: case Token::Mod:
m_context << (c_isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); m_context << (c_isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD);
break; break;
case Token::Exp:
m_context << eth::Instruction::EXP;
break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator."));
} }

10
libsolidity/Scanner.cpp

@ -465,8 +465,14 @@ void Scanner::scanToken()
token = Token::Sub; token = Token::Sub;
break; break;
case '*': case '*':
// * *= // * ** *=
token = selectToken('=', Token::AssignMul, Token::Mul); advance();
if (m_char == '*')
token = selectToken(Token::Exp);
else if (m_char == '=')
token = selectToken(Token::AssignMul);
else
token = Token::Mul;
break; break;
case '%': case '%':
// % %= // % %=

5
libsolidity/Token.h

@ -118,6 +118,7 @@ namespace solidity
T(Mul, "*", 13) \ T(Mul, "*", 13) \
T(Div, "/", 13) \ T(Div, "/", 13) \
T(Mod, "%", 13) \ T(Mod, "%", 13) \
T(Exp, "**", 14) \
\ \
/* Compare operators sorted by precedence. */ \ /* Compare operators sorted by precedence. */ \
/* IsCompareOp() relies on this block of enum values */ \ /* IsCompareOp() relies on this block of enum values */ \
@ -361,10 +362,10 @@ public:
// Predicates // Predicates
static bool isElementaryTypeName(Value tok) { return Int <= tok && tok < TypesEnd; } static bool isElementaryTypeName(Value tok) { return Int <= tok && tok < TypesEnd; }
static bool isAssignmentOp(Value tok) { return Assign <= tok && tok <= AssignMod; } static bool isAssignmentOp(Value tok) { return Assign <= tok && tok <= AssignMod; }
static bool isBinaryOp(Value op) { return Comma <= op && op <= Mod; } static bool isBinaryOp(Value op) { return Comma <= op && op <= Exp; }
static bool isCommutativeOp(Value op) { return op == BitOr || op == BitXor || op == BitAnd || static bool isCommutativeOp(Value op) { return op == BitOr || op == BitXor || op == BitAnd ||
op == Add || op == Mul || op == Equal || op == NotEqual; } op == Add || op == Mul || op == Equal || op == NotEqual; }
static bool isArithmeticOp(Value op) { return Add <= op && op <= Mod; } static bool isArithmeticOp(Value op) { return Add <= op && op <= Exp; }
static bool isCompareOp(Value op) { return Equal <= op && op <= In; } static bool isCompareOp(Value op) { return Equal <= op && op <= In; }
static Value AssignmentToBinaryOp(Value op) static Value AssignmentToBinaryOp(Value op)

10
libsolidity/Types.cpp

@ -320,6 +320,16 @@ TypePointer IntegerConstantType::binaryOperatorResult(Token::Value _operator, Ty
return TypePointer(); return TypePointer();
value = m_value % other.m_value; value = m_value % other.m_value;
break; break;
case Token::Exp:
if (other.m_value < 0)
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("exponent can't be negative"));
else
{
value = boost::multiprecision::powm(m_value, other.m_value, bigint(2) << 256);
if (value >= (bigint(1) << 256))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("exp result overflowed"));
}
break;
default: default:
return TypePointer(); return TypePointer();
} }

30
test/SolidityEndToEndTest.cpp

@ -56,6 +56,36 @@ BOOST_AUTO_TEST_CASE(empty_contract)
BOOST_CHECK(callContractFunction("i_am_not_there()", bytes()).empty()); BOOST_CHECK(callContractFunction("i_am_not_there()", bytes()).empty());
} }
BOOST_AUTO_TEST_CASE(exp_operator)
{
char const* sourceCode = R"(
contract test {
function f(uint a) returns(uint d) { return 2 ** a; }
})";
compileAndRun(sourceCode);
testSolidityAgainstCppOnRange("f(uint256)", [](u256 const& a) -> u256 { return u256(1 << a.convert_to<int>()); }, 0, 16);
}
BOOST_AUTO_TEST_CASE(exp_operator_const)
{
char const* sourceCode = R"(
contract test {
function f() returns(uint d) { return 2 ** 3; }
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("f()", bytes()) == toBigEndian(u256(8)));
}
BOOST_AUTO_TEST_CASE(exp_operator_const_signed)
{
char const* sourceCode = R"(
contract test {
function f() returns(int d) { return -2 ** 3; }
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("f()", bytes()) == toBigEndian(u256(-8)));
}
BOOST_AUTO_TEST_CASE(recursive_calls) BOOST_AUTO_TEST_CASE(recursive_calls)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"

11
test/SolidityParser.cpp

@ -387,6 +387,17 @@ BOOST_AUTO_TEST_CASE(complex_expression)
BOOST_CHECK_NO_THROW(parseText(text)); BOOST_CHECK_NO_THROW(parseText(text));
} }
BOOST_AUTO_TEST_CASE(exp_expression)
{
char const* text = R"(
contract test {
function fun(uint256 a) {
uint256 x = 3 ** a;
}
})";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(while_loop) BOOST_AUTO_TEST_CASE(while_loop)
{ {
char const* text = "contract test {\n" char const* text = "contract test {\n"

Loading…
Cancel
Save