From d8ddf5949799e6ad24e4e456e15df1d107226878 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 2 Mar 2015 18:10:32 +0100 Subject: [PATCH 1/5] Solidity STOPs in case of failed call. --- ExpressionCompiler.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 430e46b06..63aa8a3c2 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -984,9 +984,10 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos)); else // send all gas except for the 21 needed to execute "SUB" and "CALL" - m_context << u256(21) << eth::Instruction::GAS << eth::Instruction::SUB; - m_context << eth::Instruction::CALL - << eth::Instruction::POP; // @todo do not ignore failure indicator + m_context << u256(_functionType.valueSet() ? 6741 : 41) << eth::Instruction::GAS << eth::Instruction::SUB; + m_context << eth::Instruction::CALL; + auto tag = m_context.appendConditionalJump(); + m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0. if (_functionType.valueSet()) m_context << eth::Instruction::POP; if (_functionType.gasSet()) @@ -999,10 +1000,12 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio CompilerUtils(m_context).loadFromMemory(0, *firstType, false, true); } -void ExpressionCompiler::appendArgumentsCopyToMemory(vector> const& _arguments, - TypePointers const& _types, - bool _padToWordBoundaries, - bool _padExceptionIfFourBytes) +void ExpressionCompiler::appendArgumentsCopyToMemory( + vector> const& _arguments, + TypePointers const& _types, + bool _padToWordBoundaries, + bool _padExceptionIfFourBytes +) { solAssert(_types.empty() || _types.size() == _arguments.size(), ""); for (size_t i = 0; i < _arguments.size(); ++i) From 5aff9fbde2c33a5bf2edf3e54c421a654a02e90c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 4 Mar 2015 17:35:23 +0100 Subject: [PATCH 2/5] Add date/time language to solidity. --- AST.h | 8 +++++++- ExpressionCompiler.cpp | 3 +++ Parser.cpp | 9 +++++++++ Token.h | 24 ++++++++++++++++-------- Types.cpp | 19 ++++++++++++++++++- 5 files changed, 53 insertions(+), 10 deletions(-) diff --git a/AST.h b/AST.h index c91c433ed..c3c2cd8d3 100644 --- a/AST.h +++ b/AST.h @@ -1197,7 +1197,13 @@ public: Wei = Token::SubWei, Szabo = Token::SubSzabo, 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, ASTPointer const& _value, diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 619b06738..38d9aac86 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -250,6 +250,9 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) case Token::BitNot: // ~ m_context << eth::Instruction::NOT; break; + case Token::After: // after + m_context << eth::Instruction::TIMESTAMP << eth::Instruction::ADD; + break; case Token::Delete: // delete solAssert(!!m_currentLValue, "LValue not retrieved."); m_currentLValue->setToZero(_unaryOperation.getLocation()); diff --git a/Parser.cpp b/Parser.cpp index 3c88efc7c..44d111591 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -822,6 +822,15 @@ ASTPointer Parser::parsePrimaryExpression() expression = nodeFactory.createNode(token, literal, subdenomination); break; } + if (Token::isTimeSubdenomination(m_scanner->peekNextToken())) + { + ASTPointer literal = getLiteralAndAdvance(); + nodeFactory.markEndPosition(); + Literal::SubDenomination subdenomination = static_cast(m_scanner->getCurrentToken()); + m_scanner->next(); + expression = nodeFactory.createNode(token, literal, subdenomination); + break; + } // fall-through case Token::StringLiteral: nodeFactory.markEndPosition(); diff --git a/Token.h b/Token.h index 5e4a6317f..2997bb493 100644 --- a/Token.h +++ b/Token.h @@ -162,7 +162,7 @@ namespace solidity K(New, "new", 0) \ K(Public, "public", 0) \ K(Private, "private", 0) \ - K(Internal, "internal", 0) \ + K(Internal, "internal", 0) \ K(Return, "return", 0) \ K(Returns, "returns", 0) \ K(Struct, "struct", 0) \ @@ -171,11 +171,18 @@ namespace solidity K(While, "while", 0) \ K(Enum, "enum", 0) \ \ - /* Ether subdenominations */ \ - K(SubWei, "wei", 0) \ - K(SubSzabo, "szabo", 0) \ - K(SubFinney, "finney", 0) \ - K(SubEther, "ether", 0) \ + /* Ether subdenominations */ \ + K(SubWei, "wei", 0) \ + K(SubSzabo, "szabo", 0) \ + K(SubFinney, "finney", 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 * the implementation in Types.cpp has to be synced to this here */\ K(Int, "int", 0) \ @@ -376,12 +383,13 @@ public: } 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 isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; } 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 // (.e., "<" for the token LT) or NULL if the token doesn't diff --git a/Types.cpp b/Types.cpp index 22d612cd9..2105d6299 100644 --- a/Types.cpp +++ b/Types.cpp @@ -195,7 +195,8 @@ TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const return TypePointer(); // for non-hash integers, we allow +, -, ++ and -- 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(); else return TypePointer(); @@ -251,6 +252,7 @@ IntegerConstantType::IntegerConstantType(Literal const& _literal) switch (_literal.getSubDenomination()) { case Literal::SubDenomination::Wei: + case Literal::SubDenomination::Second: case Literal::SubDenomination::None: break; case Literal::SubDenomination::Szabo: @@ -262,6 +264,21 @@ IntegerConstantType::IntegerConstantType(Literal const& _literal) case Literal::SubDenomination::Ether: m_value *= bigint("1000000000000000000"); 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; } } From de2ed72e6b0b8c2f447d87468428be16c77a5f53 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 4 Mar 2015 19:55:52 +0100 Subject: [PATCH 3/5] Params & JSON file. --- Types.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Types.cpp b/Types.cpp index 2105d6299..865a32c3a 100644 --- a/Types.cpp +++ b/Types.cpp @@ -308,6 +308,8 @@ TypePointer IntegerConstantType::unaryOperatorResult(Token::Value _operator) con case Token::Sub: value = -m_value; break; + case Token::After: + return shared_from_this(); default: return TypePointer(); } From 4822154f61c60482fcee74cf0f9b4eb16e11aa4e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 4 Mar 2015 17:35:23 +0100 Subject: [PATCH 4/5] Add date/time language to solidity. --- AST.h | 8 +++++++- ExpressionCompiler.cpp | 3 +++ Parser.cpp | 9 +++++++++ Token.h | 24 ++++++++++++++++-------- Types.cpp | 19 ++++++++++++++++++- 5 files changed, 53 insertions(+), 10 deletions(-) diff --git a/AST.h b/AST.h index c91c433ed..c3c2cd8d3 100644 --- a/AST.h +++ b/AST.h @@ -1197,7 +1197,13 @@ public: Wei = Token::SubWei, Szabo = Token::SubSzabo, 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, ASTPointer const& _value, diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 619b06738..38d9aac86 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -250,6 +250,9 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) case Token::BitNot: // ~ m_context << eth::Instruction::NOT; break; + case Token::After: // after + m_context << eth::Instruction::TIMESTAMP << eth::Instruction::ADD; + break; case Token::Delete: // delete solAssert(!!m_currentLValue, "LValue not retrieved."); m_currentLValue->setToZero(_unaryOperation.getLocation()); diff --git a/Parser.cpp b/Parser.cpp index 3c88efc7c..44d111591 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -822,6 +822,15 @@ ASTPointer Parser::parsePrimaryExpression() expression = nodeFactory.createNode(token, literal, subdenomination); break; } + if (Token::isTimeSubdenomination(m_scanner->peekNextToken())) + { + ASTPointer literal = getLiteralAndAdvance(); + nodeFactory.markEndPosition(); + Literal::SubDenomination subdenomination = static_cast(m_scanner->getCurrentToken()); + m_scanner->next(); + expression = nodeFactory.createNode(token, literal, subdenomination); + break; + } // fall-through case Token::StringLiteral: nodeFactory.markEndPosition(); diff --git a/Token.h b/Token.h index 5e4a6317f..2997bb493 100644 --- a/Token.h +++ b/Token.h @@ -162,7 +162,7 @@ namespace solidity K(New, "new", 0) \ K(Public, "public", 0) \ K(Private, "private", 0) \ - K(Internal, "internal", 0) \ + K(Internal, "internal", 0) \ K(Return, "return", 0) \ K(Returns, "returns", 0) \ K(Struct, "struct", 0) \ @@ -171,11 +171,18 @@ namespace solidity K(While, "while", 0) \ K(Enum, "enum", 0) \ \ - /* Ether subdenominations */ \ - K(SubWei, "wei", 0) \ - K(SubSzabo, "szabo", 0) \ - K(SubFinney, "finney", 0) \ - K(SubEther, "ether", 0) \ + /* Ether subdenominations */ \ + K(SubWei, "wei", 0) \ + K(SubSzabo, "szabo", 0) \ + K(SubFinney, "finney", 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 * the implementation in Types.cpp has to be synced to this here */\ K(Int, "int", 0) \ @@ -376,12 +383,13 @@ public: } 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 isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; } 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 // (.e., "<" for the token LT) or NULL if the token doesn't diff --git a/Types.cpp b/Types.cpp index 22d612cd9..2105d6299 100644 --- a/Types.cpp +++ b/Types.cpp @@ -195,7 +195,8 @@ TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const return TypePointer(); // for non-hash integers, we allow +, -, ++ and -- 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(); else return TypePointer(); @@ -251,6 +252,7 @@ IntegerConstantType::IntegerConstantType(Literal const& _literal) switch (_literal.getSubDenomination()) { case Literal::SubDenomination::Wei: + case Literal::SubDenomination::Second: case Literal::SubDenomination::None: break; case Literal::SubDenomination::Szabo: @@ -262,6 +264,21 @@ IntegerConstantType::IntegerConstantType(Literal const& _literal) case Literal::SubDenomination::Ether: m_value *= bigint("1000000000000000000"); 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; } } From 2668214f1a0dfd0fbd915f970d8f3011910bd450 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 4 Mar 2015 19:55:52 +0100 Subject: [PATCH 5/5] Params & JSON file. --- Types.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Types.cpp b/Types.cpp index 2105d6299..865a32c3a 100644 --- a/Types.cpp +++ b/Types.cpp @@ -308,6 +308,8 @@ TypePointer IntegerConstantType::unaryOperatorResult(Token::Value _operator) con case Token::Sub: value = -m_value; break; + case Token::After: + return shared_from_this(); default: return TypePointer(); }