Browse Source

Support for negative literals.

cl-refactor
Christian 10 years ago
parent
commit
1b9e014374
  1. 22
      libsolidity/Scanner.cpp
  2. 2
      libsolidity/Scanner.h
  3. 8
      libsolidity/Types.cpp
  4. 41
      test/solidityExpressionCompiler.cpp
  5. 26
      test/solidityScanner.cpp

22
libsolidity/Scanner.cpp

@ -271,7 +271,7 @@ void Scanner::scanToken()
token = Token::ADD;
break;
case '-':
// - -- -=
// - -- -= Number
advance();
if (m_char == '-')
{
@ -280,6 +280,8 @@ void Scanner::scanToken()
}
else if (m_char == '=')
token = selectToken(Token::ASSIGN_SUB);
else if (m_char == '.' || IsDecimalDigit(m_char))
token = scanNumber('-');
else
token = Token::SUB;
break;
@ -331,7 +333,7 @@ void Scanner::scanToken()
// . Number
advance();
if (IsDecimalDigit(m_char))
token = scanNumber(true);
token = scanNumber('.');
else
token = Token::PERIOD;
break;
@ -372,7 +374,7 @@ void Scanner::scanToken()
if (IsIdentifierStart(m_char))
token = scanIdentifierOrKeyword();
else if (IsDecimalDigit(m_char))
token = scanNumber(false);
token = scanNumber();
else if (skipWhitespace())
token = Token::WHITESPACE;
else if (isSourcePastEndOfInput())
@ -461,14 +463,11 @@ void Scanner::scanDecimalDigits()
}
Token::Value Scanner::scanNumber(bool _periodSeen)
Token::Value Scanner::scanNumber(char _charSeen)
{
// the first digit of the number or the fraction
if (asserts(IsDecimalDigit(m_char)))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Number does not start with decimal digit."));
enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL;
enum { DECIMAL, HEX, BINARY } kind = DECIMAL;
LiteralScope literal(this);
if (_periodSeen)
if (_charSeen == '.')
{
// we have already seen a decimal point of the float
addLiteralChar('.');
@ -476,12 +475,13 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
}
else
{
if (_charSeen == '-')
addLiteralChar('-');
// if the first character is '0' we must check for octals and hex
if (m_char == '0')
{
addLiteralCharAndAdvance();
// either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or
// an octal number.
// either 0, 0exxx, 0Exxx, 0.xxx or a hex number
if (m_char == 'x' || m_char == 'X')
{
// hex number

2
libsolidity/Scanner.h

@ -180,7 +180,7 @@ private:
Token::Value skipMultiLineComment();
void scanDecimalDigits();
Token::Value scanNumber(bool _periodSeen);
Token::Value scanNumber(char _charSeen = 0);
Token::Value scanIdentifierOrKeyword();
Token::Value scanString();

8
libsolidity/Types.cpp

@ -89,10 +89,14 @@ shared_ptr<Type> Type::forLiteral(Literal const& _literal)
shared_ptr<IntegerType> IntegerType::smallestTypeForLiteral(string const& _literal)
{
bigint value(_literal);
bool isSigned = value < 0 || (!_literal.empty() && _literal.front() == '-');
if (isSigned)
// convert to positive number of same bit requirements
value = ((-value) - 1) << 1;
unsigned bytes = max(bytesRequired(value), 1u);
if (bytes > 32)
return shared_ptr<IntegerType>();
return make_shared<IntegerType>(bytes * 8, Modifier::UNSIGNED);
return make_shared<IntegerType>(bytes * 8, isSigned ? Modifier::SIGNED : Modifier::UNSIGNED);
}
IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
@ -169,8 +173,6 @@ string IntegerType::toString() const
u256 IntegerType::literalValue(Literal const& _literal) const
{
bigint value(_literal.getValue());
//@todo check that the number is not too large
//@todo does this work for signed numbers?
return u256(value);
}

41
test/solidityExpressionCompiler.cpp

@ -227,7 +227,7 @@ BOOST_AUTO_TEST_CASE(arithmetics)
BOOST_AUTO_TEST_CASE(unary_operators)
{
char const* sourceCode = "contract test {\n"
" function f() { var x = !(~+-1 == 2); }"
" function f() { var x = !(~+- 1 == 2); }"
"}\n";
bytes code = compileFirstExpression(sourceCode);
@ -347,6 +347,45 @@ BOOST_AUTO_TEST_CASE(function_call)
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(negative_literals_8bits)
{
// these all fit in 8 bits
char const* sourceCode = "contract test {\n"
" function f() { int8 x = -0 + -1 + -0x01 + -127 + -128; }\n"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation(bytes({byte(eth::Instruction::PUSH1), 0x00,
byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) +
bytes({byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) +
bytes({byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x81) +
bytes({byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80) +
bytes({byte(eth::Instruction::ADD)}));
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(negative_literals_16bits)
{
// -1 should need 8 bits, -129 should need 16 bits, how many bits are used is visible
// from the SIGNEXTEND opcodes
char const* sourceCode = "contract test {\n"
" function f() { int64 x = int64(-1 + -129); }\n"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) +
bytes({byte(eth::Instruction::PUSH1), 0x00,
byte(eth::Instruction::SIGNEXTEND),
byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x7f) +
bytes({byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH1), 0x01,
byte(eth::Instruction::SIGNEXTEND)}));
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_SUITE_END()
}

26
test/solidityScanner.cpp

@ -97,6 +97,27 @@ BOOST_AUTO_TEST_CASE(hex_numbers)
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
}
BOOST_AUTO_TEST_CASE(negative_numbers)
{
Scanner scanner(CharStream("var x = -.2 + -0x78 + -7.3 + 8.9;"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::VAR);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.next(), Token::ASSIGN);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-.2");
BOOST_CHECK_EQUAL(scanner.next(), Token::ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-0x78");
BOOST_CHECK_EQUAL(scanner.next(), Token::ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-7.3");
BOOST_CHECK_EQUAL(scanner.next(), Token::ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "8.9");
BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON);
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
}
BOOST_AUTO_TEST_CASE(locations)
{
Scanner scanner(CharStream("function_identifier has ; -0x743/*comment*/\n ident //comment"));
@ -109,11 +130,8 @@ BOOST_AUTO_TEST_CASE(locations)
BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 24);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 25);
BOOST_CHECK_EQUAL(scanner.next(), Token::SUB);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 27);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 27);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 32);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 45);

Loading…
Cancel
Save