Browse Source

Add date/time language to solidity.

cl-refactor
Gav Wood 10 years ago
parent
commit
e2f1bc4133
  1. 4
      libdevcore/FixedHash.h
  2. 8
      libsolidity/AST.h
  3. 3
      libsolidity/ExpressionCompiler.cpp
  4. 9
      libsolidity/Parser.cpp
  5. 24
      libsolidity/Token.h
  6. 19
      libsolidity/Types.cpp
  7. 9
      mix/MixClient.cpp
  8. 17
      test/SolidityScanner.cpp
  9. 14
      test/blockchain.cpp

4
libdevcore/FixedHash.h

@ -85,8 +85,8 @@ public:
// The obvious comparison operators. // The obvious comparison operators.
bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; } bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }
bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; } bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; }
bool operator<(FixedHash const& _c) const { return m_data < _c.m_data; } bool operator<(FixedHash const& _c) const { for (unsigned i = 0; i < N; ++i) if (m_data[i] < _c.m_data[i]) return true; else if (m_data[i] > _c.m_data[i]) return false; return false; }
bool operator>=(FixedHash const& _c) const { return m_data >= _c.m_data; } bool operator>=(FixedHash const& _c) const { return !operator<(_c); }
// The obvious binary operators. // The obvious binary operators.
FixedHash& operator^=(FixedHash const& _c) { for (unsigned i = 0; i < N; ++i) m_data[i] ^= _c.m_data[i]; return *this; } FixedHash& operator^=(FixedHash const& _c) { for (unsigned i = 0; i < N; ++i) m_data[i] ^= _c.m_data[i]; return *this; }

8
libsolidity/AST.h

@ -1197,7 +1197,13 @@ public:
Wei = Token::SubWei, Wei = Token::SubWei,
Szabo = Token::SubSzabo, Szabo = Token::SubSzabo,
Finney = Token::SubFinney, Finney = Token::SubFinney,
Ether = Token::SubEther Ether = Token::SubEther,
Second = Token::SubSecond,
Minute = Token::SubMinute,
Hour = Token::SubHour,
Day = Token::SubDay,
Week = Token::SubWeek,
Year = Token::SubYear
}; };
Literal(SourceLocation const& _location, Token::Value _token, Literal(SourceLocation const& _location, Token::Value _token,
ASTPointer<ASTString> const& _value, ASTPointer<ASTString> const& _value,

3
libsolidity/ExpressionCompiler.cpp

@ -258,6 +258,9 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
case Token::BitNot: // ~ case Token::BitNot: // ~
m_context << eth::Instruction::NOT; m_context << eth::Instruction::NOT;
break; break;
case Token::After: // after
m_context << eth::Instruction::TIMESTAMP << eth::Instruction::ADD;
break;
case Token::Delete: // delete case Token::Delete: // delete
solAssert(!!m_currentLValue, "LValue not retrieved."); solAssert(!!m_currentLValue, "LValue not retrieved.");
m_currentLValue->setToZero(_unaryOperation.getLocation()); m_currentLValue->setToZero(_unaryOperation.getLocation());

9
libsolidity/Parser.cpp

@ -822,6 +822,15 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
expression = nodeFactory.createNode<Literal>(token, literal, subdenomination); expression = nodeFactory.createNode<Literal>(token, literal, subdenomination);
break; break;
} }
if (Token::isTimeSubdenomination(m_scanner->peekNextToken()))
{
ASTPointer<ASTString> literal = getLiteralAndAdvance();
nodeFactory.markEndPosition();
Literal::SubDenomination subdenomination = static_cast<Literal::SubDenomination>(m_scanner->getCurrentToken());
m_scanner->next();
expression = nodeFactory.createNode<Literal>(token, literal, subdenomination);
break;
}
// fall-through // fall-through
case Token::StringLiteral: case Token::StringLiteral:
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();

24
libsolidity/Token.h

@ -163,7 +163,7 @@ namespace solidity
K(New, "new", 0) \ K(New, "new", 0) \
K(Public, "public", 0) \ K(Public, "public", 0) \
K(Private, "private", 0) \ K(Private, "private", 0) \
K(Internal, "internal", 0) \ K(Internal, "internal", 0) \
K(Return, "return", 0) \ K(Return, "return", 0) \
K(Returns, "returns", 0) \ K(Returns, "returns", 0) \
K(Struct, "struct", 0) \ K(Struct, "struct", 0) \
@ -172,11 +172,18 @@ namespace solidity
K(While, "while", 0) \ K(While, "while", 0) \
K(Enum, "enum", 0) \ K(Enum, "enum", 0) \
\ \
/* Ether subdenominations */ \ /* Ether subdenominations */ \
K(SubWei, "wei", 0) \ K(SubWei, "wei", 0) \
K(SubSzabo, "szabo", 0) \ K(SubSzabo, "szabo", 0) \
K(SubFinney, "finney", 0) \ K(SubFinney, "finney", 0) \
K(SubEther, "ether", 0) \ K(SubEther, "ether", 0) \
K(SubSecond, "seconds", 0) \
K(SubMinute, "minutes", 0) \
K(SubHour, "hours", 0) \
K(SubDay, "days", 0) \
K(SubWeek, "weeks", 0) \
K(SubYear, "years", 0) \
K(After, "after", 0) \
/* type keywords, keep them in this order, keep int as first keyword /* type keywords, keep them in this order, keep int as first keyword
* the implementation in Types.cpp has to be synced to this here */\ * the implementation in Types.cpp has to be synced to this here */\
K(Int, "int", 0) \ K(Int, "int", 0) \
@ -377,12 +384,13 @@ public:
} }
static bool isBitOp(Value op) { return (BitOr <= op && op <= SHR) || op == BitNot; } static bool isBitOp(Value op) { return (BitOr <= op && op <= SHR) || op == BitNot; }
static bool isUnaryOp(Value op) { return (Not <= op && op <= Delete) || op == Add || op == Sub; } static bool isUnaryOp(Value op) { return (Not <= op && op <= Delete) || op == Add || op == Sub || op == After; }
static bool isCountOp(Value op) { return op == Inc || op == Dec; } static bool isCountOp(Value op) { return op == Inc || op == Dec; }
static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); }
static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; } static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; }
static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; } static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; }
static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == Token::SubEther; } static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == SubEther; }
static bool isTimeSubdenomination(Value op) { return op == SubSecond || op == SubMinute || op == SubHour || op == SubDay || op == SubWeek || op == SubYear; }
// Returns a string corresponding to the JS token string // Returns a string corresponding to the JS token string
// (.e., "<" for the token LT) or NULL if the token doesn't // (.e., "<" for the token LT) or NULL if the token doesn't

19
libsolidity/Types.cpp

@ -195,7 +195,8 @@ TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const
return TypePointer(); return TypePointer();
// for non-hash integers, we allow +, -, ++ and -- // for non-hash integers, we allow +, -, ++ and --
else if (_operator == Token::Add || _operator == Token::Sub || else if (_operator == Token::Add || _operator == Token::Sub ||
_operator == Token::Inc || _operator == Token::Dec) _operator == Token::Inc || _operator == Token::Dec ||
_operator == Token::After)
return shared_from_this(); return shared_from_this();
else else
return TypePointer(); return TypePointer();
@ -251,6 +252,7 @@ IntegerConstantType::IntegerConstantType(Literal const& _literal)
switch (_literal.getSubDenomination()) switch (_literal.getSubDenomination())
{ {
case Literal::SubDenomination::Wei: case Literal::SubDenomination::Wei:
case Literal::SubDenomination::Second:
case Literal::SubDenomination::None: case Literal::SubDenomination::None:
break; break;
case Literal::SubDenomination::Szabo: case Literal::SubDenomination::Szabo:
@ -262,6 +264,21 @@ IntegerConstantType::IntegerConstantType(Literal const& _literal)
case Literal::SubDenomination::Ether: case Literal::SubDenomination::Ether:
m_value *= bigint("1000000000000000000"); m_value *= bigint("1000000000000000000");
break; break;
case Literal::SubDenomination::Minute:
m_value *= bigint("60");
break;
case Literal::SubDenomination::Hour:
m_value *= bigint("3600");
break;
case Literal::SubDenomination::Day:
m_value *= bigint("86400");
break;
case Literal::SubDenomination::Week:
m_value *= bigint("604800");
break;
case Literal::SubDenomination::Year:
m_value *= bigint("31536000");
break;
} }
} }

9
mix/MixClient.cpp

@ -46,15 +46,18 @@ const u256 c_mixGenesisDifficulty = (u256) 1 << 4;
class MixBlockChain: public dev::eth::BlockChain class MixBlockChain: public dev::eth::BlockChain
{ {
public: public:
MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, true) MixBlockChain(std::string const& _path, h256 _stateRoot):
BlockChain(createGenesisBlock(_stateRoot), _path, true)
{ {
} }
static bytes createGenesisBlock(h256 _stateRoot) static bytes createGenesisBlock(h256 _stateRoot)
{ {
RLPStream block(3); RLPStream block(3);
block.appendList(14) block.appendList(16)
<< h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_mixGenesisDifficulty << 0 << 1000000 << 0 << (unsigned)0 << std::string() << sha3(bytes(1, 42)); << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie
<< LogBloom() << c_mixGenesisDifficulty << 0 << 1000000 << 0 << (unsigned)0
<< std::string() << h256() << h256() << h64(u64(42));
block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList);
return block.out(); return block.out();

17
test/SolidityScanner.cpp

@ -264,6 +264,23 @@ BOOST_AUTO_TEST_CASE(ether_subdenominations)
BOOST_CHECK_EQUAL(scanner.next(), Token::SubEther); BOOST_CHECK_EQUAL(scanner.next(), Token::SubEther);
} }
BOOST_AUTO_TEST_CASE(time_subdenominations)
{
Scanner scanner(CharStream("seconds minutes hours days weeks years"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::SubSecond);
BOOST_CHECK_EQUAL(scanner.next(), Token::SubMinute);
BOOST_CHECK_EQUAL(scanner.next(), Token::SubHour);
BOOST_CHECK_EQUAL(scanner.next(), Token::SubDay);
BOOST_CHECK_EQUAL(scanner.next(), Token::SubWeek);
BOOST_CHECK_EQUAL(scanner.next(), Token::SubYear);
}
BOOST_AUTO_TEST_CASE(time_after)
{
Scanner scanner(CharStream("after 1"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::After);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

14
test/blockchain.cpp

@ -78,8 +78,8 @@ bytes createBlockRLPFromFields(mObject& _tObj)
if (_tObj.count("seedHash")) if (_tObj.count("seedHash"))
rlpStream << importByteArray(_tObj["seedHash"].get_str()); rlpStream << importByteArray(_tObj["seedHash"].get_str());
if (_tObj.count("mixBytes")) if (_tObj.count("mixHash"))
rlpStream << importByteArray(_tObj["mixBytes"].get_str()); rlpStream << importByteArray(_tObj["mixHash"].get_str());
if (_tObj.count("nonce")) if (_tObj.count("nonce"))
rlpStream << importByteArray(_tObj["nonce"].get_str()); rlpStream << importByteArray(_tObj["nonce"].get_str());
@ -146,7 +146,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
//update genesis block in json file //update genesis block in json file
o["genesisBlockHeader"].get_obj()["stateRoot"] = toString(blockFromFields.stateRoot); o["genesisBlockHeader"].get_obj()["stateRoot"] = toString(blockFromFields.stateRoot);
o["genesisBlockHeader"].get_obj()["nonce"] = toString(blockFromFields.nonce); o["genesisBlockHeader"].get_obj()["nonce"] = toString(blockFromFields.nonce);
o["genesisBlockHeader"].get_obj()["mixBytes"] = toString(blockFromFields.mixBytes); o["genesisBlockHeader"].get_obj()["mixHash"] = toString(blockFromFields.mixHash);
} }
// create new "genesis" block // create new "genesis" block
@ -276,8 +276,8 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
if (blObj["blockHeader"].get_obj().count("extraData")) if (blObj["blockHeader"].get_obj().count("extraData"))
tmp.extraData = importByteArray(blObj["blockHeader"].get_obj()["extraData"].get_str()); tmp.extraData = importByteArray(blObj["blockHeader"].get_obj()["extraData"].get_str());
if (blObj["blockHeader"].get_obj().count("mixBytes")) if (blObj["blockHeader"].get_obj().count("mixHash"))
tmp.mixBytes = h256(blObj["blockHeader"].get_obj()["mixBytes"].get_str()); tmp.mixHash = h256(blObj["blockHeader"].get_obj()["mixHash"].get_str());
if (blObj["blockHeader"].get_obj().count("seedHash")) if (blObj["blockHeader"].get_obj().count("seedHash"))
tmp.seedHash = h256(blObj["blockHeader"].get_obj()["seedHash"].get_str()); tmp.seedHash = h256(blObj["blockHeader"].get_obj()["seedHash"].get_str());
@ -322,7 +322,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
oBlockHeader["gasUsed"] = toString(current_BlockHeader.gasUsed); oBlockHeader["gasUsed"] = toString(current_BlockHeader.gasUsed);
oBlockHeader["timestamp"] = toString(current_BlockHeader.timestamp); oBlockHeader["timestamp"] = toString(current_BlockHeader.timestamp);
oBlockHeader["extraData"] = toHex(current_BlockHeader.extraData); oBlockHeader["extraData"] = toHex(current_BlockHeader.extraData);
oBlockHeader["mixBytes"] = toString(current_BlockHeader.mixBytes); oBlockHeader["mixHash"] = toString(current_BlockHeader.mixHash);
oBlockHeader["seedHash"] = toString(current_BlockHeader.seedHash); oBlockHeader["seedHash"] = toString(current_BlockHeader.seedHash);
oBlockHeader["nonce"] = toString(current_BlockHeader.nonce); oBlockHeader["nonce"] = toString(current_BlockHeader.nonce);
@ -445,7 +445,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.mixBytes == blockFromRlp.mixBytes, "mixBytes in given RLP not matching the block mixBytes!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.mixHash == blockFromRlp.mixHash, "mixHash in given RLP not matching the block mixHash!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.seedHash == blockFromRlp.seedHash, "transactionsRoot in given RLP not matching the block transactionsRoot!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.seedHash == blockFromRlp.seedHash, "transactionsRoot in given RLP not matching the block transactionsRoot!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!");

Loading…
Cancel
Save