Browse Source

Converted all asserts to exceptions.

cl-refactor
Christian 10 years ago
parent
commit
37216a246a
  1. 25
      libsolidity/AST.cpp
  2. 32
      libsolidity/AST.h
  3. 6
      libsolidity/Compiler.cpp
  4. 7
      libsolidity/CompilerContext.cpp
  5. 1
      libsolidity/Exceptions.h
  6. 58
      libsolidity/ExpressionCompiler.cpp
  7. 16
      libsolidity/NameAndTypeResolver.cpp
  8. 33
      libsolidity/Scanner.cpp
  9. 2
      libsolidity/Scanner.h
  10. 64
      libsolidity/Token.h
  11. 14
      libsolidity/Types.cpp
  12. 7
      libsolidity/Types.h
  13. 45
      solc/main.cpp

25
libsolidity/AST.cpp

@ -293,9 +293,10 @@ void Break::checkTypeRequirements()
void Return::checkTypeRequirements() void Return::checkTypeRequirements()
{ {
assert(m_returnParameters);
if (!m_expression) if (!m_expression)
return; return;
if (asserts(m_returnParameters))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Return parameters not assigned."));
if (m_returnParameters->getParameters().size() != 1) if (m_returnParameters->getParameters().size() != 1)
BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement " BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement "
"than in returns declaration.")); "than in returns declaration."));
@ -377,7 +378,6 @@ void BinaryOperation::checkTypeRequirements()
m_type = make_shared<BoolType>(); m_type = make_shared<BoolType>();
else else
{ {
assert(Token::isBinaryOp(m_operator));
m_type = m_commonType; m_type = m_commonType;
if (!m_commonType->acceptsBinaryOperator(m_operator)) if (!m_commonType->acceptsBinaryOperator(m_operator))
BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type."));
@ -393,25 +393,22 @@ void FunctionCall::checkTypeRequirements()
Type const* expressionType = m_expression->getType().get(); Type const* expressionType = m_expression->getType().get();
if (isTypeConversion()) if (isTypeConversion())
{ {
TypeType const* type = dynamic_cast<TypeType const*>(expressionType); TypeType const& type = dynamic_cast<TypeType const&>(*expressionType);
assert(type);
//@todo for structs, we have to check the number of arguments to be equal to the //@todo for structs, we have to check the number of arguments to be equal to the
// number of non-mapping members // number of non-mapping members
if (m_arguments.size() != 1) if (m_arguments.size() != 1)
BOOST_THROW_EXCEPTION(createTypeError("More than one argument for " BOOST_THROW_EXCEPTION(createTypeError("More than one argument for "
"explicit type conersion.")); "explicit type conersion."));
if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type->getActualType())) if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type.getActualType()))
BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed.")); BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
m_type = type->getActualType(); m_type = type.getActualType();
} }
else else
{ {
//@todo would be nice to create a struct type from the arguments //@todo would be nice to create a struct type from the arguments
// and then ask if that is implicitly convertible to the struct represented by the // and then ask if that is implicitly convertible to the struct represented by the
// function parameters // function parameters
FunctionType const* function = dynamic_cast<FunctionType const*>(expressionType); FunctionDefinition const& fun = dynamic_cast<FunctionType const&>(*expressionType).getFunction();
assert(function);
FunctionDefinition const& fun = function->getFunction();
vector<ASTPointer<VariableDeclaration>> const& parameters = fun.getParameters(); vector<ASTPointer<VariableDeclaration>> const& parameters = fun.getParameters();
if (parameters.size() != m_arguments.size()) if (parameters.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
@ -434,19 +431,21 @@ bool FunctionCall::isTypeConversion() const
void MemberAccess::checkTypeRequirements() void MemberAccess::checkTypeRequirements()
{ {
assert(false); // not yet implemented BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access not yet implemented."));
// m_type = ; // m_type = ;
} }
void IndexAccess::checkTypeRequirements() void IndexAccess::checkTypeRequirements()
{ {
assert(false); // not yet implemented BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Index access not yet implemented."));
// m_type = ; // m_type = ;
} }
void Identifier::checkTypeRequirements() void Identifier::checkTypeRequirements()
{ {
assert(m_referencedDeclaration); if (asserts(m_referencedDeclaration))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier not resolved."));
//@todo these dynamic casts here are not really nice... //@todo these dynamic casts here are not really nice...
// is i useful to have an AST visitor here? // is i useful to have an AST visitor here?
// or can this already be done in NameAndTypeResolver? // or can this already be done in NameAndTypeResolver?
@ -487,7 +486,7 @@ void Identifier::checkTypeRequirements()
m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef)); m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef));
return; return;
} }
assert(false); // declaration reference of unknown/forbidden type BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration reference of unknown/forbidden type."));
} }
void ElementaryTypeNameExpression::checkTypeRequirements() void ElementaryTypeNameExpression::checkTypeRequirements()

32
libsolidity/AST.h

@ -243,7 +243,10 @@ class ElementaryTypeName: public TypeName
{ {
public: public:
explicit ElementaryTypeName(Location const& _location, Token::Value _type): explicit ElementaryTypeName(Location const& _location, Token::Value _type):
TypeName(_location), m_type(_type) {} TypeName(_location), m_type(_type)
{
if (asserts(Token::isElementaryTypeName(_type))) BOOST_THROW_EXCEPTION(InternalCompilerError());
}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual std::shared_ptr<Type> toType() override { return Type::fromElementaryTypeName(m_type); } virtual std::shared_ptr<Type> toType() override { return Type::fromElementaryTypeName(m_type); }
@ -407,7 +410,12 @@ public:
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; } void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; }
ParameterList const& getFunctionReturnParameters() const { assert(m_returnParameters); return *m_returnParameters; } ParameterList const& getFunctionReturnParameters() const
{
if (asserts(m_returnParameters))
BOOST_THROW_EXCEPTION(InternalCompilerError());
return *m_returnParameters;
}
Expression* getExpression() const { return m_expression.get(); } Expression* getExpression() const { return m_expression.get(); }
private: private:
@ -495,7 +503,10 @@ public:
Assignment(Location const& _location, ASTPointer<Expression> const& _leftHandSide, Assignment(Location const& _location, ASTPointer<Expression> const& _leftHandSide,
Token::Value _assignmentOperator, ASTPointer<Expression> const& _rightHandSide): Token::Value _assignmentOperator, ASTPointer<Expression> const& _rightHandSide):
Expression(_location), m_leftHandSide(_leftHandSide), Expression(_location), m_leftHandSide(_leftHandSide),
m_assigmentOperator(_assignmentOperator), m_rightHandSide(_rightHandSide) {} m_assigmentOperator(_assignmentOperator), m_rightHandSide(_rightHandSide)
{
if (asserts(Token::isAssignmentOp(_assignmentOperator))) BOOST_THROW_EXCEPTION(InternalCompilerError());
}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
@ -519,7 +530,10 @@ public:
UnaryOperation(Location const& _location, Token::Value _operator, UnaryOperation(Location const& _location, Token::Value _operator,
ASTPointer<Expression> const& _subExpression, bool _isPrefix): ASTPointer<Expression> const& _subExpression, bool _isPrefix):
Expression(_location), m_operator(_operator), Expression(_location), m_operator(_operator),
m_subExpression(_subExpression), m_isPrefix(_isPrefix) {} m_subExpression(_subExpression), m_isPrefix(_isPrefix)
{
if (asserts(Token::isUnaryOp(_operator))) BOOST_THROW_EXCEPTION(InternalCompilerError());
}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
@ -541,7 +555,10 @@ class BinaryOperation: public Expression
public: public:
BinaryOperation(Location const& _location, ASTPointer<Expression> const& _left, BinaryOperation(Location const& _location, ASTPointer<Expression> const& _left,
Token::Value _operator, ASTPointer<Expression> const& _right): Token::Value _operator, ASTPointer<Expression> const& _right):
Expression(_location), m_left(_left), m_operator(_operator), m_right(_right) {} Expression(_location), m_left(_left), m_operator(_operator), m_right(_right)
{
if (asserts(Token::isBinaryOp(_operator) || Token::isCompareOp(_operator))) BOOST_THROW_EXCEPTION(InternalCompilerError());
}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
@ -658,7 +675,10 @@ class ElementaryTypeNameExpression: public PrimaryExpression
{ {
public: public:
ElementaryTypeNameExpression(Location const& _location, Token::Value _typeToken): ElementaryTypeNameExpression(Location const& _location, Token::Value _typeToken):
PrimaryExpression(_location), m_typeToken(_typeToken) {} PrimaryExpression(_location), m_typeToken(_typeToken)
{
if (asserts(Token::isElementaryTypeName(_typeToken))) BOOST_THROW_EXCEPTION(InternalCompilerError());
}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;

6
libsolidity/Compiler.cpp

@ -252,14 +252,16 @@ bool Compiler::visit(WhileStatement& _whileStatement)
bool Compiler::visit(Continue&) bool Compiler::visit(Continue&)
{ {
assert(!m_continueTags.empty()); if (asserts(!m_continueTags.empty()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Jump tag not available for \"continue\"."));
m_context.appendJumpTo(m_continueTags.back()); m_context.appendJumpTo(m_continueTags.back());
return false; return false;
} }
bool Compiler::visit(Break&) bool Compiler::visit(Break&)
{ {
assert(!m_breakTags.empty()); if (asserts(!m_breakTags.empty()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Jump tag not available for \"break\"."));
m_context.appendJumpTo(m_breakTags.back()); m_context.appendJumpTo(m_breakTags.back());
return false; return false;
} }

7
libsolidity/CompilerContext.cpp

@ -20,7 +20,6 @@
* Utilities for the solidity compiler. * Utilities for the solidity compiler.
*/ */
#include <cassert>
#include <utility> #include <utility>
#include <numeric> #include <numeric>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
@ -45,14 +44,16 @@ void CompilerContext::initializeLocalVariables(unsigned _numVariables)
int CompilerContext::getStackPositionOfVariable(const Declaration& _declaration) int CompilerContext::getStackPositionOfVariable(const Declaration& _declaration)
{ {
auto res = find(begin(m_localVariables), end(m_localVariables), &_declaration); auto res = find(begin(m_localVariables), end(m_localVariables), &_declaration);
assert(res != m_localVariables.end()); if (asserts(res != m_localVariables.end()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found on stack."));
return end(m_localVariables) - res - 1 + m_asm.deposit(); return end(m_localVariables) - res - 1 + m_asm.deposit();
} }
eth::AssemblyItem CompilerContext::getFunctionEntryLabel(const FunctionDefinition& _function) const eth::AssemblyItem CompilerContext::getFunctionEntryLabel(const FunctionDefinition& _function) const
{ {
auto res = m_functionEntryLabels.find(&_function); auto res = m_functionEntryLabels.find(&_function);
assert(res != m_functionEntryLabels.end()); if (asserts(res != m_functionEntryLabels.end()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Function entry label not found."));
return res->second.tag(); return res->second.tag();
} }

1
libsolidity/Exceptions.h

@ -35,6 +35,7 @@ struct ParserError: virtual Exception {};
struct TypeError: virtual Exception {}; struct TypeError: virtual Exception {};
struct DeclarationError: virtual Exception {}; struct DeclarationError: virtual Exception {};
struct CompilerError: virtual Exception {}; struct CompilerError: virtual Exception {};
struct InternalCompilerError: virtual Exception {};
typedef boost::error_info<struct tag_sourcePosition, int> errinfo_sourcePosition; typedef boost::error_info<struct tag_sourcePosition, int> errinfo_sourcePosition;
typedef boost::error_info<struct tag_sourceLocation, Location> errinfo_sourceLocation; typedef boost::error_info<struct tag_sourceLocation, Location> errinfo_sourceLocation;

58
libsolidity/ExpressionCompiler.cpp

@ -20,7 +20,6 @@
* Solidity AST to EVM bytecode compiler for expressions. * Solidity AST to EVM bytecode compiler for expressions.
*/ */
#include <cassert>
#include <utility> #include <utility>
#include <numeric> #include <numeric>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
@ -105,7 +104,8 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation)
m_context << u256(0) << eth::Instruction::SUB; m_context << u256(0) << eth::Instruction::SUB;
break; break;
default: default:
assert(false); // invalid operation BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid unary operator: " +
string(Token::toString(_unaryOperation.getOperator()))));
} }
} }
@ -127,7 +127,8 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation)
rightExpression.accept(*this); rightExpression.accept(*this);
// the types to compare have to be the same, but the resulting type is always bool // the types to compare have to be the same, but the resulting type is always bool
assert(*leftExpression.getType() == *rightExpression.getType()); if (asserts(*leftExpression.getType() == *rightExpression.getType()))
BOOST_THROW_EXCEPTION(InternalCompilerError());
appendCompareOperatorCode(op, *leftExpression.getType()); appendCompareOperatorCode(op, *leftExpression.getType());
} }
else else
@ -148,7 +149,8 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
if (_functionCall.isTypeConversion()) if (_functionCall.isTypeConversion())
{ {
//@todo we only have integers and bools for now which cannot be explicitly converted //@todo we only have integers and bools for now which cannot be explicitly converted
assert(_functionCall.getArguments().size() == 1); if (asserts(_functionCall.getArguments().size() == 1))
BOOST_THROW_EXCEPTION(InternalCompilerError());
Expression& firstArgument = *_functionCall.getArguments().front(); Expression& firstArgument = *_functionCall.getArguments().front();
firstArgument.accept(*this); firstArgument.accept(*this);
cleanHigherOrderBitsIfNeeded(*firstArgument.getType(), *_functionCall.getType()); cleanHigherOrderBitsIfNeeded(*firstArgument.getType(), *_functionCall.getType());
@ -159,28 +161,28 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
// Callee removes them and pushes return values // Callee removes them and pushes return values
m_currentLValue = nullptr; m_currentLValue = nullptr;
_functionCall.getExpression().accept(*this); _functionCall.getExpression().accept(*this);
FunctionDefinition const* function = dynamic_cast<FunctionDefinition*>(m_currentLValue); FunctionDefinition const& function = dynamic_cast<FunctionDefinition&>(*m_currentLValue);
assert(function);
eth::AssemblyItem returnLabel = m_context.pushNewTag(); eth::AssemblyItem returnLabel = m_context.pushNewTag();
std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments(); std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments();
assert(arguments.size() == function->getParameters().size()); if (asserts(arguments.size() == function.getParameters().size()))
BOOST_THROW_EXCEPTION(InternalCompilerError());
for (unsigned i = 0; i < arguments.size(); ++i) for (unsigned i = 0; i < arguments.size(); ++i)
{ {
arguments[i]->accept(*this); arguments[i]->accept(*this);
cleanHigherOrderBitsIfNeeded(*arguments[i]->getType(), cleanHigherOrderBitsIfNeeded(*arguments[i]->getType(),
*function->getParameters()[i]->getType()); *function.getParameters()[i]->getType());
} }
m_context.appendJumpTo(m_context.getFunctionEntryLabel(*function)); m_context.appendJumpTo(m_context.getFunctionEntryLabel(function));
m_context << returnLabel; m_context << returnLabel;
// callee adds return parameters, but removes arguments and return label // callee adds return parameters, but removes arguments and return label
m_context.adjustStackOffset(function->getReturnParameters().size() - arguments.size() - 1); m_context.adjustStackOffset(function.getReturnParameters().size() - arguments.size() - 1);
// @todo for now, the return value of a function is its first return value, so remove // @todo for now, the return value of a function is its first return value, so remove
// all others // all others
for (unsigned i = 1; i < function->getReturnParameters().size(); ++i) for (unsigned i = 1; i < function.getReturnParameters().size(); ++i)
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
} }
return false; return false;
@ -227,7 +229,7 @@ void ExpressionCompiler::endVisit(Literal& _literal)
m_context << _literal.getType()->literalValue(_literal); m_context << _literal.getType()->literalValue(_literal);
break; break;
default: default:
assert(false); // @todo BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer and boolean literals implemented for now."));
} }
} }
@ -249,15 +251,15 @@ void ExpressionCompiler::cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack,
{ {
// If we get here, there is either an implementation missing to clean higher oder bits // If we get here, there is either an implementation missing to clean higher oder bits
// for non-integer types that are explicitly convertible or we got here in error. // for non-integer types that are explicitly convertible or we got here in error.
assert(!_typeOnStack.isExplicitlyConvertibleTo(_targetType)); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested."));
assert(false); // these types should not be convertible.
} }
} }
void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation) void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation)
{ {
Token::Value const op = _binaryOperation.getOperator(); Token::Value const op = _binaryOperation.getOperator();
assert(op == Token::OR || op == Token::AND); if (asserts(op == Token::OR || op == Token::AND))
BOOST_THROW_EXCEPTION(InternalCompilerError());
_binaryOperation.getLeftExpression().accept(*this); _binaryOperation.getLeftExpression().accept(*this);
m_context << eth::Instruction::DUP1; m_context << eth::Instruction::DUP1;
@ -279,9 +281,8 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type
} }
else else
{ {
IntegerType const* type = dynamic_cast<IntegerType const*>(&_type); IntegerType const& type = dynamic_cast<IntegerType const&>(_type);
assert(type); bool const isSigned = type.isSigned();
bool const isSigned = type->isSigned();
// note that EVM opcodes compare like "stack[0] < stack[1]", // note that EVM opcodes compare like "stack[0] < stack[1]",
// but our left value is at stack[1], so everyhing is reversed. // but our left value is at stack[1], so everyhing is reversed.
@ -302,7 +303,7 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type
m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT); m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT);
break; break;
default: default:
assert(false); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator."));
} }
} }
} }
@ -316,14 +317,13 @@ void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator
else if (Token::isShiftOp(_operator)) else if (Token::isShiftOp(_operator))
appendShiftOperatorCode(_operator); appendShiftOperatorCode(_operator);
else else
assert(false); // unknown binary operator BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown binary operator."));
} }
void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type) void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type)
{ {
IntegerType const* type = dynamic_cast<IntegerType const*>(&_type); IntegerType const& type = dynamic_cast<IntegerType const&>(_type);
assert(type); bool const isSigned = type.isSigned();
bool const isSigned = type->isSigned();
switch (_operator) switch (_operator)
{ {
@ -343,7 +343,7 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty
m_context << eth::Instruction::SWAP1 << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); m_context << eth::Instruction::SWAP1 << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD);
break; break;
default: default:
assert(false); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator."));
} }
} }
@ -361,22 +361,21 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator)
m_context << eth::Instruction::XOR; m_context << eth::Instruction::XOR;
break; break;
default: default:
assert(false); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown bit operator."));
} }
} }
void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator)
{ {
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Shift operators not yet implemented."));
switch (_operator) switch (_operator)
{ {
case Token::SHL: case Token::SHL:
assert(false); //@todo
break; break;
case Token::SAR: case Token::SAR:
assert(false); //@todo
break; break;
default: default:
assert(false); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown shift operator."));
} }
} }
@ -402,7 +401,8 @@ void ExpressionCompiler::moveToLValue(Expression const& _expression)
unsigned ExpressionCompiler::stackPositionOfLValue() const unsigned ExpressionCompiler::stackPositionOfLValue() const
{ {
assert(m_currentLValue); if (asserts(m_currentLValue))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("LValue not available on request."));
return m_context.getStackPositionOfVariable(*m_currentLValue); return m_context.getStackPositionOfVariable(*m_currentLValue);
} }

16
libsolidity/NameAndTypeResolver.cpp

@ -20,7 +20,6 @@
* Parser part that determines the declarations corresponding to names and the types of expressions. * Parser part that determines the declarations corresponding to names and the types of expressions.
*/ */
#include <cassert>
#include <libsolidity/NameAndTypeResolver.h> #include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
#include <libsolidity/Exceptions.h> #include <libsolidity/Exceptions.h>
@ -123,7 +122,8 @@ void DeclarationRegistrationHelper::endVisit(VariableDefinition& _variableDefini
{ {
// Register the local variables with the function // Register the local variables with the function
// This does not fit here perfectly, but it saves us another AST visit. // This does not fit here perfectly, but it saves us another AST visit.
assert(m_currentFunction); if (asserts(m_currentFunction))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable definition without function."));
m_currentFunction->addLocalVariable(_variableDefinition.getDeclaration()); m_currentFunction->addLocalVariable(_variableDefinition.getDeclaration());
} }
@ -138,19 +138,22 @@ void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node)
map<ASTNode const*, Scope>::iterator iter; map<ASTNode const*, Scope>::iterator iter;
bool newlyAdded; bool newlyAdded;
tie(iter, newlyAdded) = m_scopes.emplace(&_node, Scope(m_currentScope)); tie(iter, newlyAdded) = m_scopes.emplace(&_node, Scope(m_currentScope));
assert(newlyAdded); if (asserts(newlyAdded))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to add new scope."));
m_currentScope = &iter->second; m_currentScope = &iter->second;
} }
void DeclarationRegistrationHelper::closeCurrentScope() void DeclarationRegistrationHelper::closeCurrentScope()
{ {
assert(m_currentScope); if (asserts(m_currentScope))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Closed non-existing scope."));
m_currentScope = m_currentScope->getEnclosingScope(); m_currentScope = m_currentScope->getEnclosingScope();
} }
void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope)
{ {
assert(m_currentScope); if (asserts(m_currentScope))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration registered without scope."));
if (!m_currentScope->registerDeclaration(_declaration)) if (!m_currentScope->registerDeclaration(_declaration))
BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation())
<< errinfo_comment("Identifier already declared.")); << errinfo_comment("Identifier already declared."));
@ -177,7 +180,8 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable)
bool ReferencesResolver::visit(Return& _return) bool ReferencesResolver::visit(Return& _return)
{ {
assert(m_returnParameters); if (asserts(m_returnParameters))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Return parameters not set."));
_return.setFunctionReturnParameters(*m_returnParameters); _return.setFunctionReturnParameters(*m_returnParameters);
return true; return true;
} }

33
libsolidity/Scanner.cpp

@ -50,7 +50,6 @@
* Solidity scanner. * Solidity scanner.
*/ */
#include <cassert>
#include <algorithm> #include <algorithm>
#include <tuple> #include <tuple>
#include <libsolidity/Scanner.h> #include <libsolidity/Scanner.h>
@ -113,11 +112,10 @@ void Scanner::reset(CharStream const& _source)
} }
bool Scanner::scanHexNumber(char& o_scannedNumber, int _expectedLength) bool Scanner::scanHexByte(char& o_scannedByte)
{ {
assert(_expectedLength <= 4); // prevent overflow
char x = 0; char x = 0;
for (int i = 0; i < _expectedLength; i++) for (int i = 0; i < 2; i++)
{ {
int d = HexValue(m_char); int d = HexValue(m_char);
if (d < 0) if (d < 0)
@ -128,7 +126,7 @@ bool Scanner::scanHexNumber(char& o_scannedNumber, int _expectedLength)
x = x * 16 + d; x = x * 16 + d;
advance(); advance();
} }
o_scannedNumber = x; o_scannedByte = x;
return true; return true;
} }
@ -175,7 +173,8 @@ Token::Value Scanner::skipSingleLineComment()
Token::Value Scanner::skipMultiLineComment() Token::Value Scanner::skipMultiLineComment()
{ {
assert(m_char == '*'); if (asserts(m_char == '*'))
BOOST_THROW_EXCEPTION(InternalCompilerError());
advance(); advance();
while (!isSourcePastEndOfInput()) while (!isSourcePastEndOfInput())
{ {
@ -418,15 +417,11 @@ bool Scanner::scanEscape()
case 't': case 't':
c = '\t'; c = '\t';
break; break;
case 'u':
if (!scanHexNumber(c, 4))
return false;
break;
case 'v': case 'v':
c = '\v'; c = '\v';
break; break;
case 'x': case 'x':
if (!scanHexNumber(c, 2)) if (!scanHexByte(c))
return false; return false;
break; break;
} }
@ -468,7 +463,9 @@ void Scanner::scanDecimalDigits()
Token::Value Scanner::scanNumber(bool _periodSeen) Token::Value Scanner::scanNumber(bool _periodSeen)
{ {
assert(IsDecimalDigit(m_char)); // the first digit of the number or the fraction // the first digit of the number or the fraction
if (asserts(IsDecimalDigit(m_char)))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Number does not start with decimal digit."));
enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL; enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL;
LiteralScope literal(this); LiteralScope literal(this);
if (_periodSeen) if (_periodSeen)
@ -510,7 +507,8 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
// scan exponent, if any // scan exponent, if any
if (m_char == 'e' || m_char == 'E') if (m_char == 'e' || m_char == 'E')
{ {
assert(kind != HEX); // 'e'/'E' must be scanned as part of the hex number if (asserts(kind != HEX)) // 'e'/'E' must be scanned as part of the hex number
BOOST_THROW_EXCEPTION(InternalCompilerError());
if (kind != DECIMAL) return Token::ILLEGAL; if (kind != DECIMAL) return Token::ILLEGAL;
// scan exponent // scan exponent
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
@ -606,7 +604,8 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
static Token::Value KeywordOrIdentifierToken(string const& input) static Token::Value KeywordOrIdentifierToken(string const& input)
{ {
assert(!input.empty()); if (asserts(!input.empty()))
BOOST_THROW_EXCEPTION(InternalCompilerError());
int const kMinLength = 2; int const kMinLength = 2;
int const kMaxLength = 10; int const kMaxLength = 10;
if (input.size() < kMinLength || input.size() > kMaxLength) if (input.size() < kMinLength || input.size() > kMaxLength)
@ -634,7 +633,8 @@ case ch:
Token::Value Scanner::scanIdentifierOrKeyword() Token::Value Scanner::scanIdentifierOrKeyword()
{ {
assert(IsIdentifierStart(m_char)); if (asserts(IsIdentifierStart(m_char)))
BOOST_THROW_EXCEPTION(InternalCompilerError());
LiteralScope literal(this); LiteralScope literal(this);
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
// Scan the rest of the identifier characters. // Scan the rest of the identifier characters.
@ -656,7 +656,8 @@ char CharStream::advanceAndGet()
char CharStream::rollback(size_t _amount) char CharStream::rollback(size_t _amount)
{ {
assert(m_pos >= _amount); if (asserts(m_pos >= _amount))
BOOST_THROW_EXCEPTION(InternalCompilerError());
m_pos -= _amount; m_pos -= _amount;
return get(); return get();
} }

2
libsolidity/Scanner.h

@ -169,7 +169,7 @@ private:
/// If the next character is _next, advance and return _then, otherwise return _else. /// If the next character is _next, advance and return _then, otherwise return _else.
inline Token::Value selectToken(char _next, Token::Value _then, Token::Value _else); inline Token::Value selectToken(char _next, Token::Value _then, Token::Value _else);
bool scanHexNumber(char& o_scannedNumber, int _expectedLength); bool scanHexByte(char& o_scannedByte);
/// Scans a single JavaScript token. /// Scans a single JavaScript token.
void scanToken(); void scanToken();

64
libsolidity/Token.h

@ -42,9 +42,9 @@
#pragma once #pragma once
#include <cassert>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libsolidity/Exceptions.h>
namespace dev namespace dev
{ {
@ -81,8 +81,6 @@ namespace solidity
T(SEMICOLON, ";", 0) \ T(SEMICOLON, ";", 0) \
T(PERIOD, ".", 0) \ T(PERIOD, ".", 0) \
T(CONDITIONAL, "?", 3) \ T(CONDITIONAL, "?", 3) \
T(INC, "++", 0) \
T(DEC, "--", 0) \
T(ARROW, "=>", 0) \ T(ARROW, "=>", 0) \
\ \
/* Assignment operators. */ \ /* Assignment operators. */ \
@ -136,6 +134,8 @@ namespace solidity
/* being contiguous and sorted in the same order! */ \ /* being contiguous and sorted in the same order! */ \
T(NOT, "!", 0) \ T(NOT, "!", 0) \
T(BIT_NOT, "~", 0) \ T(BIT_NOT, "~", 0) \
T(INC, "++", 0) \
T(DEC, "--", 0) \
K(DELETE, "delete", 0) \ K(DELETE, "delete", 0) \
\ \
/* Keywords */ \ /* Keywords */ \
@ -224,7 +224,8 @@ public:
// (e.g. "LT" for the token LT). // (e.g. "LT" for the token LT).
static char const* getName(Value tok) static char const* getName(Value tok)
{ {
assert(tok < NUM_TOKENS); // tok is unsigned if (asserts(tok < NUM_TOKENS))
BOOST_THROW_EXCEPTION(InternalCompilerError());
return m_name[tok]; return m_name[tok];
} }
@ -249,55 +250,10 @@ public:
isEqualityOp(op) || isInequalityOp(op); isEqualityOp(op) || isInequalityOp(op);
} }
static Value negateCompareOp(Value op)
{
assert(isArithmeticCompareOp(op));
switch (op)
{
case EQ:
return NE;
case NE:
return EQ;
case LT:
return GTE;
case GT:
return LTE;
case LTE:
return GT;
case GTE:
return LT;
default:
assert(false); // should not get here
return op;
}
}
static Value reverseCompareOp(Value op)
{
assert(isArithmeticCompareOp(op));
switch (op)
{
case EQ:
return EQ;
case NE:
return NE;
case LT:
return GT;
case GT:
return LT;
case LTE:
return GTE;
case GTE:
return LTE;
default:
assert(false); // should not get here
return op;
}
}
static Value AssignmentToBinaryOp(Value op) static Value AssignmentToBinaryOp(Value op)
{ {
assert(isAssignmentOp(op) && op != ASSIGN); if (asserts(isAssignmentOp(op) && op != ASSIGN))
BOOST_THROW_EXCEPTION(InternalCompilerError());
return Token::Value(op + (BIT_OR - ASSIGN_BIT_OR)); return Token::Value(op + (BIT_OR - ASSIGN_BIT_OR));
} }
@ -311,7 +267,8 @@ public:
// have a (unique) string (e.g. an IDENTIFIER). // have a (unique) string (e.g. an IDENTIFIER).
static char const* toString(Value tok) static char const* toString(Value tok)
{ {
assert(tok < NUM_TOKENS); // tok is unsigned. if (asserts(tok < NUM_TOKENS))
BOOST_THROW_EXCEPTION(InternalCompilerError());
return m_string[tok]; return m_string[tok];
} }
@ -319,7 +276,8 @@ public:
// operators; returns 0 otherwise. // operators; returns 0 otherwise.
static int precedence(Value tok) static int precedence(Value tok)
{ {
assert(tok < NUM_TOKENS); // tok is unsigned. if (asserts(tok < NUM_TOKENS))
BOOST_THROW_EXCEPTION(InternalCompilerError());
return m_precedence[tok]; return m_precedence[tok];
} }

14
libsolidity/Types.cpp

@ -20,7 +20,6 @@
* Solidity data types * Solidity data types
*/ */
#include <cassert>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <libsolidity/Types.h> #include <libsolidity/Types.h>
@ -33,6 +32,9 @@ namespace solidity
std::shared_ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken) std::shared_ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken)
{ {
if (asserts(Token::isElementaryTypeName(_typeToken)))
BOOST_THROW_EXCEPTION(InternalCompilerError());
if (Token::INT <= _typeToken && _typeToken <= Token::HASH256) if (Token::INT <= _typeToken && _typeToken <= Token::HASH256)
{ {
int offset = _typeToken - Token::INT; int offset = _typeToken - Token::INT;
@ -52,7 +54,8 @@ std::shared_ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken)
else if (_typeToken == Token::BOOL) else if (_typeToken == Token::BOOL)
return std::make_shared<BoolType>(); return std::make_shared<BoolType>();
else else
assert(false); // @todo add other tyes BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " +
std::string(Token::toString(_typeToken)) + " to type."));
return std::shared_ptr<Type>(); return std::shared_ptr<Type>();
} }
@ -63,7 +66,7 @@ std::shared_ptr<Type> Type::fromUserDefinedTypeName(UserDefinedTypeName const& _
std::shared_ptr<Type> Type::fromMapping(Mapping const&) std::shared_ptr<Type> Type::fromMapping(Mapping const&)
{ {
assert(false); //@todo not yet implemented BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Mapping types not yet implemented."));
return std::shared_ptr<Type>(); return std::shared_ptr<Type>();
} }
@ -94,7 +97,8 @@ IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
{ {
if (isAddress()) if (isAddress())
_bits = 160; _bits = 160;
assert(_bits > 0 && _bits <= 256 && _bits % 8 == 0); if (asserts(_bits > 0 && _bits <= 256 && _bits % 8 == 0))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid bit number for integer type: " + dev::toString(_bits)));
} }
bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
@ -187,7 +191,7 @@ u256 BoolType::literalValue(Literal const& _literal) const
else if (_literal.getToken() == Token::FALSE_LITERAL) else if (_literal.getToken() == Token::FALSE_LITERAL)
return u256(0); return u256(0);
else else
assert(false); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Bool type constructed from non-boolean literal."));
} }
bool ContractType::operator==(Type const& _other) const bool ContractType::operator==(Type const& _other) const

7
libsolidity/Types.h

@ -26,6 +26,7 @@
#include <string> #include <string>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libsolidity/Exceptions.h>
#include <libsolidity/ASTForward.h> #include <libsolidity/ASTForward.h>
#include <libsolidity/Token.h> #include <libsolidity/Token.h>
@ -75,7 +76,11 @@ public:
virtual unsigned getCalldataEncodedSize() const { return 0; } virtual unsigned getCalldataEncodedSize() const { return 0; }
virtual std::string toString() const = 0; virtual std::string toString() const = 0;
virtual u256 literalValue(Literal const&) const { assert(false); } virtual u256 literalValue(Literal const&) const
{
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Literal value requested "
"for type without literals."));
}
}; };
/** /**

45
solc/main.cpp

@ -84,21 +84,27 @@ int main(int argc, char** argv)
ASTPointer<ContractDefinition> ast; ASTPointer<ContractDefinition> ast;
shared_ptr<Scanner> scanner = make_shared<Scanner>(CharStream(sourceCode)); shared_ptr<Scanner> scanner = make_shared<Scanner>(CharStream(sourceCode));
Parser parser; Parser parser;
bytes instructions;
Compiler compiler;
try try
{ {
ast = parser.parse(scanner); ast = parser.parse(scanner);
NameAndTypeResolver resolver;
resolver.resolveNamesAndTypes(*ast.get());
cout << "Syntax tree for the contract:" << endl;
dev::solidity::ASTPrinter printer(ast, sourceCode);
printer.print(cout);
compiler.compileContract(*ast);
instructions = compiler.getAssembledBytecode();
} }
catch (ParserError const& exception) catch (ParserError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Parser error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Parser error", *scanner);
return -1; return -1;
} }
NameAndTypeResolver resolver;
try
{
resolver.resolveNamesAndTypes(*ast.get());
}
catch (DeclarationError const& exception) catch (DeclarationError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Declaration error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Declaration error", *scanner);
@ -109,23 +115,26 @@ int main(int argc, char** argv)
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Type error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Type error", *scanner);
return -1; return -1;
} }
cout << "Syntax tree for the contract:" << endl;
dev::solidity::ASTPrinter printer(ast, sourceCode);
printer.print(cout);
bytes instructions;
Compiler compiler;
try
{
compiler.compileContract(*ast);
instructions = compiler.getAssembledBytecode();
}
catch (CompilerError const& exception) catch (CompilerError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Compiler error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Compiler error", *scanner);
return -1; return -1;
} }
catch (InternalCompilerError const& exception)
{
cerr << "Internal compiler error: " << boost::diagnostic_information(exception) << endl;
return -1;
}
catch (Exception const& exception)
{
cerr << "Exception during compilation: " << boost::diagnostic_information(exception) << endl;
return -1;
}
catch (...)
{
cerr << "Unknown exception during compilation." << endl;
return -1;
}
cout << "EVM assembly:" << endl; cout << "EVM assembly:" << endl;
compiler.streamAssembly(cout); compiler.streamAssembly(cout);

Loading…
Cancel
Save