From bf3a76f5af38c5d62d52600e2b57e51247adb0b8 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 16 Oct 2014 17:56:10 +0200 Subject: [PATCH 1/6] Improved exceptions and reporting exceptions for command-line compiler. --- libdevcore/Exceptions.h | 3 + libethcore/Exceptions.cpp | 2 - libsolidity/AST.cpp | 37 ++++++------ libsolidity/Exceptions.cpp | 47 +++++++++++++++ libsolidity/Exceptions.h | 43 ++++++++++++- libsolidity/NameAndTypeResolver.cpp | 9 +-- libsolidity/Parser.cpp | 11 +--- libsolidity/Types.cpp | 2 +- solc/main.cpp | 93 +++++++++++++++++++++-------- 9 files changed, 183 insertions(+), 64 deletions(-) create mode 100644 libsolidity/Exceptions.cpp diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 1a54814c6..0be1cf30e 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -28,6 +28,9 @@ #include "CommonData.h" #include "FixedHash.h" +// for use in what() implementations +#define ETH_RETURN_STRING(S) static std::string s_what; s_what = S; return s_what.c_str(); + namespace dev { // base class for all exceptions diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp index c6f35763e..f9054ec5d 100644 --- a/libethcore/Exceptions.cpp +++ b/libethcore/Exceptions.cpp @@ -26,8 +26,6 @@ using namespace std; using namespace dev; using namespace dev::eth; -#define ETH_RETURN_STRING(S) static string s_what; s_what = S; return s_what.c_str(); - const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); } const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); } const char* InvalidTransactionsHash::what() const noexcept { ETH_RETURN_STRING("Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref())); } diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 15da9e0d8..0671ecd7a 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -252,8 +252,8 @@ void Statement::expectType(Expression& _expression, const Type& _expectedType) { _expression.checkTypeRequirements(); if (!_expression.getType()->isImplicitlyConvertibleTo(_expectedType)) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Type not implicitly convertible " - "to expected type.")); + BOOST_THROW_EXCEPTION(TypeError(_expression.getLocation(), + "Type not implicitly convertible to expected type.")); //@todo provide more information to the exception } @@ -289,9 +289,9 @@ void Return::checkTypeRequirements() { BOOST_ASSERT(m_returnParameters != nullptr); if (m_returnParameters->getParameters().size() != 1) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Different number of arguments in " - "return statement than in returns " - "declaration.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Different number of arguments in " + "return statement than in returns " + "declaration.")); // this could later be changed such that the paramaters type is an anonymous struct type, // but for now, we only allow one return parameter expectType(*m_expression, *m_returnParameters->getParameters().front()->getType()); @@ -327,7 +327,7 @@ void Assignment::checkTypeRequirements() { // complex assignment if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator))) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Operator not compatible with type.")); } } @@ -337,7 +337,7 @@ void UnaryOperation::checkTypeRequirements() m_subExpression->checkTypeRequirements(); m_type = m_subExpression->getType(); if (m_type->acceptsUnaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Unary operator not compatible with type.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Unary operator not compatible with type.")); } void BinaryOperation::checkTypeRequirements() @@ -349,7 +349,7 @@ void BinaryOperation::checkTypeRequirements() else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType())) m_commonType = m_right->getType(); else - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("No common type found in binary operation.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "No common type found in binary operation.")); if (Token::isCompareOp(m_operator)) m_type = std::make_shared(); else @@ -357,7 +357,7 @@ void BinaryOperation::checkTypeRequirements() BOOST_ASSERT(Token::isBinaryOp(m_operator)); m_type = m_commonType; if (!m_commonType->acceptsBinaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Operator not compatible with type.")); } } @@ -375,11 +375,10 @@ void FunctionCall::checkTypeRequirements() //@todo for structs, we have to check the number of arguments to be equal to the // number of non-mapping members if (m_arguments.size() != 1) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("More than one argument for " - "explicit type conersion.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "More than one argument for " + "explicit type conersion.")); if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type->getActualType())) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Explicit type conversion not " - "allowed.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Explicit type conversion not allowed.")); m_type = type->getActualType(); } else if (category == Type::Category::FUNCTION) @@ -392,12 +391,10 @@ void FunctionCall::checkTypeRequirements() FunctionDefinition const& fun = function->getFunction(); std::vector> const& parameters = fun.getParameters(); if (parameters.size() != m_arguments.size()) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Wrong argument count for " - "function call.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Wrong argument count for function call.")); for (size_t i = 0; i < m_arguments.size(); ++i) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType())) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Invalid type for argument in " - "function call.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Invalid type for argument in function call.")); // @todo actually the return type should be an anonymous struct, // but we change it to the type of the first return value until we have structs if (fun.getReturnParameterList()->getParameters().empty()) @@ -407,7 +404,7 @@ void FunctionCall::checkTypeRequirements() } else { - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Type does not support invocation.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Type does not support invocation.")); } } @@ -438,8 +435,8 @@ void Identifier::checkTypeRequirements() if (variable != nullptr) { if (!variable->getType()) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Variable referenced before type " - "could be determined.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Variable referenced before type " + "could be determined.")); m_type = variable->getType(); return; } diff --git a/libsolidity/Exceptions.cpp b/libsolidity/Exceptions.cpp new file mode 100644 index 000000000..53380d778 --- /dev/null +++ b/libsolidity/Exceptions.cpp @@ -0,0 +1,47 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @author Christian + * @date 2014 + * Solidity exception hierarchy. + */ + +#include + + +namespace dev +{ +namespace solidity +{ + +const char* ParserError::what() const noexcept +{ + ETH_RETURN_STRING("Parser error: " + m_description); +} + +const char* DeclarationError::what() const noexcept +{ + ETH_RETURN_STRING("Declaration error: " + m_description); +} + +const char* TypeError::what() const noexcept +{ + ETH_RETURN_STRING("Type error: " + m_description); +} + +} +} diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index c600ebf12..075af2b93 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -22,16 +22,53 @@ #pragma once +#include #include +#include namespace dev { namespace solidity { -struct ParserError: virtual Exception {}; -struct TypeError: virtual Exception {}; -struct DeclarationError: virtual Exception {}; +class ParserError: public virtual Exception +{ +public: + ParserError(int _position, std::string const& _description): + m_position(_position), m_description(_description) {} + virtual const char* what() const noexcept; + int getPosition() const { return m_position; } + +private: + int m_position; + std::string m_description; +}; + +class TypeError: public virtual Exception +{ +public: + TypeError(Location const& _location, std::string const& _description): + m_location(_location), m_description(_description) {} + virtual const char* what() const noexcept; + Location const& getLocation() const { return m_location; } + +private: + Location m_location; + std::string m_description; +}; + +class DeclarationError: public virtual Exception +{ +public: + DeclarationError(Location const& _location, std::string const& _description): + m_location(_location), m_description(_description) {} + virtual const char* what() const noexcept; + Location const& getLocation() const { return m_location; } + +private: + Location m_location; + std::string m_description; +}; } } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 707b6ce14..8fe452812 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -137,7 +137,8 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio { BOOST_ASSERT(m_currentScope != nullptr); if (!m_currentScope->registerDeclaration(_declaration)) - BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Identifier already declared.")); + BOOST_THROW_EXCEPTION(DeclarationError(_declaration.getLocation(), "Identifier already declared.")); + //@todo the exception should also contain the location of the first declaration if (_opensScope) enterNewSubScope(_declaration); } @@ -175,11 +176,11 @@ bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_typeName.getName()); if (declaration == nullptr) - BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Undeclared identifier.")); + BOOST_THROW_EXCEPTION(DeclarationError(_typeName.getLocation(), "Undeclared identifier.")); StructDefinition* referencedStruct = dynamic_cast(declaration); //@todo later, contracts are also valid types if (referencedStruct == nullptr) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Identifier does not name a type name.")); + BOOST_THROW_EXCEPTION(TypeError(_typeName.getLocation(), "Identifier does not name a type name.")); _typeName.setReferencedStruct(*referencedStruct); return false; } @@ -188,7 +189,7 @@ bool ReferencesResolver::visit(Identifier& _identifier) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName()); if (declaration == nullptr) - BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Undeclared identifier.")); + BOOST_THROW_EXCEPTION(DeclarationError(_identifier.getLocation(), "Undeclared identifier.")); _identifier.setReferencedDeclaration(*declaration); return false; } diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 408aa7bd6..3887ac8f2 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -536,16 +536,7 @@ ASTPointer Parser::getLiteralAndAdvance() void Parser::throwExpectationError(std::string const& _description) { - //@todo put some of this stuff into ParserError - int line, column; - std::tie(line, column) = m_scanner->translatePositionToLineColumn(getPosition()); - std::stringstream buf; - buf << "Solidity parser error: " << _description - << " at line " << (line + 1) - << ", column " << (column + 1) << "\n" - << m_scanner->getLineAtPosition(getPosition()) << "\n" - << std::string(column, ' ') << "^"; - BOOST_THROW_EXCEPTION(ParserError() << errinfo_comment(buf.str())); + BOOST_THROW_EXCEPTION(ParserError(getPosition(), _description)); } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 7634951a1..d5ae0c3e5 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -88,9 +88,9 @@ std::shared_ptr IntegerType::smallestTypeForLiteral(std::string con IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): m_bits(_bits), m_modifier(_modifier) { - BOOST_ASSERT(_bits > 0 && _bits <= 256 && _bits % 8 == 0); if (isAddress()) _bits = 160; + BOOST_ASSERT(_bits > 0 && _bits <= 256 && _bits % 8 == 0); } bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const diff --git a/solc/main.cpp b/solc/main.cpp index e155b0fe6..91cabfb33 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -9,21 +9,10 @@ #include #include #include +#include -namespace dev -{ -namespace solidity -{ - -ASTPointer parseAST(std::string const& _source) -{ - ASTPointer scanner = std::make_shared(CharStream(_source)); - Parser parser; - return parser.parse(scanner); -} - -} -} // end namespaces +using namespace dev; +using namespace solidity; void help() { @@ -44,6 +33,33 @@ void version() exit(0); } +void printSourcePart(std::ostream& _stream, Location const& _location, Scanner const& _scanner) +{ + int startLine; + int startColumn; + std::tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start); + _stream << " starting at line " << (startLine + 1) << ", column " << (startColumn + 1) << "\n"; + int endLine; + int endColumn; + std::tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); + if (startLine == endLine) + { + _stream << _scanner.getLineAtPosition(_location.start) << "\n" + << std::string(startColumn, ' ') << "^"; + if (endColumn > startColumn + 2) + _stream << std::string(endColumn - startColumn - 2, '-'); + if (endColumn > startColumn + 1) + _stream << "^"; + _stream << "\n"; + } + else + { + _stream << _scanner.getLineAtPosition(_location.start) << "\n" + << std::string(startColumn, ' ') << "^\n" + << "Spanning multiple lines.\n"; + } +} + int main(int argc, char** argv) { std::string infile; @@ -57,28 +73,57 @@ int main(int argc, char** argv) else infile = argv[i]; } - std::string src; + std::string sourceCode; if (infile.empty()) { std::string s; while (!std::cin.eof()) { getline(std::cin, s); - src.append(s); + sourceCode.append(s); } } else + sourceCode = asString(dev::contents(infile)); + + ASTPointer ast; + std::shared_ptr scanner = std::make_shared(CharStream(sourceCode)); + Parser parser; + try + { + ast = parser.parse(scanner); + } + catch (ParserError const& exc) { - src = dev::asString(dev::contents(infile)); + int line; + int column; + std::tie(line, column) = scanner->translatePositionToLineColumn(exc.getPosition()); + std::cerr << exc.what() << " at line " << (line + 1) << ", column " << (column + 1) << std::endl; + std::cerr << scanner->getLineAtPosition(exc.getPosition()) << std::endl; + std::cerr << std::string(column, ' ') << "^" << std::endl; + return -1; } - std::cout << "Parsing..." << std::endl; - // @todo catch exception - dev::solidity::ASTPointer ast = dev::solidity::parseAST(src); + + dev::solidity::NameAndTypeResolver resolver; + try + { + resolver.resolveNamesAndTypes(*ast.get()); + } + catch (DeclarationError const& exc) + { + std::cerr << exc.what() << std::endl; + printSourcePart(std::cerr, exc.getLocation(), *scanner); + return -1; + } + catch (TypeError const& exc) + { + std::cerr << exc.what() << std::endl; + printSourcePart(std::cerr, exc.getLocation(), *scanner); + return -1; + } + std::cout << "Syntax tree for the contract:" << std::endl; - dev::solidity::ASTPrinter printer(ast, src); + dev::solidity::ASTPrinter printer(ast, sourceCode); printer.print(std::cout); - std::cout << "Resolving identifiers..." << std::endl; - dev::solidity::NameAndTypeResolver resolver; - resolver.resolveNamesAndTypes(*ast.get()); return 0; } From 8bb71c4ebf3fcccd27ea52dac0ca7e4e5ada9dcf Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 23 Oct 2014 19:22:30 +0200 Subject: [PATCH 2/6] Use boost errinfo. --- libdevcore/Exceptions.h | 3 - libethcore/Exceptions.cpp | 2 + libsolidity/AST.cpp | 34 ++++--- libsolidity/AST.h | 9 +- libsolidity/Exceptions.h | 42 +------- libsolidity/NameAndTypeResolver.cpp | 12 ++- libsolidity/Parser.cpp | 20 ++-- libsolidity/Parser.h | 5 +- libsolidity/SourceReferenceFormatter.cpp | 96 +++++++++++++++++++ ...eptions.cpp => SourceReferenceFormatter.h} | 29 +++--- solc/main.cpp | 47 ++------- 11 files changed, 173 insertions(+), 126 deletions(-) create mode 100644 libsolidity/SourceReferenceFormatter.cpp rename libsolidity/{Exceptions.cpp => SourceReferenceFormatter.h} (55%) diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 0be1cf30e..1a54814c6 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -28,9 +28,6 @@ #include "CommonData.h" #include "FixedHash.h" -// for use in what() implementations -#define ETH_RETURN_STRING(S) static std::string s_what; s_what = S; return s_what.c_str(); - namespace dev { // base class for all exceptions diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp index f9054ec5d..c6f35763e 100644 --- a/libethcore/Exceptions.cpp +++ b/libethcore/Exceptions.cpp @@ -26,6 +26,8 @@ using namespace std; using namespace dev; using namespace dev::eth; +#define ETH_RETURN_STRING(S) static string s_what; s_what = S; return s_what.c_str(); + const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); } const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); } const char* InvalidTransactionsHash::what() const noexcept { ETH_RETURN_STRING("Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref())); } diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 0671ecd7a..50c53bf37 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -248,12 +248,17 @@ void Literal::accept(ASTVisitor& _visitor) _visitor.endVisit(*this); } +TypeError ASTNode::createTypeError(std::string const& _description) +{ + return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description); +} + void Statement::expectType(Expression& _expression, const Type& _expectedType) { _expression.checkTypeRequirements(); if (!_expression.getType()->isImplicitlyConvertibleTo(_expectedType)) - BOOST_THROW_EXCEPTION(TypeError(_expression.getLocation(), - "Type not implicitly convertible to expected type.")); + BOOST_THROW_EXCEPTION(TypeError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Type not implicitly convertible to expected type.")); //@todo provide more information to the exception } @@ -289,9 +294,8 @@ void Return::checkTypeRequirements() { BOOST_ASSERT(m_returnParameters != nullptr); if (m_returnParameters->getParameters().size() != 1) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Different number of arguments in " - "return statement than in returns " - "declaration.")); + BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement " + "than in returns declaration.")); // this could later be changed such that the paramaters type is an anonymous struct type, // but for now, we only allow one return parameter expectType(*m_expression, *m_returnParameters->getParameters().front()->getType()); @@ -327,7 +331,7 @@ void Assignment::checkTypeRequirements() { // complex assignment if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator))) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); } } @@ -337,7 +341,7 @@ void UnaryOperation::checkTypeRequirements() m_subExpression->checkTypeRequirements(); m_type = m_subExpression->getType(); if (m_type->acceptsUnaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Unary operator not compatible with type.")); + BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type.")); } void BinaryOperation::checkTypeRequirements() @@ -349,7 +353,7 @@ void BinaryOperation::checkTypeRequirements() else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType())) m_commonType = m_right->getType(); else - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "No common type found in binary operation.")); + BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation.")); if (Token::isCompareOp(m_operator)) m_type = std::make_shared(); else @@ -357,7 +361,7 @@ void BinaryOperation::checkTypeRequirements() BOOST_ASSERT(Token::isBinaryOp(m_operator)); m_type = m_commonType; if (!m_commonType->acceptsBinaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); } } @@ -375,10 +379,10 @@ void FunctionCall::checkTypeRequirements() //@todo for structs, we have to check the number of arguments to be equal to the // number of non-mapping members if (m_arguments.size() != 1) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "More than one argument for " + BOOST_THROW_EXCEPTION(createTypeError("More than one argument for " "explicit type conersion.")); if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type->getActualType())) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Explicit type conversion not allowed.")); + BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed.")); m_type = type->getActualType(); } else if (category == Type::Category::FUNCTION) @@ -391,10 +395,10 @@ void FunctionCall::checkTypeRequirements() FunctionDefinition const& fun = function->getFunction(); std::vector> const& parameters = fun.getParameters(); if (parameters.size() != m_arguments.size()) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Wrong argument count for function call.")); + BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); for (size_t i = 0; i < m_arguments.size(); ++i) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType())) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Invalid type for argument in function call.")); + BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); // @todo actually the return type should be an anonymous struct, // but we change it to the type of the first return value until we have structs if (fun.getReturnParameterList()->getParameters().empty()) @@ -404,7 +408,7 @@ void FunctionCall::checkTypeRequirements() } else { - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Type does not support invocation.")); + BOOST_THROW_EXCEPTION(createTypeError("Type does not support invocation.")); } } @@ -435,7 +439,7 @@ void Identifier::checkTypeRequirements() if (variable != nullptr) { if (!variable->getType()) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Variable referenced before type " + BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type " "could be determined.")); m_type = variable->getType(); return; diff --git a/libsolidity/AST.h b/libsolidity/AST.h index d5e1e0662..5679ed831 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -22,16 +22,16 @@ #pragma once -#include #include #include #include - +#include #include #include #include #include +#include namespace dev { @@ -57,6 +57,11 @@ public: Location const& getLocation() const { return m_location; } +protected: + /// Creates a @ref TypeError exception and decorates it with the current location and + /// the given description + TypeError createTypeError(std::string const& _description); + private: Location m_location; }; diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index 075af2b93..330c37788 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -31,44 +31,12 @@ namespace dev namespace solidity { -class ParserError: public virtual Exception -{ -public: - ParserError(int _position, std::string const& _description): - m_position(_position), m_description(_description) {} - virtual const char* what() const noexcept; - int getPosition() const { return m_position; } - -private: - int m_position; - std::string m_description; -}; - -class TypeError: public virtual Exception -{ -public: - TypeError(Location const& _location, std::string const& _description): - m_location(_location), m_description(_description) {} - virtual const char* what() const noexcept; - Location const& getLocation() const { return m_location; } - -private: - Location m_location; - std::string m_description; -}; - -class DeclarationError: public virtual Exception -{ -public: - DeclarationError(Location const& _location, std::string const& _description): - m_location(_location), m_description(_description) {} - virtual const char* what() const noexcept; - Location const& getLocation() const { return m_location; } +struct ParserError: public virtual Exception {}; +struct TypeError: public virtual Exception {}; +struct DeclarationError: public virtual Exception {}; -private: - Location m_location; - std::string m_description; -}; +typedef boost::error_info errinfo_sourcePosition; +typedef boost::error_info errinfo_sourceLocation; } } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 8fe452812..a56502727 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -137,7 +137,8 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio { BOOST_ASSERT(m_currentScope != nullptr); if (!m_currentScope->registerDeclaration(_declaration)) - BOOST_THROW_EXCEPTION(DeclarationError(_declaration.getLocation(), "Identifier already declared.")); + BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) + << errinfo_comment("Identifier already declared.")); //@todo the exception should also contain the location of the first declaration if (_opensScope) enterNewSubScope(_declaration); @@ -176,11 +177,13 @@ bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_typeName.getName()); if (declaration == nullptr) - BOOST_THROW_EXCEPTION(DeclarationError(_typeName.getLocation(), "Undeclared identifier.")); + BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_typeName.getLocation()) + << errinfo_comment("Undeclared identifier.")); StructDefinition* referencedStruct = dynamic_cast(declaration); //@todo later, contracts are also valid types if (referencedStruct == nullptr) - BOOST_THROW_EXCEPTION(TypeError(_typeName.getLocation(), "Identifier does not name a type name.")); + BOOST_THROW_EXCEPTION(TypeError() << errinfo_sourceLocation(_typeName.getLocation()) + << errinfo_comment("Identifier does not name a type name.")); _typeName.setReferencedStruct(*referencedStruct); return false; } @@ -189,7 +192,8 @@ bool ReferencesResolver::visit(Identifier& _identifier) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName()); if (declaration == nullptr) - BOOST_THROW_EXCEPTION(DeclarationError(_identifier.getLocation(), "Undeclared identifier.")); + BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_identifier.getLocation()) + << errinfo_comment("Undeclared identifier.")); _identifier.setReferencedDeclaration(*declaration); return false; } diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 3887ac8f2..1ea413ee9 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -106,7 +106,7 @@ ASTPointer Parser::parseContractDefinition() expectToken(Token::SEMICOLON); } else - throwExpectationError("Function, variable or struct declaration expected."); + BOOST_THROW_EXCEPTION(createParserError("Function, variable or struct declaration expected.")); } nodeFactory.markEndPosition(); expectToken(Token::RBRACE); @@ -184,7 +184,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) else if (token == Token::VAR) { if (!_allowVar) - throwExpectationError("Expected explicit type name."); + BOOST_THROW_EXCEPTION(createParserError("Expected explicit type name.")); m_scanner->next(); } else if (token == Token::MAPPING) @@ -198,7 +198,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) type = nodeFactory.createNode(expectIdentifierToken()); } else - throwExpectationError("Expected type name"); + BOOST_THROW_EXCEPTION(createParserError("Expected type name")); return type; } @@ -208,7 +208,7 @@ ASTPointer Parser::parseMapping() expectToken(Token::MAPPING); expectToken(Token::LPAREN); if (!Token::isElementaryTypeName(m_scanner->getCurrentToken())) - throwExpectationError("Expected elementary type name for mapping key type"); + BOOST_THROW_EXCEPTION(createParserError("Expected elementary type name for mapping key type")); ASTPointer keyType; keyType = ASTNodeFactory(*this).createNode(m_scanner->getCurrentToken()); m_scanner->next(); @@ -481,7 +481,7 @@ ASTPointer Parser::parsePrimaryExpression() } else { - throwExpectationError("Expected primary expression."); + BOOST_THROW_EXCEPTION(createParserError("Expected primary expression.")); return ASTPointer(); // this is not reached } break; @@ -507,7 +507,7 @@ std::vector> Parser::parseFunctionCallArguments() void Parser::expectToken(Token::Value _value) { if (m_scanner->getCurrentToken() != _value) - throwExpectationError(std::string("Expected token ") + std::string(Token::getName(_value))); + BOOST_THROW_EXCEPTION(createParserError(std::string("Expected token ") + std::string(Token::getName(_value)))); m_scanner->next(); } @@ -515,7 +515,7 @@ Token::Value Parser::expectAssignmentOperator() { Token::Value op = m_scanner->getCurrentToken(); if (!Token::isAssignmentOp(op)) - throwExpectationError(std::string("Expected assignment operator")); + BOOST_THROW_EXCEPTION(createParserError("Expected assignment operator")); m_scanner->next(); return op; } @@ -523,7 +523,7 @@ Token::Value Parser::expectAssignmentOperator() ASTPointer Parser::expectIdentifierToken() { if (m_scanner->getCurrentToken() != Token::IDENTIFIER) - throwExpectationError("Expected identifier"); + BOOST_THROW_EXCEPTION(createParserError("Expected identifier")); return getLiteralAndAdvance(); } @@ -534,9 +534,9 @@ ASTPointer Parser::getLiteralAndAdvance() return identifier; } -void Parser::throwExpectationError(std::string const& _description) +ParserError Parser::createParserError(std::string const& _description) const { - BOOST_THROW_EXCEPTION(ParserError(getPosition(), _description)); + return ParserError() << errinfo_sourcePosition(getPosition()) << errinfo_comment(_description); } diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 7cc415136..14338dc28 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -73,9 +73,12 @@ private: Token::Value expectAssignmentOperator(); ASTPointer expectIdentifierToken(); ASTPointer getLiteralAndAdvance(); - void throwExpectationError(std::string const& _description); /// @} + /// Creates a @ref ParserError exception and annotates it with the current position and the + /// given @a _description. + ParserError createParserError(std::string const& _description) const; + std::shared_ptr m_scanner; }; diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/SourceReferenceFormatter.cpp new file mode 100644 index 000000000..6d2911165 --- /dev/null +++ b/libsolidity/SourceReferenceFormatter.cpp @@ -0,0 +1,96 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @author Christian + * @date 2014 + * Formatting functions for errors referencing positions and locations in the source. + */ + +#include +#include +#include + +namespace dev +{ +namespace solidity +{ + +void SourceReferenceFormatter::printSourceLocation(std::ostream& _stream, + Location const& _location, + Scanner const& _scanner) +{ + int startLine; + int startColumn; + std::tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start); + _stream << "starting at line " << (startLine + 1) << ", column " << (startColumn + 1) << "\n"; + int endLine; + int endColumn; + std::tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); + if (startLine == endLine) + { + _stream << _scanner.getLineAtPosition(_location.start) << "\n" + << std::string(startColumn, ' ') << "^"; + if (endColumn > startColumn + 2) + _stream << std::string(endColumn - startColumn - 2, '-'); + if (endColumn > startColumn + 1) + _stream << "^"; + _stream << "\n"; + } + else + _stream << _scanner.getLineAtPosition(_location.start) << "\n" + << std::string(startColumn, ' ') << "^\n" + << "Spanning multiple lines.\n"; +} + +void SourceReferenceFormatter::printSourcePosition(std::ostream& _stream, + int _position, + const Scanner& _scanner) +{ + int line; + int column; + std::tie(line, column) = _scanner.translatePositionToLineColumn(_position); + _stream << "at line " << (line + 1) << ", column " << (column + 1) << "\n" + << _scanner.getLineAtPosition(_position) << "\n" + << std::string(column, ' ') << "^" << std::endl; +} + +void SourceReferenceFormatter::printExceptionInformation(std::ostream& _stream, + Exception const& _exception, + std::string const& _name, + Scanner const& _scanner) +{ + std::cerr << _name; + std::string const* description = boost::get_error_info(_exception); + if (description != nullptr) + std::cerr << ": " << *description; + + int const* position = boost::get_error_info(_exception); + if (position != nullptr) + { + std::cerr << " "; + printSourcePosition(std::cerr, *position, _scanner); + } + Location const* location = boost::get_error_info(_exception); + if (location != nullptr) + { + std::cerr << " "; + printSourceLocation(_stream, *location, _scanner); + } +} + +} +} diff --git a/libsolidity/Exceptions.cpp b/libsolidity/SourceReferenceFormatter.h similarity index 55% rename from libsolidity/Exceptions.cpp rename to libsolidity/SourceReferenceFormatter.h index 53380d778..4736066fd 100644 --- a/libsolidity/Exceptions.cpp +++ b/libsolidity/SourceReferenceFormatter.h @@ -17,31 +17,32 @@ /** * @author Christian * @date 2014 - * Solidity exception hierarchy. + * Formatting functions for errors referencing positions and locations in the source. */ -#include +#pragma once +#include +#include namespace dev { -namespace solidity -{ -const char* ParserError::what() const noexcept -{ - ETH_RETURN_STRING("Parser error: " + m_description); -} +class Exception; // forward -const char* DeclarationError::what() const noexcept +namespace solidity { - ETH_RETURN_STRING("Declaration error: " + m_description); -} -const char* TypeError::what() const noexcept +class Scanner; // forward + +struct SourceReferenceFormatter { - ETH_RETURN_STRING("Type error: " + m_description); -} +public: + static void printSourceLocation(std::ostream& _stream, Location const& _location, Scanner const& _scanner); + static void printSourcePosition(std::ostream& _stream, int _position, Scanner const& _scanner); + static void printExceptionInformation(std::ostream& _stream, Exception const& _exception, + std::string const& _name, Scanner const& _scanner); +}; } } diff --git a/solc/main.cpp b/solc/main.cpp index 91cabfb33..ba0b6ccf7 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include using namespace dev; using namespace solidity; @@ -33,33 +34,6 @@ void version() exit(0); } -void printSourcePart(std::ostream& _stream, Location const& _location, Scanner const& _scanner) -{ - int startLine; - int startColumn; - std::tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start); - _stream << " starting at line " << (startLine + 1) << ", column " << (startColumn + 1) << "\n"; - int endLine; - int endColumn; - std::tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); - if (startLine == endLine) - { - _stream << _scanner.getLineAtPosition(_location.start) << "\n" - << std::string(startColumn, ' ') << "^"; - if (endColumn > startColumn + 2) - _stream << std::string(endColumn - startColumn - 2, '-'); - if (endColumn > startColumn + 1) - _stream << "^"; - _stream << "\n"; - } - else - { - _stream << _scanner.getLineAtPosition(_location.start) << "\n" - << std::string(startColumn, ' ') << "^\n" - << "Spanning multiple lines.\n"; - } -} - int main(int argc, char** argv) { std::string infile; @@ -93,14 +67,9 @@ int main(int argc, char** argv) { ast = parser.parse(scanner); } - catch (ParserError const& exc) + catch (ParserError const& exception) { - int line; - int column; - std::tie(line, column) = scanner->translatePositionToLineColumn(exc.getPosition()); - std::cerr << exc.what() << " at line " << (line + 1) << ", column " << (column + 1) << std::endl; - std::cerr << scanner->getLineAtPosition(exc.getPosition()) << std::endl; - std::cerr << std::string(column, ' ') << "^" << std::endl; + SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Parser error", *scanner); return -1; } @@ -109,16 +78,14 @@ int main(int argc, char** argv) { resolver.resolveNamesAndTypes(*ast.get()); } - catch (DeclarationError const& exc) + catch (DeclarationError const& exception) { - std::cerr << exc.what() << std::endl; - printSourcePart(std::cerr, exc.getLocation(), *scanner); + SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Declaration error", *scanner); return -1; } - catch (TypeError const& exc) + catch (TypeError const& exception) { - std::cerr << exc.what() << std::endl; - printSourcePart(std::cerr, exc.getLocation(), *scanner); + SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Type error", *scanner); return -1; } From 7bab242f5fd598a8e30fc1cef78917d615834c51 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 24 Oct 2014 12:42:44 +0200 Subject: [PATCH 3/6] Use createTypeError everywhere and stream out Location. --- libsolidity/AST.cpp | 5 +---- libsolidity/AST.h | 3 +-- libsolidity/BaseTypes.h | 7 +++++++ libsolidity/Exceptions.h | 6 +++--- libsolidity/NameAndTypeResolver.cpp | 3 +-- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 50c53bf37..357b9bd94 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -257,8 +257,7 @@ void Statement::expectType(Expression& _expression, const Type& _expectedType) { _expression.checkTypeRequirements(); if (!_expression.getType()->isImplicitlyConvertibleTo(_expectedType)) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_sourceLocation(_expression.getLocation()) - << errinfo_comment("Type not implicitly convertible to expected type.")); + BOOST_THROW_EXCEPTION(_expression.createTypeError("Type not implicitly convertible to expected type.")); //@todo provide more information to the exception } @@ -407,9 +406,7 @@ void FunctionCall::checkTypeRequirements() m_type = fun.getReturnParameterList()->getParameters().front()->getType(); } else - { BOOST_THROW_EXCEPTION(createTypeError("Type does not support invocation.")); - } } void MemberAccess::checkTypeRequirements() diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 5679ed831..e94137a84 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -57,8 +57,7 @@ public: Location const& getLocation() const { return m_location; } -protected: - /// Creates a @ref TypeError exception and decorates it with the current location and + /// Creates a @ref TypeError exception and decorates it with the location of the node and /// the given description TypeError createTypeError(std::string const& _description); diff --git a/libsolidity/BaseTypes.h b/libsolidity/BaseTypes.h index fdf3f7b53..cfc14c7e9 100644 --- a/libsolidity/BaseTypes.h +++ b/libsolidity/BaseTypes.h @@ -22,6 +22,7 @@ #pragma once +#include namespace dev { @@ -41,5 +42,11 @@ struct Location int end; }; +/// Stream output for Location (used e.g. in boost exceptions). +inline std::ostream& operator<<(std::ostream& _out, Location const& _location) +{ + return _out << "[" << _location.start << "," << _location.end << ")"; +} + } } diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index 330c37788..5a48c47dd 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -31,9 +31,9 @@ namespace dev namespace solidity { -struct ParserError: public virtual Exception {}; -struct TypeError: public virtual Exception {}; -struct DeclarationError: public virtual Exception {}; +struct ParserError: virtual Exception {}; +struct TypeError: virtual Exception {}; +struct DeclarationError: virtual Exception {}; typedef boost::error_info errinfo_sourcePosition; typedef boost::error_info errinfo_sourceLocation; diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index a56502727..c0467b036 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -182,8 +182,7 @@ bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) StructDefinition* referencedStruct = dynamic_cast(declaration); //@todo later, contracts are also valid types if (referencedStruct == nullptr) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_sourceLocation(_typeName.getLocation()) - << errinfo_comment("Identifier does not name a type name.")); + BOOST_THROW_EXCEPTION(_typeName.createTypeError("Identifier does not name a type name.")); _typeName.setReferencedStruct(*referencedStruct); return false; } From 19e7a08b0e042b53de65ddba1fb4b539bc9bc4e9 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 24 Oct 2014 16:43:11 +0200 Subject: [PATCH 4/6] Remove nullptr comparisons. --- libsolidity/AST.cpp | 16 ++++++++-------- libsolidity/AST.h | 2 +- libsolidity/ASTPrinter.cpp | 2 +- libsolidity/NameAndTypeResolver.cpp | 14 +++++++------- libsolidity/Scope.cpp | 2 +- libsolidity/SourceReferenceFormatter.cpp | 9 +++------ 6 files changed, 21 insertions(+), 24 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 357b9bd94..91b4a42b1 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -291,7 +291,7 @@ void Break::checkTypeRequirements() void Return::checkTypeRequirements() { - BOOST_ASSERT(m_returnParameters != nullptr); + BOOST_ASSERT(m_returnParameters); if (m_returnParameters->getParameters().size() != 1) BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement " "than in returns declaration.")); @@ -374,7 +374,7 @@ void FunctionCall::checkTypeRequirements() if (category == Type::Category::TYPE) { TypeType const* type = dynamic_cast(&expressionType); - BOOST_ASSERT(type != nullptr); + BOOST_ASSERT(type); //@todo for structs, we have to check the number of arguments to be equal to the // number of non-mapping members if (m_arguments.size() != 1) @@ -390,7 +390,7 @@ void FunctionCall::checkTypeRequirements() // and then ask if that is implicitly convertible to the struct represented by the // function parameters FunctionType const* function = dynamic_cast(&expressionType); - BOOST_ASSERT(function != nullptr); + BOOST_ASSERT(function); FunctionDefinition const& fun = function->getFunction(); std::vector> const& parameters = fun.getParameters(); if (parameters.size() != m_arguments.size()) @@ -423,7 +423,7 @@ void IndexAccess::checkTypeRequirements() void Identifier::checkTypeRequirements() { - BOOST_ASSERT(m_referencedDeclaration != nullptr); + BOOST_ASSERT(m_referencedDeclaration); //@todo these dynamic casts here are not really nice... // is i useful to have an AST visitor here? // or can this already be done in NameAndTypeResolver? @@ -433,7 +433,7 @@ void Identifier::checkTypeRequirements() // var y = x; // the type of x is not yet determined. VariableDeclaration* variable = dynamic_cast(m_referencedDeclaration); - if (variable != nullptr) + if (variable) { if (!variable->getType()) BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type " @@ -443,14 +443,14 @@ void Identifier::checkTypeRequirements() } //@todo can we unify these with TypeName::toType()? StructDefinition* structDef = dynamic_cast(m_referencedDeclaration); - if (structDef != nullptr) + if (structDef) { // note that we do not have a struct type here m_type = std::make_shared(std::make_shared(*structDef)); return; } FunctionDefinition* functionDef = dynamic_cast(m_referencedDeclaration); - if (functionDef != nullptr) + if (functionDef) { // a function reference is not a TypeType, because calling a TypeType converts to the type. // Calling a function (e.g. function(12), otherContract.function(34)) does not do a type @@ -459,7 +459,7 @@ void Identifier::checkTypeRequirements() return; } ContractDefinition* contractDef = dynamic_cast(m_referencedDeclaration); - if (contractDef != nullptr) + if (contractDef) { m_type = std::make_shared(std::make_shared(*contractDef)); return; diff --git a/libsolidity/AST.h b/libsolidity/AST.h index e94137a84..df146ab10 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -169,7 +169,7 @@ public: Declaration(_location, _name), m_typeName(_type) {} virtual void accept(ASTVisitor& _visitor) override; - bool isTypeGivenExplicitly() const { return m_typeName.get() != nullptr; } + bool isTypeGivenExplicitly() const { return bool(m_typeName); } TypeName* getTypeName() const { return m_typeName.get(); } //! Returns the declared or inferred type. Can be an empty pointer if no type was explicitly diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index c512bd3f9..6d782f274 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -243,7 +243,7 @@ bool ASTPrinter::visit(ElementaryTypeNameExpression& _node) bool ASTPrinter::visit(Literal& _node) { char const* tokenString = Token::toString(_node.getToken()); - if (tokenString == nullptr) + if (!tokenString) tokenString = "[no token]"; writeLine(std::string("Literal, token: ") + tokenString + " value: " + _node.getValue()); printSourcePart(_node); diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index c0467b036..e9d90dc88 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -129,13 +129,13 @@ void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node) void DeclarationRegistrationHelper::closeCurrentScope() { - BOOST_ASSERT(m_currentScope != nullptr); + BOOST_ASSERT(m_currentScope); m_currentScope = m_currentScope->getOuterScope(); } void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) { - BOOST_ASSERT(m_currentScope != nullptr); + BOOST_ASSERT(m_currentScope); if (!m_currentScope->registerDeclaration(_declaration)) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) << errinfo_comment("Identifier already declared.")); @@ -155,14 +155,14 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) { // endVisit because the internal type needs resolving if it is a user defined type // or mapping - if (_variable.getTypeName() != nullptr) + if (_variable.getTypeName()) _variable.setType(_variable.getTypeName()->toType()); // otherwise we have a "var"-declaration whose type is resolved by the first assignment } bool ReferencesResolver::visit(Return& _return) { - BOOST_ASSERT(m_returnParameters != nullptr); + BOOST_ASSERT(m_returnParameters); _return.setFunctionReturnParameters(*m_returnParameters); return true; } @@ -176,12 +176,12 @@ bool ReferencesResolver::visit(Mapping&) bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_typeName.getName()); - if (declaration == nullptr) + if (!declaration) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_typeName.getLocation()) << errinfo_comment("Undeclared identifier.")); StructDefinition* referencedStruct = dynamic_cast(declaration); //@todo later, contracts are also valid types - if (referencedStruct == nullptr) + if (!referencedStruct) BOOST_THROW_EXCEPTION(_typeName.createTypeError("Identifier does not name a type name.")); _typeName.setReferencedStruct(*referencedStruct); return false; @@ -190,7 +190,7 @@ bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) bool ReferencesResolver::visit(Identifier& _identifier) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName()); - if (declaration == nullptr) + if (!declaration) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_identifier.getLocation()) << errinfo_comment("Undeclared identifier.")); _identifier.setReferencedDeclaration(*declaration); diff --git a/libsolidity/Scope.cpp b/libsolidity/Scope.cpp index 28a54dd27..4fcd2f45e 100644 --- a/libsolidity/Scope.cpp +++ b/libsolidity/Scope.cpp @@ -41,7 +41,7 @@ Declaration* Scope::resolveName(ASTString const& _name, bool _recursive) const auto result = m_declarations.find(_name); if (result != m_declarations.end()) return result->second; - if (_recursive && m_outerScope != nullptr) + if (_recursive && m_outerScope) return m_outerScope->resolveName(_name, true); return nullptr; } diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/SourceReferenceFormatter.cpp index 6d2911165..665df32a4 100644 --- a/libsolidity/SourceReferenceFormatter.cpp +++ b/libsolidity/SourceReferenceFormatter.cpp @@ -74,18 +74,15 @@ void SourceReferenceFormatter::printExceptionInformation(std::ostream& _stream, Scanner const& _scanner) { std::cerr << _name; - std::string const* description = boost::get_error_info(_exception); - if (description != nullptr) + if (std::string const* description = boost::get_error_info(_exception)) std::cerr << ": " << *description; - int const* position = boost::get_error_info(_exception); - if (position != nullptr) + if (int const* position = boost::get_error_info(_exception)) { std::cerr << " "; printSourcePosition(std::cerr, *position, _scanner); } - Location const* location = boost::get_error_info(_exception); - if (location != nullptr) + if (Location const* location = boost::get_error_info(_exception)) { std::cerr << " "; printSourceLocation(_stream, *location, _scanner); From c5698b7341e426238487095aa871baff8222d286 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 24 Oct 2014 16:47:10 +0200 Subject: [PATCH 5/6] Use endl instead of "\n". --- libsolidity/ASTPrinter.cpp | 4 ++-- libsolidity/SourceReferenceFormatter.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index 6d782f274..e79146d05 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -406,7 +406,7 @@ void ASTPrinter::printSourcePart(ASTNode const& _node) { Location const& location(_node.getLocation()); *m_ostream << getIndentation() << " Source: |" - << m_source.substr(location.start, location.end - location.start) << "|\n"; + << m_source.substr(location.start, location.end - location.start) << "|" << std::endl; } } @@ -417,7 +417,7 @@ std::string ASTPrinter::getIndentation() const void ASTPrinter::writeLine(std::string const& _line) { - *m_ostream << getIndentation() << _line << '\n'; + *m_ostream << getIndentation() << _line << std::endl; } } diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/SourceReferenceFormatter.cpp index 665df32a4..bc9e8f262 100644 --- a/libsolidity/SourceReferenceFormatter.cpp +++ b/libsolidity/SourceReferenceFormatter.cpp @@ -42,16 +42,16 @@ void SourceReferenceFormatter::printSourceLocation(std::ostream& _stream, std::tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); if (startLine == endLine) { - _stream << _scanner.getLineAtPosition(_location.start) << "\n" + _stream << _scanner.getLineAtPosition(_location.start) << std::endl << std::string(startColumn, ' ') << "^"; if (endColumn > startColumn + 2) _stream << std::string(endColumn - startColumn - 2, '-'); if (endColumn > startColumn + 1) _stream << "^"; - _stream << "\n"; + _stream << std::endl; } else - _stream << _scanner.getLineAtPosition(_location.start) << "\n" + _stream << _scanner.getLineAtPosition(_location.start) << std::endl << std::string(startColumn, ' ') << "^\n" << "Spanning multiple lines.\n"; } @@ -63,8 +63,8 @@ void SourceReferenceFormatter::printSourcePosition(std::ostream& _stream, int line; int column; std::tie(line, column) = _scanner.translatePositionToLineColumn(_position); - _stream << "at line " << (line + 1) << ", column " << (column + 1) << "\n" - << _scanner.getLineAtPosition(_position) << "\n" + _stream << "at line " << (line + 1) << ", column " << (column + 1) << std::endl + << _scanner.getLineAtPosition(_position) << std::endl << std::string(column, ' ') << "^" << std::endl; } From dfea1573130de8416462a9aa74b8d3dd9149d013 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 24 Oct 2014 19:08:31 +0200 Subject: [PATCH 6/6] Use the passed stream, not std::cerr. --- libsolidity/SourceReferenceFormatter.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/SourceReferenceFormatter.cpp index bc9e8f262..b270342c9 100644 --- a/libsolidity/SourceReferenceFormatter.cpp +++ b/libsolidity/SourceReferenceFormatter.cpp @@ -73,18 +73,18 @@ void SourceReferenceFormatter::printExceptionInformation(std::ostream& _stream, std::string const& _name, Scanner const& _scanner) { - std::cerr << _name; + _stream << _name; if (std::string const* description = boost::get_error_info(_exception)) - std::cerr << ": " << *description; + _stream << ": " << *description; if (int const* position = boost::get_error_info(_exception)) { - std::cerr << " "; - printSourcePosition(std::cerr, *position, _scanner); + _stream << " "; + printSourcePosition(_stream, *position, _scanner); } if (Location const* location = boost::get_error_info(_exception)) { - std::cerr << " "; + _stream << " "; printSourceLocation(_stream, *location, _scanner); } }