Browse Source

Merge pull request #953 from LefterisJP/sol_ethSubDenominations

Solidity ether subdenominations
cl-refactor
Gav Wood 10 years ago
parent
commit
fe3bd818f3
  1. 11
      libsolidity/AST.cpp
  2. 18
      libsolidity/AST.h
  3. 8
      libsolidity/Parser.cpp
  4. 6
      libsolidity/Token.h
  5. 30
      libsolidity/Types.cpp
  6. 70
      test/SolidityExpressionCompiler.cpp
  7. 19
      test/SolidityParser.cpp
  8. 9
      test/SolidityScanner.cpp

11
libsolidity/AST.cpp

@ -594,6 +594,17 @@ void ElementaryTypeNameExpression::checkTypeRequirements()
m_type = make_shared<TypeType>(Type::fromElementaryTypeName(m_typeToken));
}
Literal::Literal(Location const& _location, Token::Value _token,
ASTPointer<ASTString> const& _value,
Token::Value _sub):
PrimaryExpression(_location), m_token(_token), m_value(_value)
{
if (Token::isEtherSubdenomination(_sub))
m_subDenomination = static_cast<Literal::SubDenomination>(_sub);
else
m_subDenomination = Literal::SubDenomination::None;
}
void Literal::checkTypeRequirements()
{
m_type = Type::forLiteral(*this);

18
libsolidity/AST.h

@ -1112,13 +1112,22 @@ private:
};
/**
* A literal string or number. @see Type::literalToBigEndian is used to actually parse its value.
* A literal string or number. @see ExpressionCompiler::endVisit() is used to actually parse its value.
*/
class Literal: public PrimaryExpression
{
public:
Literal(Location const& _location, Token::Value _token, ASTPointer<ASTString> const& _value):
PrimaryExpression(_location), m_token(_token), m_value(_value) {}
enum class SubDenomination
{
None = Token::ILLEGAL,
Wei = Token::SubWei,
Szabo = Token::SubSzabo,
Finney = Token::SubFinney,
Ether = Token::SubEther
};
Literal(Location const& _location, Token::Value _token,
ASTPointer<ASTString> const& _value,
Token::Value _sub = Token::ILLEGAL);
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
@ -1127,9 +1136,12 @@ public:
/// @returns the non-parsed value of the literal
ASTString const& getValue() const { return *m_value; }
SubDenomination getSubDenomination() const { return m_subDenomination; }
private:
Token::Value m_token;
ASTPointer<ASTString> m_value;
SubDenomination m_subDenomination;
};
/// @}

8
libsolidity/Parser.cpp

@ -180,7 +180,7 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token)
{
Declaration::Visibility visibility;
Declaration::Visibility visibility = Declaration::Visibility::DEFAULT;
if (_token == Token::PUBLIC)
visibility = Declaration::Visibility::PUBLIC;
else if (_token == Token::PROTECTED)
@ -684,6 +684,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
ASTNodeFactory nodeFactory(*this);
Token::Value token = m_scanner->getCurrentToken();
ASTPointer<Expression> expression;
Token::Value nextToken = Token::ILLEGAL;
switch (token)
{
case Token::TRUE_LITERAL:
@ -691,9 +692,12 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance());
break;
case Token::NUMBER:
nextToken = m_scanner->peekNextToken();
case Token::STRING_LITERAL:
nodeFactory.markEndPosition();
expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance());
expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance(), nextToken);
if (Token::isEtherSubdenomination(nextToken))
m_scanner->next();
break;
case Token::IDENTIFIER:
nodeFactory.markEndPosition();

6
libsolidity/Token.h

@ -174,6 +174,11 @@ namespace solidity
K(WHILE, "while", 0) \
\
\
/* Ether subdenominations */ \
K(SubWei, "wei", 0) \
K(SubSzabo, "szabo", 0) \
K(SubFinney, "finney", 0) \
K(SubEther, "ether", 0) \
/* type keywords, keep them in this order, keep int as first keyword
* the implementation in Types.cpp has to be synced to this here
* TODO more to be added */ \
@ -378,6 +383,7 @@ public:
static bool isCountOp(Value op) { return op == INC || op == DEC; }
static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); }
static bool isVisibilitySpecifier(Value op) { return op == PUBLIC || op == PRIVATE || op == PROTECTED; }
static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == Token::SubEther; }
// Returns a string corresponding to the JS token string
// (.e., "<" for the token LT) or NULL if the token doesn't

30
libsolidity/Types.cpp

@ -326,15 +326,39 @@ string IntegerConstantType::toString() const
return "int_const " + m_value.str();
}
u256 IntegerConstantType::literalValue(Literal const*) const
u256 IntegerConstantType::literalValue(Literal const* _literal) const
{
u256 value;
// we ignore the literal and hope that the type was correctly determined
solAssert(m_value <= u256(-1), "Integer constant too large.");
solAssert(m_value >= -(bigint(1) << 255), "Integer constant too small.");
if (m_value >= 0)
return u256(m_value);
value = u256(m_value);
else
return s2u(s256(m_value));
value = s2u(s256(m_value));
if (_literal)
{
Literal::SubDenomination sub =_literal->getSubDenomination();
switch(sub)
{
case Literal::SubDenomination::Wei:
case Literal::SubDenomination::None:
break;
case Literal::SubDenomination::Szabo:
value *= u256(1000000000000);
break;
case Literal::SubDenomination::Finney:
value *= u256(1000000000000000);
break;
case Literal::SubDenomination::Ether:
value *= u256(1000000000000000000);
break;
}
}
return value;
}
shared_ptr<IntegerType const> IntegerConstantType::getIntegerType() const

70
test/SolidityExpressionCompiler.cpp

@ -91,7 +91,15 @@ bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _
{
Parser parser;
ASTPointer<SourceUnit> sourceUnit;
BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
try
{
sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode)));
}
catch(boost::exception const& _e)
{
auto msg = std::string("Parsing source code failed with: \n") + boost::diagnostic_information(_e);
BOOST_FAIL(msg);
}
vector<Declaration const*> declarations;
declarations.reserve(_globalDeclarations.size() + 1);
@ -177,6 +185,66 @@ BOOST_AUTO_TEST_CASE(int_literal)
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(int_with_wei_ether_subdenomination)
{
char const* sourceCode = R"(
contract test {
function test ()
{
var x = 1 wei;
}
})";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x1});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(int_with_szabo_ether_subdenomination)
{
char const* sourceCode = R"(
contract test {
function test ()
{
var x = 1 szabo;
}
})";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH5), 0xe8, 0xd4, 0xa5, 0x10, 0x00});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(int_with_finney_ether_subdenomination)
{
char const* sourceCode = R"(
contract test {
function test ()
{
var x = 1 finney;
}
})";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH7), 0x3, 0x8d, 0x7e, 0xa4, 0xc6, 0x80, 0x00});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(int_with_ether_ether_subdenomination)
{
char const* sourceCode = R"(
contract test {
function test ()
{
var x = 1 ether;
}
})";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH8), 0xd, 0xe0, 0xb6, 0xb3, 0xa7, 0x64, 0x00, 0x00});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(comparison)
{
char const* sourceCode = "contract test {\n"

19
test/SolidityParser.cpp

@ -660,6 +660,25 @@ BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers)
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations)
{
char const* text = R"(
contract c {
function c ()
{
a = 1 wei;
b = 2 szabo;
c = 3 finney;
b = 4 ether;
}
uint256 a;
uint256 b;
uint256 c;
uint256 d;
})";
BOOST_CHECK_NO_THROW(parseTextExplainError(text));
}
BOOST_AUTO_TEST_SUITE_END()
}

9
test/SolidityScanner.cpp

@ -255,6 +255,15 @@ BOOST_AUTO_TEST_CASE(comments_mixed_in_sequence)
BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), "documentation comment ");
}
BOOST_AUTO_TEST_CASE(ether_subdenominations)
{
Scanner scanner(CharStream("wei szabo finney ether"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::SubWei);
BOOST_CHECK_EQUAL(scanner.next(), Token::SubSzabo);
BOOST_CHECK_EQUAL(scanner.next(), Token::SubFinney);
BOOST_CHECK_EQUAL(scanner.next(), Token::SubEther);
}
BOOST_AUTO_TEST_SUITE_END()
}

Loading…
Cancel
Save