aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian <c@ethdev.com>2014-10-15 20:45:51 +0800
committerChristian <c@ethdev.com>2014-10-16 00:41:29 +0800
commitdf142782bc3a1435f70d9f5f4c8e04ae8d7e1678 (patch)
tree363823cbff0362b1e47e8e22b8cb8c482308a49f
parent89b794f1dc15c8688526470b9d68b361dab82be3 (diff)
downloaddexon-solidity-df142782bc3a1435f70d9f5f4c8e04ae8d7e1678.tar.gz
dexon-solidity-df142782bc3a1435f70d9f5f4c8e04ae8d7e1678.tar.zst
dexon-solidity-df142782bc3a1435f70d9f5f4c8e04ae8d7e1678.zip
Added meaningful exception types.
-rw-r--r--AST.cpp36
-rw-r--r--Exceptions.h34
-rw-r--r--NameAndTypeResolver.cpp10
-rw-r--r--Parser.cpp26
4 files changed, 77 insertions, 29 deletions
diff --git a/AST.cpp b/AST.cpp
index 325ef50b..926f1c68 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -24,6 +24,7 @@
#include <libsolidity/AST.h>
#include <libsolidity/ASTVisitor.h>
+#include <libsolidity/Exceptions.h>
namespace dev {
namespace solidity {
@@ -245,7 +246,9 @@ void Literal::accept(ASTVisitor& _visitor)
void Statement::expectType(Expression& _expression, const Type& _expectedType)
{
if (!_expression.checkTypeRequirements()->isImplicitlyConvertibleTo(_expectedType))
- throw std::exception(); // @todo
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Type not implicitly convertible "
+ "to expected type."));
+ //@todo provide more information to the exception
}
ptr<Type> Block::checkTypeRequirements()
@@ -284,7 +287,9 @@ ptr<Type> Return::checkTypeRequirements()
{
BOOST_ASSERT(m_returnParameters != nullptr);
if (m_returnParameters->getParameters().size() != 1)
- throw std::exception(); // @todo
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("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
@@ -318,7 +323,7 @@ ptr<Type> Assignment::checkTypeRequirements()
if (m_assigmentOperator != Token::ASSIGN) {
// complex assignment
if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator)))
- throw std::exception();
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Operator not compatible with type."));
}
return m_type;
}
@@ -328,7 +333,7 @@ ptr<Type> UnaryOperation::checkTypeRequirements()
// INC, DEC, NOT, BIT_NOT, DELETE
m_type = m_subExpression->checkTypeRequirements();
if (m_type->acceptsUnaryOperator(m_operator))
- throw std::exception();
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Unary operator not compatible with type."));
return m_type;
}
@@ -342,7 +347,7 @@ ptr<Type> BinaryOperation::checkTypeRequirements()
else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType()))
m_commonType = m_right->getType();
else
- throw std::exception();
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("No common type found in binary operation."));
if (Token::IsCompareOp(m_operator)) {
m_type = std::make_shared<BoolType>();
@@ -350,7 +355,7 @@ ptr<Type> BinaryOperation::checkTypeRequirements()
BOOST_ASSERT(Token::IsBinaryOp(m_operator));
m_type = m_commonType;
if (!m_commonType->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_operator)))
- throw std::exception();
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Operator not compatible with type."));
}
return m_type;
}
@@ -369,9 +374,11 @@ ptr<Type> 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)
- throw std::exception();
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("More than one argument for "
+ "explicit type conersion."));
if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type->getActualType()))
- throw std::exception();
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Explicit type conversion not "
+ "allowed."));
m_type = type->getActualType();
} else if (category == Type::Category::FUNCTION) {
//@todo would be nice to create a struct type from the arguments
@@ -382,10 +389,12 @@ ptr<Type> FunctionCall::checkTypeRequirements()
FunctionDefinition const& fun = function->getFunction();
vecptr<VariableDeclaration> const& parameters = fun.getParameters();
if (parameters.size() != m_arguments.size())
- throw std::exception();
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("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()))
- throw std::exception();
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Invalid type for argument in "
+ "function call."));
}
// @todo actually the return type should be an anonymous struct,
@@ -395,7 +404,7 @@ ptr<Type> FunctionCall::checkTypeRequirements()
else
m_type = fun.getReturnParameterList()->getParameters().front()->getType();
} else {
- throw std::exception(); // type does not support invocation
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Type does not support invocation."));
}
return m_type;
}
@@ -428,7 +437,8 @@ ptr<Type> Identifier::checkTypeRequirements()
VariableDeclaration* variable = dynamic_cast<VariableDeclaration*>(m_referencedDeclaration);
if (variable != nullptr) {
if (variable->getType().get() == nullptr)
- throw std::exception(); // variable used before type could be determined
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Variable referenced before type "
+ "could be determined."));
m_type = variable->getType();
return m_type;
}
@@ -452,7 +462,7 @@ ptr<Type> Identifier::checkTypeRequirements()
m_type = std::make_shared<TypeType>(std::make_shared<ContractType>(*contractDef));
return m_type;
}
- throw std::exception(); // declaration reference of unknown/forbidden type
+ BOOST_ASSERT(false); // declaration reference of unknown/forbidden type
return m_type;
}
diff --git a/Exceptions.h b/Exceptions.h
new file mode 100644
index 00000000..5e0b1522
--- /dev/null
+++ b/Exceptions.h
@@ -0,0 +1,34 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Solidity exception hierarchy.
+ */
+
+#pragma once
+
+#include <libdevcore/Exceptions.h>
+
+namespace dev {
+namespace solidity {
+
+struct ParserError : virtual Exception {};
+struct TypeError : virtual Exception {};
+struct DeclarationError : virtual Exception {};
+
+} }
diff --git a/NameAndTypeResolver.cpp b/NameAndTypeResolver.cpp
index 33b550eb..8e769c47 100644
--- a/NameAndTypeResolver.cpp
+++ b/NameAndTypeResolver.cpp
@@ -23,6 +23,7 @@
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/AST.h>
+#include <libsolidity/Exceptions.h>
#include <boost/assert.hpp>
namespace dev {
@@ -115,7 +116,7 @@ void NameAndTypeResolver::resolveReferencesInFunction(ParameterList& _returnPara
virtual bool visit(Identifier& _identifier) override {
Declaration* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName());
if (declaration == nullptr)
- throw std::exception(); // @todo
+ BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Undeclared identifier."));
_identifier.setReferencedDeclaration(*declaration);
return false;
}
@@ -151,10 +152,11 @@ void NameAndTypeResolver::registerVariableDeclarationAndResolveType(VariableDecl
virtual bool visit(UserDefinedTypeName& _typeName) override {
Declaration* declaration = m_resolver.getNameFromCurrentScope(_typeName.getName());
if (declaration == nullptr)
- throw std::exception(); // @todo
+ BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Undeclared identifier."));
StructDefinition* referencedStruct = dynamic_cast<StructDefinition*>(declaration);
+ //@todo later, contracts are also valid types
if (referencedStruct == nullptr)
- throw std::exception(); // @todo we only allow structs as user defined types (later also contracts)
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Identifier does not name a type name."));
_typeName.setReferencedStruct(*referencedStruct);
return false;
}
@@ -176,7 +178,7 @@ void NameAndTypeResolver::registerVariableDeclarationAndResolveType(VariableDecl
void NameAndTypeResolver::registerDeclaration(Declaration& _declaration)
{
if (!m_currentScope->registerDeclaration(_declaration))
- throw std::exception(); // @todo
+ BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Identifier already declared."));
}
Declaration* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive)
diff --git a/Parser.cpp b/Parser.cpp
index ab72bf7f..b2815411 100644
--- a/Parser.cpp
+++ b/Parser.cpp
@@ -20,10 +20,11 @@
* Solidity parser.
*/
-#include "libdevcore/Log.h"
-#include "libsolidity/BaseTypes.h"
-#include "libsolidity/Parser.h"
-#include "libsolidity/Scanner.h"
+#include <libdevcore/Log.h>
+#include <libsolidity/BaseTypes.h>
+#include <libsolidity/Parser.h>
+#include <libsolidity/Scanner.h>
+#include <libsolidity/Exceptions.h>
namespace dev {
namespace solidity {
@@ -530,16 +531,17 @@ ptr<ASTString> Parser::getLiteralAndAdvance()
void Parser::throwExpectationError(const std::string& _description)
{
+ //@todo put some of this stuff into ParserError
int line, column;
std::tie(line, column) = m_scanner->translatePositionToLineColumn(getPosition());
- cwarn << "Solidity parser error: " << _description
- << "at line " << (line + 1)
- << ", column " << (column + 1);
- cwarn << m_scanner->getLineAtPosition(getPosition());
- cwarn << std::string(column, ' ') << "^";
-
- /// @todo make a proper exception hierarchy
- throw std::exception();
+ 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()));
}