diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 15da9e0d8..91b4a42b1 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -248,12 +248,16 @@ 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() << 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 } @@ -287,11 +291,10 @@ void Break::checkTypeRequirements() void Return::checkTypeRequirements() { - BOOST_ASSERT(m_returnParameters != nullptr); + BOOST_ASSERT(m_returnParameters); 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(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 +330,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(createTypeError("Operator not compatible with type.")); } } @@ -337,7 +340,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(createTypeError("Unary operator not compatible with type.")); } void BinaryOperation::checkTypeRequirements() @@ -349,7 +352,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(createTypeError("No common type found in binary operation.")); if (Token::isCompareOp(m_operator)) m_type = std::make_shared(); else @@ -357,7 +360,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(createTypeError("Operator not compatible with type.")); } } @@ -371,15 +374,14 @@ 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) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("More than one argument for " - "explicit type conersion.")); + BOOST_THROW_EXCEPTION(createTypeError("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(createTypeError("Explicit type conversion not allowed.")); m_type = type->getActualType(); } else if (category == Type::Category::FUNCTION) @@ -388,16 +390,14 @@ 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()) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("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() << errinfo_comment("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()) @@ -406,9 +406,7 @@ void FunctionCall::checkTypeRequirements() m_type = fun.getReturnParameterList()->getParameters().front()->getType(); } else - { - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Type does not support invocation.")); - } + BOOST_THROW_EXCEPTION(createTypeError("Type does not support invocation.")); } void MemberAccess::checkTypeRequirements() @@ -425,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? @@ -435,24 +433,24 @@ 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(TypeError() << errinfo_comment("Variable referenced before type " - "could be determined.")); + BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type " + "could be determined.")); m_type = variable->getType(); return; } //@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 @@ -461,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 d5e1e0662..df146ab10 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,10 @@ public: Location const& getLocation() const { return m_location; } + /// Creates a @ref TypeError exception and decorates it with the location of the node and + /// the given description + TypeError createTypeError(std::string const& _description); + private: Location m_location; }; @@ -165,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 066088009..44245ed46 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -253,7 +253,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()); printType(_node); @@ -417,7 +417,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; } } @@ -436,7 +436,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/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 c600ebf12..5a48c47dd 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -22,7 +22,9 @@ #pragma once +#include #include +#include namespace dev { @@ -33,5 +35,8 @@ 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 707b6ce14..e9d90dc88 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -129,15 +129,17 @@ 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_comment("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); } @@ -153,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; } @@ -174,12 +176,13 @@ bool ReferencesResolver::visit(Mapping&) bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_typeName.getName()); - if (declaration == nullptr) - BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Undeclared identifier.")); + 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) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Identifier does not name a type name.")); + if (!referencedStruct) + BOOST_THROW_EXCEPTION(_typeName.createTypeError("Identifier does not name a type name.")); _typeName.setReferencedStruct(*referencedStruct); return false; } @@ -187,8 +190,9 @@ bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) bool ReferencesResolver::visit(Identifier& _identifier) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName()); - if (declaration == nullptr) - BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Undeclared identifier.")); + if (!declaration) + 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 408aa7bd6..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,18 +534,9 @@ ASTPointer Parser::getLiteralAndAdvance() return identifier; } -void Parser::throwExpectationError(std::string const& _description) +ParserError Parser::createParserError(std::string const& _description) const { - //@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())); + 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/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 new file mode 100644 index 000000000..b270342c9 --- /dev/null +++ b/libsolidity/SourceReferenceFormatter.cpp @@ -0,0 +1,93 @@ +/* + 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) << std::endl + << std::string(startColumn, ' ') << "^"; + if (endColumn > startColumn + 2) + _stream << std::string(endColumn - startColumn - 2, '-'); + if (endColumn > startColumn + 1) + _stream << "^"; + _stream << std::endl; + } + else + _stream << _scanner.getLineAtPosition(_location.start) << std::endl + << 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) << std::endl + << _scanner.getLineAtPosition(_position) << std::endl + << std::string(column, ' ') << "^" << std::endl; +} + +void SourceReferenceFormatter::printExceptionInformation(std::ostream& _stream, + Exception const& _exception, + std::string const& _name, + Scanner const& _scanner) +{ + _stream << _name; + if (std::string const* description = boost::get_error_info(_exception)) + _stream << ": " << *description; + + if (int const* position = boost::get_error_info(_exception)) + { + _stream << " "; + printSourcePosition(_stream, *position, _scanner); + } + if (Location const* location = boost::get_error_info(_exception)) + { + _stream << " "; + printSourceLocation(_stream, *location, _scanner); + } +} + +} +} diff --git a/libsolidity/SourceReferenceFormatter.h b/libsolidity/SourceReferenceFormatter.h new file mode 100644 index 000000000..4736066fd --- /dev/null +++ b/libsolidity/SourceReferenceFormatter.h @@ -0,0 +1,48 @@ +/* + 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. + */ + +#pragma once + +#include +#include + +namespace dev +{ + +class Exception; // forward + +namespace solidity +{ + +class Scanner; // forward + +struct SourceReferenceFormatter +{ +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/libsolidity/Types.cpp b/libsolidity/Types.cpp index 91dccb468..62324f8c2 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -89,9 +89,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..ba0b6ccf7 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -9,21 +9,11 @@ #include #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() { @@ -57,28 +47,50 @@ 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& exception) + { + SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Parser error", *scanner); + return -1; + } + + dev::solidity::NameAndTypeResolver resolver; + try { - src = dev::asString(dev::contents(infile)); + resolver.resolveNamesAndTypes(*ast.get()); } - std::cout << "Parsing..." << std::endl; - // @todo catch exception - dev::solidity::ASTPointer ast = dev::solidity::parseAST(src); + catch (DeclarationError const& exception) + { + SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Declaration error", *scanner); + return -1; + } + catch (TypeError const& exception) + { + SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Type error", *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; }