diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 4 | ||||
-rw-r--r-- | libsolidity/ast/AST.h | 8 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.cpp | 6 | ||||
-rw-r--r-- | libsolidity/ast/ASTPrinter.cpp | 2 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 17 | ||||
-rw-r--r-- | libsolidity/ast/Types.h | 1 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerUtils.cpp | 19 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.cpp | 19 | ||||
-rw-r--r-- | libsolidity/formal/Why3Translator.cpp | 10 | ||||
-rw-r--r-- | libsolidity/grammar.txt | 3 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 21 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.h | 1 |
12 files changed, 93 insertions, 18 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 46f4f7f6..f934b2c8 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -996,9 +996,9 @@ bool TypeChecker::visit(TupleExpression const& _tuple) fatalTypeError(components[i]->location(), "Invalid mobile type."); if (i == 0) - inlineArrayType = types[i]->mobileType(); + inlineArrayType = types[i]; else if (inlineArrayType) - inlineArrayType = Type::commonType(inlineArrayType, types[i]->mobileType()); + inlineArrayType = Type::commonType(inlineArrayType, types[i]); } } else diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 7ed4ddce..6c3f52bc 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -1005,18 +1005,22 @@ public: SourceLocation const& _location, ASTPointer<ASTString> const& _docString, ASTPointer<Expression> const& _condition, - ASTPointer<Statement> const& _body + ASTPointer<Statement> const& _body, + bool _isDoWhile ): - BreakableStatement(_location, _docString), m_condition(_condition), m_body(_body) {} + BreakableStatement(_location, _docString), m_condition(_condition), m_body(_body), + m_isDoWhile(_isDoWhile) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; Expression const& condition() const { return *m_condition; } Statement const& body() const { return *m_body; } + bool isDoWhile() const { return m_isDoWhile; } private: ASTPointer<Expression> m_condition; ASTPointer<Statement> m_body; + bool m_isDoWhile; }; /** diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index b573feda..3fce1180 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -264,7 +264,11 @@ bool ASTJsonConverter::visit(IfStatement const& _node) bool ASTJsonConverter::visit(WhileStatement const& _node) { - addJsonNode(_node, "WhileStatement", {}, true); + addJsonNode( + _node, + _node.isDoWhile() ? "DoWhileStatement" : "WhileStatement", + {}, + true); return true; } diff --git a/libsolidity/ast/ASTPrinter.cpp b/libsolidity/ast/ASTPrinter.cpp index a9de457a..27266968 100644 --- a/libsolidity/ast/ASTPrinter.cpp +++ b/libsolidity/ast/ASTPrinter.cpp @@ -208,7 +208,7 @@ bool ASTPrinter::visit(IfStatement const& _node) bool ASTPrinter::visit(WhileStatement const& _node) { - writeLine("WhileStatement"); + writeLine(_node.isDoWhile() ? "DoWhileStatement" : "WhileStatement"); printSourcePart(_node); return goDeeper(); } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 7fe97fa7..f0995393 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -200,10 +200,10 @@ TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b) { if (!_a || !_b) return TypePointer(); - else if (_b->isImplicitlyConvertibleTo(*_a)) - return _a; - else if (_a->isImplicitlyConvertibleTo(*_b)) - return _b; + else if (_b->isImplicitlyConvertibleTo(*_a->mobileType())) + return _a->mobileType(); + else if (_a->isImplicitlyConvertibleTo(*_b->mobileType())) + return _b->mobileType(); else return TypePointer(); } @@ -1561,7 +1561,7 @@ bool EnumType::operator==(Type const& _other) const unsigned EnumType::storageBytes() const { - size_t elements = m_enum.members().size(); + size_t elements = numberOfMembers(); if (elements <= 1) return 1; else @@ -1578,9 +1578,14 @@ string EnumType::canonicalName(bool) const return m_enum.annotation().canonicalName; } +size_t EnumType::numberOfMembers() const +{ + return m_enum.members().size(); +}; + bool EnumType::isExplicitlyConvertibleTo(Type const& _convertTo) const { - return _convertTo.category() == category() || _convertTo.category() == Category::Integer; + return _convertTo == *this || _convertTo.category() == Category::Integer; } unsigned EnumType::memberValue(ASTString const& _member) const diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 3f94d11a..082e16a6 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -738,6 +738,7 @@ public: EnumDefinition const& enumDefinition() const { return m_enum; } /// @returns the value that the string has in the Enum unsigned int memberValue(ASTString const& _member) const; + size_t numberOfMembers() const; private: EnumDefinition const& m_enum; diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index e064c1a6..dd133aea 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -315,6 +315,8 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp Type::Category stackTypeCategory = _typeOnStack.category(); Type::Category targetTypeCategory = _targetType.category(); + bool enumOverflowCheckPending = (targetTypeCategory == Type::Category::Enum); + switch (stackTypeCategory) { case Type::Category::FixedBytes: @@ -348,7 +350,15 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp } break; case Type::Category::Enum: - solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Enum, ""); + solAssert(_targetType == _typeOnStack || targetTypeCategory == Type::Category::Integer, ""); + if (enumOverflowCheckPending) + { + EnumType const& enumType = dynamic_cast<decltype(enumType)>(_targetType); + solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error."); + m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT; + m_context.appendConditionalJumpTo(m_context.errorTag()); + enumOverflowCheckPending = false; + } break; case Type::Category::FixedPoint: solAssert(false, "Not yet implemented - FixedPointType."); @@ -372,6 +382,11 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp solAssert(_typeOnStack.mobileType(), ""); // just clean convertType(_typeOnStack, *_typeOnStack.mobileType(), true); + EnumType const& enumType = dynamic_cast<decltype(enumType)>(_targetType); + solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error."); + m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT; + m_context.appendConditionalJumpTo(m_context.errorTag()); + enumOverflowCheckPending = false; } else if (targetTypeCategory == Type::Category::FixedPoint) { @@ -656,6 +671,8 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp solAssert(_typeOnStack == _targetType, "Invalid type conversion requested."); break; } + + solAssert(!enumOverflowCheckPending, "enum overflow checking missing."); } void CompilerUtils::pushZeroValue(Type const& _type) diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index ebb84784..1404963f 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -611,12 +611,25 @@ bool ContractCompiler::visit(WhileStatement const& _whileStatement) m_breakTags.push_back(loopEnd); m_context << loopStart; - compileExpression(_whileStatement.condition()); - m_context << Instruction::ISZERO; - m_context.appendConditionalJumpTo(loopEnd); + + // While loops have the condition prepended + if (!_whileStatement.isDoWhile()) + { + compileExpression(_whileStatement.condition()); + m_context << Instruction::ISZERO; + m_context.appendConditionalJumpTo(loopEnd); + } _whileStatement.body().accept(*this); + // Do-while loops have the condition appended + if (_whileStatement.isDoWhile()) + { + compileExpression(_whileStatement.condition()); + m_context << Instruction::ISZERO; + m_context.appendConditionalJumpTo(loopEnd); + } + m_context.appendJumpTo(loopStart); m_context << loopEnd; diff --git a/libsolidity/formal/Why3Translator.cpp b/libsolidity/formal/Why3Translator.cpp index 813fa3ab..5934d593 100644 --- a/libsolidity/formal/Why3Translator.cpp +++ b/libsolidity/formal/Why3Translator.cpp @@ -410,6 +410,16 @@ bool Why3Translator::visit(WhileStatement const& _node) { addSourceFromDocStrings(_node.annotation()); + // Why3 does not appear to support do-while loops, + // so we will simulate them by performing a while + // loop with the body prepended once. + + if (_node.isDoWhile()) + { + visitIndentedUnlessBlock(_node.body()); + newLine(); + } + add("while "); _node.condition().accept(*this); newLine(); diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt index d84ee10c..3edb4eba 100644 --- a/libsolidity/grammar.txt +++ b/libsolidity/grammar.txt @@ -42,7 +42,7 @@ StorageLocation = 'memory' | 'storage' Block = '{' Statement* '}' Statement = IfStatement | WhileStatement | ForStatement | Block | - ( PlaceholderStatement | Continue | Break | Return | + ( DoWhileStatement | PlaceholderStatement | Continue | Break | Return | Throw | SimpleStatement ) ';' ExpressionStatement = Expression @@ -51,6 +51,7 @@ WhileStatement = 'while' '(' Expression ')' Statement PlaceholderStatement = '_' SimpleStatement = VariableDefinition | ExpressionStatement ForStatement = 'for' '(' (SimpleStatement)? ';' (Expression)? ';' (ExpressionStatement)? ')' Statement +DoWhileStatement = 'do' Statement 'while' '(' Expression ')' Continue = 'continue' Break = 'break' Return = 'return' Expression? diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 0e99d1e7..df3ed7b2 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -406,6 +406,8 @@ ASTPointer<EnumDefinition> Parser::parseEnumDefinition() if (m_scanner->currentToken() != Token::Identifier) fatalParserError(string("Expected Identifier after ','")); } + if (members.size() == 0) + parserError({"enum with no members is not allowed."}); nodeFactory.markEndPosition(); expectToken(Token::RBrace); @@ -722,6 +724,8 @@ ASTPointer<Statement> Parser::parseStatement() return parseIfStatement(docString); case Token::While: return parseWhileStatement(docString); + case Token::Do: + return parseDoWhileStatement(docString); case Token::For: return parseForStatement(docString); case Token::LBrace: @@ -816,9 +820,24 @@ ASTPointer<WhileStatement> Parser::parseWhileStatement(ASTPointer<ASTString> con expectToken(Token::RParen); ASTPointer<Statement> body = parseStatement(); nodeFactory.setEndPositionFromNode(body); - return nodeFactory.createNode<WhileStatement>(_docString, condition, body); + return nodeFactory.createNode<WhileStatement>(_docString, condition, body, false); } +ASTPointer<WhileStatement> Parser::parseDoWhileStatement(ASTPointer<ASTString> const& _docString) +{ + ASTNodeFactory nodeFactory(*this); + expectToken(Token::Do); + ASTPointer<Statement> body = parseStatement(); + expectToken(Token::While); + expectToken(Token::LParen); + ASTPointer<Expression> condition = parseExpression(); + expectToken(Token::RParen); + nodeFactory.markEndPosition(); + expectToken(Token::Semicolon); + return nodeFactory.createNode<WhileStatement>(_docString, condition, body, true); +} + + ASTPointer<ForStatement> Parser::parseForStatement(ASTPointer<ASTString> const& _docString) { ASTNodeFactory nodeFactory(*this); diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 9c30cf60..26f347cb 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -85,6 +85,7 @@ private: ASTPointer<InlineAssembly> parseInlineAssembly(ASTPointer<ASTString> const& _docString = {}); ASTPointer<IfStatement> parseIfStatement(ASTPointer<ASTString> const& _docString); ASTPointer<WhileStatement> parseWhileStatement(ASTPointer<ASTString> const& _docString); + ASTPointer<WhileStatement> parseDoWhileStatement(ASTPointer<ASTString> const& _docString); ASTPointer<ForStatement> parseForStatement(ASTPointer<ASTString> const& _docString); /// A "simple statement" can be a variable declaration statement or an expression statement. ASTPointer<Statement> parseSimpleStatement(ASTPointer<ASTString> const& _docString); |