From 37216a246ae2ef73029c46861fc260cfe807b062 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 5 Nov 2014 14:20:56 +0100 Subject: [PATCH] Converted all asserts to exceptions. --- libsolidity/AST.cpp | 25 ++++++----- libsolidity/AST.h | 32 ++++++++++++--- libsolidity/Compiler.cpp | 6 ++- libsolidity/CompilerContext.cpp | 7 ++-- libsolidity/Exceptions.h | 1 + libsolidity/ExpressionCompiler.cpp | 58 +++++++++++++------------- libsolidity/NameAndTypeResolver.cpp | 16 +++++--- libsolidity/Scanner.cpp | 33 +++++++-------- libsolidity/Scanner.h | 2 +- libsolidity/Token.h | 64 +++++------------------------ libsolidity/Types.cpp | 14 ++++--- libsolidity/Types.h | 7 +++- solc/main.cpp | 45 ++++++++++++-------- 13 files changed, 157 insertions(+), 153 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 0ecb639f0..f9c49adc5 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -293,9 +293,10 @@ void Break::checkTypeRequirements() void Return::checkTypeRequirements() { - assert(m_returnParameters); if (!m_expression) return; + if (asserts(m_returnParameters)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Return parameters not assigned.")); if (m_returnParameters->getParameters().size() != 1) BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement " "than in returns declaration.")); @@ -377,7 +378,6 @@ void BinaryOperation::checkTypeRequirements() m_type = make_shared(); else { - assert(Token::isBinaryOp(m_operator)); m_type = m_commonType; if (!m_commonType->acceptsBinaryOperator(m_operator)) BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); @@ -393,25 +393,22 @@ void FunctionCall::checkTypeRequirements() Type const* expressionType = m_expression->getType().get(); if (isTypeConversion()) { - TypeType const* type = dynamic_cast(expressionType); - assert(type); + TypeType const& type = dynamic_cast(*expressionType); //@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(createTypeError("More than one argument for " "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.")); - m_type = type->getActualType(); + m_type = type.getActualType(); } else { //@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 // function parameters - FunctionType const* function = dynamic_cast(expressionType); - assert(function); - FunctionDefinition const& fun = function->getFunction(); + FunctionDefinition const& fun = dynamic_cast(*expressionType).getFunction(); vector> const& parameters = fun.getParameters(); if (parameters.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); @@ -434,19 +431,21 @@ bool FunctionCall::isTypeConversion() const void MemberAccess::checkTypeRequirements() { - assert(false); // not yet implemented + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access not yet implemented.")); // m_type = ; } void IndexAccess::checkTypeRequirements() { - assert(false); // not yet implemented + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Index access not yet implemented.")); // m_type = ; } 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... // is i useful to have an AST visitor here? // or can this already be done in NameAndTypeResolver? @@ -487,7 +486,7 @@ void Identifier::checkTypeRequirements() m_type = make_shared(make_shared(*contractDef)); return; } - assert(false); // declaration reference of unknown/forbidden type + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration reference of unknown/forbidden type.")); } void ElementaryTypeNameExpression::checkTypeRequirements() diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 43aa9bf5e..f42ff47d0 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -243,7 +243,10 @@ class ElementaryTypeName: public TypeName { public: 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 std::shared_ptr toType() override { return Type::fromElementaryTypeName(m_type); } @@ -407,7 +410,12 @@ public: virtual void checkTypeRequirements() override; 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(); } private: @@ -495,7 +503,10 @@ public: Assignment(Location const& _location, ASTPointer const& _leftHandSide, Token::Value _assignmentOperator, ASTPointer const& _rightHandSide): 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 checkTypeRequirements() override; @@ -519,7 +530,10 @@ public: UnaryOperation(Location const& _location, Token::Value _operator, ASTPointer const& _subExpression, bool _isPrefix): 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 checkTypeRequirements() override; @@ -541,7 +555,10 @@ class BinaryOperation: public Expression public: BinaryOperation(Location const& _location, ASTPointer const& _left, Token::Value _operator, ASTPointer 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 checkTypeRequirements() override; @@ -658,7 +675,10 @@ class ElementaryTypeNameExpression: public PrimaryExpression { public: 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 checkTypeRequirements() override; diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index a44c177d7..654eceadb 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -252,14 +252,16 @@ bool Compiler::visit(WhileStatement& _whileStatement) 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()); return false; } 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()); return false; } diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index b8f57618b..44d0844c2 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -20,7 +20,6 @@ * Utilities for the solidity compiler. */ -#include #include #include #include @@ -45,14 +44,16 @@ void CompilerContext::initializeLocalVariables(unsigned _numVariables) int CompilerContext::getStackPositionOfVariable(const Declaration& _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(); } eth::AssemblyItem CompilerContext::getFunctionEntryLabel(const FunctionDefinition& _function) const { 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(); } diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index 1d981e7c0..1903c1dc2 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -35,6 +35,7 @@ struct ParserError: virtual Exception {}; struct TypeError: virtual Exception {}; struct DeclarationError: virtual Exception {}; struct CompilerError: virtual Exception {}; +struct InternalCompilerError: virtual Exception {}; typedef boost::error_info errinfo_sourcePosition; typedef boost::error_info errinfo_sourceLocation; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index f9cbee377..d23579b11 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -20,7 +20,6 @@ * Solidity AST to EVM bytecode compiler for expressions. */ -#include #include #include #include @@ -105,7 +104,8 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) m_context << u256(0) << eth::Instruction::SUB; break; 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); // 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()); } else @@ -148,7 +149,8 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) if (_functionCall.isTypeConversion()) { //@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(); firstArgument.accept(*this); cleanHigherOrderBitsIfNeeded(*firstArgument.getType(), *_functionCall.getType()); @@ -159,28 +161,28 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) // Callee removes them and pushes return values m_currentLValue = nullptr; _functionCall.getExpression().accept(*this); - FunctionDefinition const* function = dynamic_cast(m_currentLValue); - assert(function); + FunctionDefinition const& function = dynamic_cast(*m_currentLValue); eth::AssemblyItem returnLabel = m_context.pushNewTag(); std::vector> 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) { arguments[i]->accept(*this); 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; // 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 // 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; } return false; @@ -227,7 +229,7 @@ void ExpressionCompiler::endVisit(Literal& _literal) m_context << _literal.getType()->literalValue(_literal); break; 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 // for non-integer types that are explicitly convertible or we got here in error. - assert(!_typeOnStack.isExplicitlyConvertibleTo(_targetType)); - assert(false); // these types should not be convertible. + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested.")); } } void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation) { 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); m_context << eth::Instruction::DUP1; @@ -279,9 +281,8 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type } else { - IntegerType const* type = dynamic_cast(&_type); - assert(type); - bool const isSigned = type->isSigned(); + IntegerType const& type = dynamic_cast(_type); + bool const isSigned = type.isSigned(); // note that EVM opcodes compare like "stack[0] < stack[1]", // 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); break; 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)) appendShiftOperatorCode(_operator); else - assert(false); // unknown binary operator + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown binary operator.")); } void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type) { - IntegerType const* type = dynamic_cast(&_type); - assert(type); - bool const isSigned = type->isSigned(); + IntegerType const& type = dynamic_cast(_type); + bool const isSigned = type.isSigned(); 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); break; 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; break; default: - assert(false); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown bit operator.")); } } void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) { + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Shift operators not yet implemented.")); switch (_operator) { case Token::SHL: - assert(false); //@todo break; case Token::SAR: - assert(false); //@todo break; 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 { - assert(m_currentLValue); + if (asserts(m_currentLValue)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("LValue not available on request.")); return m_context.getStackPositionOfVariable(*m_currentLValue); } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 4b77ed132..0578e5996 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -20,7 +20,6 @@ * Parser part that determines the declarations corresponding to names and the types of expressions. */ -#include #include #include #include @@ -123,7 +122,8 @@ void DeclarationRegistrationHelper::endVisit(VariableDefinition& _variableDefini { // Register the local variables with the function // 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()); } @@ -138,19 +138,22 @@ void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node) map::iterator iter; bool newlyAdded; 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; } 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(); } 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)) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) << errinfo_comment("Identifier already declared.")); @@ -177,7 +180,8 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) 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 true; } diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index d8defb50a..c36820317 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -50,7 +50,6 @@ * Solidity scanner. */ -#include #include #include #include @@ -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; - for (int i = 0; i < _expectedLength; i++) + for (int i = 0; i < 2; i++) { int d = HexValue(m_char); if (d < 0) @@ -128,7 +126,7 @@ bool Scanner::scanHexNumber(char& o_scannedNumber, int _expectedLength) x = x * 16 + d; advance(); } - o_scannedNumber = x; + o_scannedByte = x; return true; } @@ -175,7 +173,8 @@ Token::Value Scanner::skipSingleLineComment() Token::Value Scanner::skipMultiLineComment() { - assert(m_char == '*'); + if (asserts(m_char == '*')) + BOOST_THROW_EXCEPTION(InternalCompilerError()); advance(); while (!isSourcePastEndOfInput()) { @@ -418,15 +417,11 @@ bool Scanner::scanEscape() case 't': c = '\t'; break; - case 'u': - if (!scanHexNumber(c, 4)) - return false; - break; case 'v': c = '\v'; break; case 'x': - if (!scanHexNumber(c, 2)) + if (!scanHexByte(c)) return false; break; } @@ -468,7 +463,9 @@ void Scanner::scanDecimalDigits() 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; LiteralScope literal(this); if (_periodSeen) @@ -510,7 +507,8 @@ Token::Value Scanner::scanNumber(bool _periodSeen) // scan exponent, if any 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; // scan exponent addLiteralCharAndAdvance(); @@ -606,7 +604,8 @@ Token::Value Scanner::scanNumber(bool _periodSeen) static Token::Value KeywordOrIdentifierToken(string const& input) { - assert(!input.empty()); + if (asserts(!input.empty())) + BOOST_THROW_EXCEPTION(InternalCompilerError()); int const kMinLength = 2; int const kMaxLength = 10; if (input.size() < kMinLength || input.size() > kMaxLength) @@ -634,7 +633,8 @@ case ch: Token::Value Scanner::scanIdentifierOrKeyword() { - assert(IsIdentifierStart(m_char)); + if (asserts(IsIdentifierStart(m_char))) + BOOST_THROW_EXCEPTION(InternalCompilerError()); LiteralScope literal(this); addLiteralCharAndAdvance(); // Scan the rest of the identifier characters. @@ -656,7 +656,8 @@ char CharStream::advanceAndGet() char CharStream::rollback(size_t _amount) { - assert(m_pos >= _amount); + if (asserts(m_pos >= _amount)) + BOOST_THROW_EXCEPTION(InternalCompilerError()); m_pos -= _amount; return get(); } diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index c2dfb476f..537c2434e 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -169,7 +169,7 @@ private: /// 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); - bool scanHexNumber(char& o_scannedNumber, int _expectedLength); + bool scanHexByte(char& o_scannedByte); /// Scans a single JavaScript token. void scanToken(); diff --git a/libsolidity/Token.h b/libsolidity/Token.h index c54f387c7..0fb9b670f 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -42,9 +42,9 @@ #pragma once -#include #include #include +#include namespace dev { @@ -81,8 +81,6 @@ namespace solidity T(SEMICOLON, ";", 0) \ T(PERIOD, ".", 0) \ T(CONDITIONAL, "?", 3) \ - T(INC, "++", 0) \ - T(DEC, "--", 0) \ T(ARROW, "=>", 0) \ \ /* Assignment operators. */ \ @@ -136,6 +134,8 @@ namespace solidity /* being contiguous and sorted in the same order! */ \ T(NOT, "!", 0) \ T(BIT_NOT, "~", 0) \ + T(INC, "++", 0) \ + T(DEC, "--", 0) \ K(DELETE, "delete", 0) \ \ /* Keywords */ \ @@ -224,7 +224,8 @@ public: // (e.g. "LT" for the token LT). 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]; } @@ -249,55 +250,10 @@ public: 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) { - assert(isAssignmentOp(op) && op != ASSIGN); + if (asserts(isAssignmentOp(op) && op != ASSIGN)) + BOOST_THROW_EXCEPTION(InternalCompilerError()); return Token::Value(op + (BIT_OR - ASSIGN_BIT_OR)); } @@ -311,7 +267,8 @@ public: // have a (unique) string (e.g. an IDENTIFIER). 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]; } @@ -319,7 +276,8 @@ public: // operators; returns 0 otherwise. 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]; } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 4f5563391..a4d70e3a0 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -20,7 +20,6 @@ * Solidity data types */ -#include #include #include #include @@ -33,6 +32,9 @@ namespace solidity std::shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) { + if (asserts(Token::isElementaryTypeName(_typeToken))) + BOOST_THROW_EXCEPTION(InternalCompilerError()); + if (Token::INT <= _typeToken && _typeToken <= Token::HASH256) { int offset = _typeToken - Token::INT; @@ -52,7 +54,8 @@ std::shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) else if (_typeToken == Token::BOOL) return std::make_shared(); 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(); } @@ -63,7 +66,7 @@ std::shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _ std::shared_ptr 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(); } @@ -94,7 +97,8 @@ IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): { if (isAddress()) _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 @@ -187,7 +191,7 @@ u256 BoolType::literalValue(Literal const& _literal) const else if (_literal.getToken() == Token::FALSE_LITERAL) return u256(0); else - assert(false); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Bool type constructed from non-boolean literal.")); } bool ContractType::operator==(Type const& _other) const diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 190134d7a..4493b8037 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -75,7 +76,11 @@ public: virtual unsigned getCalldataEncodedSize() const { return 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.")); + } }; /** diff --git a/solc/main.cpp b/solc/main.cpp index 1cf466c72..04fee2905 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -84,21 +84,27 @@ int main(int argc, char** argv) ASTPointer ast; shared_ptr scanner = make_shared(CharStream(sourceCode)); Parser parser; + bytes instructions; + Compiler compiler; try { 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) { SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Parser error", *scanner); return -1; } - - NameAndTypeResolver resolver; - try - { - resolver.resolveNamesAndTypes(*ast.get()); - } catch (DeclarationError const& exception) { SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Declaration error", *scanner); @@ -109,23 +115,26 @@ int main(int argc, char** argv) SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Type error", *scanner); 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) { SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Compiler error", *scanner); 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; compiler.streamAssembly(cout);