diff options
author | LianaHus <liana@ethdev.com> | 2015-10-15 02:37:41 +0800 |
---|---|---|
committer | LianaHus <liana@ethdev.com> | 2015-10-15 02:37:41 +0800 |
commit | c3491e446964f366101f28e3d51ab59dd9aaa5b2 (patch) | |
tree | 75a261126d7c0eb7919db32603aea44e5fe443ba /libsolidity | |
parent | 8f7f22c5a6b1a71d7baff489b6425670550e8e8b (diff) | |
download | dexon-solidity-c3491e446964f366101f28e3d51ab59dd9aaa5b2.tar dexon-solidity-c3491e446964f366101f28e3d51ab59dd9aaa5b2.tar.gz dexon-solidity-c3491e446964f366101f28e3d51ab59dd9aaa5b2.tar.bz2 dexon-solidity-c3491e446964f366101f28e3d51ab59dd9aaa5b2.tar.lz dexon-solidity-c3491e446964f366101f28e3d51ab59dd9aaa5b2.tar.xz dexon-solidity-c3491e446964f366101f28e3d51ab59dd9aaa5b2.tar.zst dexon-solidity-c3491e446964f366101f28e3d51ab59dd9aaa5b2.zip |
errors instead of exceptions
Conflicts:
libsolidity/CompilerStack.cpp
libsolidity/NameAndTypeResolver.cpp
libsolidity/NameAndTypeResolver.h
libsolidity/TypeChecker.cpp
test/libsolidity/SolidityNameAndTypeResolution.cpp
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/CompilerContext.cpp | 2 | ||||
-rw-r--r-- | libsolidity/CompilerStack.cpp | 32 | ||||
-rw-r--r-- | libsolidity/CompilerStack.h | 1 | ||||
-rw-r--r-- | libsolidity/Exceptions.h | 36 | ||||
-rw-r--r-- | libsolidity/NameAndTypeResolver.cpp | 240 | ||||
-rw-r--r-- | libsolidity/NameAndTypeResolver.h | 42 | ||||
-rw-r--r-- | libsolidity/Parser.cpp | 86 | ||||
-rw-r--r-- | libsolidity/Parser.h | 13 | ||||
-rw-r--r-- | libsolidity/TypeChecker.cpp | 30 | ||||
-rw-r--r-- | libsolidity/TypeChecker.h | 10 |
10 files changed, 337 insertions, 155 deletions
diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index fa7f9c77..0ba7af5b 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -137,7 +137,7 @@ ModifierDefinition const& CompilerContext::functionModifier(string const& _name) if (modifier->name() == _name) return *modifier.get(); BOOST_THROW_EXCEPTION(InternalCompilerError() - << errinfo_comment("Function modifier " + _name + " not found.")); + << errinfo_comment("Function modifier " + _name + " not found.")); } unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declaration) const diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 519f785b..3887999a 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -97,30 +97,41 @@ void CompilerStack::setSource(string const& _sourceCode) bool CompilerStack::parse() { + // todo not sure about clear. can contain warnings m_errors.clear(); for (auto& sourcePair: m_sources) { sourcePair.second.scanner->reset(); - sourcePair.second.ast = Parser().parse(sourcePair.second.scanner); + sourcePair.second.ast = Parser(m_errors).parse(sourcePair.second.scanner); // todo check for errors } + if (!Error::containsOnlyWarnings(m_errors)) + // errors while parsing. sould stop before type checking + return false; + resolveImports(); m_globalContext = make_shared<GlobalContext>(); + bool success = true; NameAndTypeResolver resolver(m_globalContext->declarations(), m_errors); for (Source const* source: m_sourceOrder) - resolver.registerDeclarations(*source->ast); + success = success && resolver.registerDeclarations(*source->ast); for (Source const* source: m_sourceOrder) for (ASTPointer<ASTNode> const& node: source->ast->nodes()) if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) { m_globalContext->setCurrentContract(*contract); - resolver.updateDeclaration(*m_globalContext->currentThis()); - resolver.updateDeclaration(*m_globalContext->currentSuper()); - resolver.resolveNamesAndTypes(*contract); + success = success && resolver.updateDeclaration(*m_globalContext->currentThis()); + success = success && resolver.updateDeclaration(*m_globalContext->currentSuper()); + success = success && resolver.resolveNamesAndTypes(*contract); m_contracts[contract->name()].contract = contract; } + if (!success) + { + m_parseSuccessful = false; + return m_parseSuccessful; + } InterfaceHandler interfaceHandler; bool typesFine = true; for (Source const* source: m_sourceOrder) @@ -137,6 +148,7 @@ bool CompilerStack::parse() } else typesFine = false; + m_contracts[contract->name()].contract = contract; m_errors += typeChecker.errors(); } @@ -253,9 +265,8 @@ string const& CompilerStack::metadata(string const& _contractName, Documentation if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - Contract const& currentContract = contract(_contractName); - std::unique_ptr<string const>* doc; + Contract const& currentContract = contract(_contractName); // checks wheather we already have the documentation switch (_type) @@ -346,9 +357,10 @@ void CompilerStack::resolveImports() if (!m_sources.count(id)) BOOST_THROW_EXCEPTION( Error(Error::Type::ParserError) - << errinfo_sourceLocation(import->location()) - << errinfo_comment("Source not found.") + << errinfo_sourceLocation(import->location()) + << errinfo_comment("Source not found.") ); + toposort(&m_sources[id]); } sourceOrder.push_back(_source); @@ -414,10 +426,12 @@ CompilerStack::Source const& CompilerStack::source(string const& _sourceName) co auto it = m_sources.find(_sourceName); if (it == m_sources.end()) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Given source file not found.")); + return it->second; } CompilerStack::Contract::Contract(): interfaceHandler(make_shared<InterfaceHandler>()) {} + } } diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 5b128868..e47f558b 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -167,6 +167,7 @@ public: /// @returns the list of errors that occured during parsing and type checking. ErrorList const& errors() const { return m_errors; } + private: /** * Information pertaining to one source unit, filled gradually during parsing and compilation. diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index 5a1b827c..92c009ef 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -26,11 +26,18 @@ #include <utility> #include <libdevcore/Exceptions.h> #include <libevmasm/SourceLocation.h> +#include <libsolidity/Utils.h> namespace dev { namespace solidity { +class Error; +using ErrorList = std::vector<std::shared_ptr<Error const>>; + +struct CompilerError: virtual Exception {}; +struct InternalCompilerError: virtual Exception {}; +struct fatalError: virtual Exception {}; //todo rename to FatalError class Error: virtual public Exception { @@ -41,7 +48,6 @@ public: DocstringParsingError, ParserError, TypeError, - Warning }; @@ -65,22 +71,39 @@ public: m_typeName = "Warning"; break; default: - m_typeName = "Error"; + solAssert(false, ""); break; } } - Type const type() { return m_type; } const + Type type() const { return m_type; } std::string const& typeName() const { return m_typeName; } + + /// helper functions + static Error const* containsErrorOfType(ErrorList const& _list, Error::Type _type) + { + for (auto e: _list) + { + if(e->type() == _type) + return e.get(); + } + return nullptr; + } + static bool containsOnlyWarnings(ErrorList const& _list) + { + for (auto e: _list) + { + if(e->type() != Type::Warning) + return false; + } + return true; + } private: Type m_type; std::string m_typeName; }; -struct CompilerError: virtual Exception {}; -struct InternalCompilerError: virtual Exception {}; -struct FatalError: virtual Exception {}; using errorSourceLocationInfo = std::pair<std::string, SourceLocation>; @@ -96,7 +119,6 @@ public: }; -using ErrorList = std::vector<std::shared_ptr<Error const>>; using errinfo_sourceLocation = boost::error_info<struct tag_sourceLocation, SourceLocation>; using errinfo_secondarySourceLocation = boost::error_info<struct tag_secondarySourceLocation, SecondarySourceLocation>; diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 3591c07a..934be0e3 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -42,81 +42,105 @@ NameAndTypeResolver::NameAndTypeResolver( m_scopes[nullptr].registerDeclaration(*declaration); } -void NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit) +bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit) { // The helper registers all declarations in m_scopes as a side-effect of its construction. - DeclarationRegistrationHelper registrar(m_scopes, _sourceUnit); + try + { + DeclarationRegistrationHelper registrar(m_scopes, _sourceUnit, m_errors); + } + catch (fatalError) + { + return false; + } + return true; } -void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) +bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) { - m_currentScope = &m_scopes[nullptr]; + try + { + m_currentScope = &m_scopes[nullptr]; - for (ASTPointer<InheritanceSpecifier> const& baseContract: _contract.baseContracts()) - ReferencesResolver resolver(*baseContract, *this, &_contract, nullptr); + for (ASTPointer<InheritanceSpecifier> const& baseContract: _contract.baseContracts()) + ReferencesResolver resolver(*baseContract, *this, &_contract, nullptr); - m_currentScope = &m_scopes[&_contract]; + m_currentScope = &m_scopes[&_contract]; - linearizeBaseContracts(_contract); - std::vector<ContractDefinition const*> properBases( - ++_contract.annotation().linearizedBaseContracts.begin(), - _contract.annotation().linearizedBaseContracts.end() - ); + linearizeBaseContracts(_contract); + std::vector<ContractDefinition const*> properBases( + ++_contract.annotation().linearizedBaseContracts.begin(), + _contract.annotation().linearizedBaseContracts.end() + ); - for (ContractDefinition const* base: properBases) - importInheritedScope(*base); + for (ContractDefinition const* base: properBases) + importInheritedScope(*base); - for (ASTPointer<StructDefinition> const& structDef: _contract.definedStructs()) - ReferencesResolver resolver(*structDef, *this, &_contract, nullptr); - for (ASTPointer<EnumDefinition> const& enumDef: _contract.definedEnums()) - ReferencesResolver resolver(*enumDef, *this, &_contract, nullptr); - for (ASTPointer<VariableDeclaration> const& variable: _contract.stateVariables()) - ReferencesResolver resolver(*variable, *this, &_contract, nullptr); - for (ASTPointer<EventDefinition> const& event: _contract.events()) - ReferencesResolver resolver(*event, *this, &_contract, nullptr); + for (ASTPointer<StructDefinition> const& structDef: _contract.definedStructs()) + ReferencesResolver resolver(*structDef, *this, &_contract, nullptr); + for (ASTPointer<EnumDefinition> const& enumDef: _contract.definedEnums()) + ReferencesResolver resolver(*enumDef, *this, &_contract, nullptr); + for (ASTPointer<VariableDeclaration> const& variable: _contract.stateVariables()) + ReferencesResolver resolver(*variable, *this, &_contract, nullptr); + for (ASTPointer<EventDefinition> const& event: _contract.events()) + ReferencesResolver resolver(*event, *this, &_contract, nullptr); - // these can contain code, only resolve parameters for now - for (ASTPointer<ModifierDefinition> const& modifier: _contract.functionModifiers()) - { - m_currentScope = &m_scopes[modifier.get()]; - ReferencesResolver resolver(*modifier, *this, &_contract, nullptr); - } - for (ASTPointer<FunctionDefinition> const& function: _contract.definedFunctions()) - { - m_currentScope = &m_scopes[function.get()]; - ReferencesResolver referencesResolver( - *function, - *this, - &_contract, - function->returnParameterList().get() - ); - } + // these can contain code, only resolve parameters for now + for (ASTPointer<ModifierDefinition> const& modifier: _contract.functionModifiers()) + { + m_currentScope = &m_scopes[modifier.get()]; + ReferencesResolver resolver(*modifier, *this, &_contract, nullptr); + } + for (ASTPointer<FunctionDefinition> const& function: _contract.definedFunctions()) + { + m_currentScope = &m_scopes[function.get()]; + ReferencesResolver referencesResolver( + *function, + *this, + &_contract, + function->returnParameterList().get() + ); + } - m_currentScope = &m_scopes[&_contract]; + m_currentScope = &m_scopes[&_contract]; - // now resolve references inside the code - for (ASTPointer<ModifierDefinition> const& modifier: _contract.functionModifiers()) - { - m_currentScope = &m_scopes[modifier.get()]; - ReferencesResolver resolver(*modifier, *this, &_contract, nullptr, true); + // now resolve references inside the code + for (ASTPointer<ModifierDefinition> const& modifier: _contract.functionModifiers()) + { + m_currentScope = &m_scopes[modifier.get()]; + ReferencesResolver resolver(*modifier, *this, &_contract, nullptr, true); + } + for (ASTPointer<FunctionDefinition> const& function: _contract.definedFunctions()) + { + m_currentScope = &m_scopes[function.get()]; + ReferencesResolver referencesResolver( + *function, + *this, + &_contract, + function->returnParameterList().get(), + true + ); + } } - for (ASTPointer<FunctionDefinition> const& function: _contract.definedFunctions()) + catch (fatalError const& _e) { - m_currentScope = &m_scopes[function.get()]; - ReferencesResolver referencesResolver( - *function, - *this, - &_contract, - function->returnParameterList().get(), - true - ); + return false; } + return true; } -void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration) +bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration) { - m_scopes[nullptr].registerDeclaration(_declaration, false, true); - solAssert(_declaration.scope() == nullptr, "Updated declaration outside global scope."); + try + { + m_scopes[nullptr].registerDeclaration(_declaration, false, true); + solAssert(_declaration.scope() == nullptr, "Updated declaration outside global scope."); + } + catch(fatalError _error) + { + return false; + } + return true; } vector<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const @@ -164,11 +188,8 @@ vector<Declaration const*> NameAndTypeResolver::cleanedDeclarations( FunctionType functionType(functionDefinition); for (auto parameter: functionType.parameterTypes() + functionType.returnParameterTypes()) if (!parameter) - BOOST_THROW_EXCEPTION( - Error(Error::Type::DeclarationError) << - errinfo_sourceLocation(_identifier.location()) << - errinfo_comment("Function type can not be used in this context") - ); + reportFatalDeclarationError(_identifier.location(), "Function type can not be used in this context"); + if (uniqueFunctions.end() == find_if( uniqueFunctions.begin(), uniqueFunctions.end(), @@ -194,7 +215,7 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base) m_currentScope->registerDeclaration(*declaration); } -void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) const +void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) { // order in the lists is from derived to base // list of lists to linearize, the last element is the list of direct bases @@ -204,19 +225,19 @@ void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) Identifier const& baseName = baseSpecifier->name(); auto base = dynamic_cast<ContractDefinition const*>(baseName.annotation().referencedDeclaration); if (!base) - BOOST_THROW_EXCEPTION(baseName.createTypeError("Contract expected.")); + reportFatalTypeError(baseName.createTypeError("Contract expected.")); // "push_front" has the effect that bases mentioned later can overwrite members of bases // mentioned earlier input.back().push_front(base); vector<ContractDefinition const*> const& basesBases = base->annotation().linearizedBaseContracts; if (basesBases.empty()) - BOOST_THROW_EXCEPTION(baseName.createTypeError("Definition of base has to precede definition of derived contract")); + reportFatalTypeError(baseName.createTypeError("Definition of base has to precede definition of derived contract")); input.push_front(list<ContractDefinition const*>(basesBases.begin(), basesBases.end())); } input.back().push_front(&_contract); vector<ContractDefinition const*> result = cThreeMerge(input); if (result.empty()) - BOOST_THROW_EXCEPTION(_contract.createTypeError("Linearization of inheritance graph impossible")); + reportFatalTypeError(_contract.createTypeError("Linearization of inheritance graph impossible")); _contract.annotation().linearizedBaseContracts = result; _contract.annotation().contractDependencies.insert(result.begin() + 1, result.end()); } @@ -272,9 +293,53 @@ vector<_T const*> NameAndTypeResolver::cThreeMerge(list<list<_T const*>>& _toMer return result; } -DeclarationRegistrationHelper::DeclarationRegistrationHelper(map<ASTNode const*, DeclarationContainer>& _scopes, - ASTNode& _astRoot): - m_scopes(_scopes), m_currentScope(nullptr) +void NameAndTypeResolver::reportDeclarationError( + SourceLocation _sourceLoction, + string const& _description, + SourceLocation _secondarySourceLocation = SourceLocation(), + string const& _secondaryDescription = "" +) +{ + auto err = make_shared<Error>(Error::Type::DeclarationError); // todo remove Error? + *err << + errinfo_sourceLocation(_sourceLoction) << + errinfo_comment(_description) << + errinfo_secondarySourceLocation( + SecondarySourceLocation().append(_secondaryDescription, _secondarySourceLocation) + ); + + m_errors.push_back(err); +} + +void NameAndTypeResolver::reportFatalDeclarationError( + SourceLocation _sourceLoction, + string _description +) +{ + reportDeclarationError(_sourceLoction, _description); + BOOST_THROW_EXCEPTION(fatalError()); +} + +void NameAndTypeResolver::reportTypeError(Error _e) +{ + m_errors.push_back(make_shared<Error>(_e)); +} + +void NameAndTypeResolver::reportFatalTypeError(Error _e) +{ + reportTypeError(_e); + BOOST_THROW_EXCEPTION(fatalError()); +} + + +DeclarationRegistrationHelper::DeclarationRegistrationHelper( + map<ASTNode const*, DeclarationContainer>& _scopes, + ASTNode& _astRoot, + ErrorList& _errors +): + m_scopes(_scopes), + m_currentScope(nullptr), + m_errors(_errors) { _astRoot.accept(*this); } @@ -409,13 +474,11 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio secondDeclarationLocation = _declaration.location(); } - BOOST_THROW_EXCEPTION( - Error(Error::Type::DeclarationError) << - errinfo_sourceLocation(secondDeclarationLocation) << - errinfo_comment("Identifier already declared.") << - errinfo_secondarySourceLocation( - SecondarySourceLocation().append("The previous declaration is here:", firstDeclarationLocation) - ) + declarationError( + secondDeclarationLocation, + "Identifier already declared.", + firstDeclarationLocation, + "The previous declaration is here:" ); } @@ -440,5 +503,32 @@ string DeclarationRegistrationHelper::currentCanonicalName() const return ret; } +void DeclarationRegistrationHelper::declarationError( + SourceLocation _sourceLoction, + string const& _description, + SourceLocation _secondarySourceLocation = SourceLocation(), + string const& _secondaryDescription = "" +) +{ + auto err = make_shared<Error>(Error::Type::DeclarationError); + *err << + errinfo_sourceLocation(_sourceLoction) << + errinfo_comment(_description) << + errinfo_secondarySourceLocation( + SecondarySourceLocation().append(_secondaryDescription, _secondarySourceLocation) + ); + + m_errors.push_back(err); +} + +void DeclarationRegistrationHelper::fatalDeclarationError( + SourceLocation _sourceLoction, + string const& _description +) +{ + declarationError(_sourceLoction, _description); + BOOST_THROW_EXCEPTION(fatalError()); +} + } } diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index d5afb29a..9587fcfe 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -44,12 +44,15 @@ class NameAndTypeResolver: private boost::noncopyable public: NameAndTypeResolver(std::vector<Declaration const*> const& _globals, ErrorList& _errors); /// Registers all declarations found in the source unit. - void registerDeclarations(SourceUnit& _sourceUnit); + /// @returns false in case of type error. + bool registerDeclarations(SourceUnit& _sourceUnit); /// Resolves all names and types referenced from the given contract. - void resolveNamesAndTypes(ContractDefinition& _contract); + /// @returns false in case of type error. + bool resolveNamesAndTypes(ContractDefinition& _contract); /// Updates the given global declaration (used for "this"). Not to be used with declarations /// that create their own scope. - void updateDeclaration(Declaration const& _declaration); + /// @returns false in case of type error. + bool updateDeclaration(Declaration const& _declaration); /// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted, /// the global scope is used (i.e. the one containing only the contract). @@ -66,7 +69,7 @@ public: Declaration const* pathFromCurrentScope(std::vector<ASTString> const& _path, bool _recursive = true) const; /// returns the vector of declarations without repetitions - static std::vector<Declaration const*> cleanedDeclarations( + std::vector<Declaration const*> cleanedDeclarations( Identifier const& _identifier, std::vector<Declaration const*> const& _declarations ); @@ -78,8 +81,8 @@ private: /// into the current scope if they are not present already. void importInheritedScope(ContractDefinition const& _base); - /// Computes "C3-Linearization" of base contracts and stores it inside the contract. - void linearizeBaseContracts(ContractDefinition& _contract) const; + /// Computes "C3-Linearization" of base contracts and stores it inside the contract. Reports errors if any + void linearizeBaseContracts(ContractDefinition& _contract); /// Computes the C3-merge of the given list of lists of bases. /// @returns the linearized vector or an empty vector if linearization is not possible. template <class _T> @@ -90,6 +93,21 @@ private: /// not contain code. std::map<ASTNode const*, DeclarationContainer> m_scopes; + // creates the Declaration error and adds it in the errors list + void reportDeclarationError( + SourceLocation _sourceLoction, + std::string const& _description, + SourceLocation _secondarySourceLocation, + std::string const& _secondaryDescription + ); + // creates the Declaration error and adds it in the errors list and throws FatalError + void reportFatalDeclarationError(SourceLocation _sourceLoction, std::string _description); + + // creates the Declaration error and adds it in the errors list + void reportTypeError(Error _e); + // creates the Declaration error and adds it in the errors list and throws FatalError + void reportFatalTypeError(Error _e); + DeclarationContainer* m_currentScope = nullptr; ErrorList& m_errors; }; @@ -101,7 +119,7 @@ private: class DeclarationRegistrationHelper: private ASTVisitor { public: - DeclarationRegistrationHelper(std::map<ASTNode const*, DeclarationContainer>& _scopes, ASTNode& _astRoot); + DeclarationRegistrationHelper(std::map<ASTNode const*, DeclarationContainer>& _scopes, ASTNode& _astRoot, ErrorList& _errors); private: bool visit(ContractDefinition& _contract) override; @@ -126,10 +144,20 @@ private: /// @returns the canonical name of the current scope. std::string currentCanonicalName() const; + // creates the Declaration error and adds it in the errors list + void declarationError( + SourceLocation _sourceLoction, + std::string const& _description, + SourceLocation _secondarySourceLocation, + std::string const& _secondaryDescription + ); + // creates the Declaration error and adds it in the errors list and throws FatalError + void fatalDeclarationError(SourceLocation _sourceLoction, std::string const& _description); std::map<ASTNode const*, DeclarationContainer>& m_scopes; Declaration const* m_currentScope; VariableScope* m_currentFunction; + ErrorList& m_errors; }; } diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index ce13098e..491af369 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -66,25 +66,35 @@ private: ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner) { - m_scanner = _scanner; - ASTNodeFactory nodeFactory(*this); - vector<ASTPointer<ASTNode>> nodes; - while (m_scanner->currentToken() != Token::EOS) - { - switch (auto token = m_scanner->currentToken()) + try{ + m_scanner = _scanner; + ASTNodeFactory nodeFactory(*this); + vector<ASTPointer<ASTNode>> nodes; + while (m_scanner->currentToken() != Token::EOS) { - case Token::Import: - nodes.push_back(parseImportDirective()); - break; - case Token::Contract: - case Token::Library: - nodes.push_back(parseContractDefinition(token == Token::Library)); - break; - default: - BOOST_THROW_EXCEPTION(createParserError(std::string("Expected import directive or contract definition."))); + switch (auto token = m_scanner->currentToken()) + { + case Token::Import: + nodes.push_back(parseImportDirective()); + break; + case Token::Contract: + case Token::Library: + nodes.push_back(parseContractDefinition(token == Token::Library)); + break; + default: + fatalParserError(std::string("Expected import directive or contract definition.")); + } } + return nodeFactory.createNode<SourceUnit>(nodes); + } + catch(fatalError const& _error) + { + return nullptr; + } + catch(Exception const& _e) + { + return nullptr; } - return nodeFactory.createNode<SourceUnit>(nodes); } std::shared_ptr<const string> const& Parser::sourceName() const @@ -107,7 +117,7 @@ ASTPointer<ImportDirective> Parser::parseImportDirective() ASTNodeFactory nodeFactory(*this); expectToken(Token::Import); if (m_scanner->currentToken() != Token::StringLiteral) - BOOST_THROW_EXCEPTION(createParserError("Expected string literal (URL).")); + fatalParserError(std::string("Expected string literal (URL).")); ASTPointer<ASTString> url = getLiteralAndAdvance(); nodeFactory.markEndPosition(); expectToken(Token::Semicolon); @@ -165,7 +175,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary) else if (currentTokenValue == Token::Event) events.push_back(parseEventDefinition()); else - BOOST_THROW_EXCEPTION(createParserError("Function, variable, struct or modifier declaration expected.")); + fatalParserError(std::string("Function, variable, struct or modifier declaration expected.")); } nodeFactory.markEndPosition(); expectToken(Token::RBrace); @@ -249,7 +259,7 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const* else if (Token::isVisibilitySpecifier(token)) { if (visibility != Declaration::Visibility::Default) - BOOST_THROW_EXCEPTION(createParserError("Multiple visibility specifiers.")); + fatalParserError(std::string("Multiple visibility specifiers.")); visibility = parseVisibilitySpecifier(token); } else @@ -326,7 +336,7 @@ ASTPointer<EnumDefinition> Parser::parseEnumDefinition() break; expectToken(Token::Comma); if (m_scanner->currentToken() != Token::Identifier) - BOOST_THROW_EXCEPTION(createParserError("Expected Identifier after ','")); + fatalParserError(std::string("Expected Identifier after ','")); } nodeFactory.markEndPosition(); @@ -362,7 +372,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration( if (_options.isStateVariable && Token::isVariableVisibilitySpecifier(token)) { if (visibility != Declaration::Visibility::Default) - BOOST_THROW_EXCEPTION(createParserError("Visibility already specified.")); + fatalParserError(std::string("Visibility already specified.")); visibility = parseVisibilitySpecifier(token); } else @@ -374,9 +384,9 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration( else if (_options.allowLocationSpecifier && Token::isLocationSpecifier(token)) { if (location != VariableDeclaration::Location::Default) - BOOST_THROW_EXCEPTION(createParserError("Location already specified.")); + fatalParserError(std::string("Location already specified.")); if (!type) - BOOST_THROW_EXCEPTION(createParserError("Location specifier needs explicit type name.")); + fatalParserError(std::string("Location specifier needs explicit type name.")); location = ( token == Token::Memory ? VariableDeclaration::Location::Memory : @@ -513,7 +523,7 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) else if (token == Token::Var) { if (!_allowVar) - BOOST_THROW_EXCEPTION(createParserError("Expected explicit type name.")); + fatalParserError(std::string("Expected explicit type name.")); m_scanner->next(); } else if (token == Token::Mapping) @@ -532,7 +542,7 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) type = nodeFactory.createNode<UserDefinedTypeName>(identifierPath); } else - BOOST_THROW_EXCEPTION(createParserError("Expected type name")); + fatalParserError(std::string("Expected type name")); if (type) // Parse "[...]" postfixes for arrays. @@ -555,7 +565,7 @@ ASTPointer<Mapping> Parser::parseMapping() expectToken(Token::Mapping); expectToken(Token::LParen); if (!Token::isElementaryTypeName(m_scanner->currentToken())) - BOOST_THROW_EXCEPTION(createParserError("Expected elementary type name for mapping key type")); + fatalParserError(std::string("Expected elementary type name for mapping key type")); ASTPointer<ElementaryTypeName> keyType; keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(m_scanner->currentToken()); m_scanner->next(); @@ -1011,7 +1021,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression() m_scanner->next(); } else - BOOST_THROW_EXCEPTION(createParserError("Expected primary expression.")); + fatalParserError(std::string("Expected primary expression.")); break; } return expression; @@ -1122,7 +1132,7 @@ ASTPointer<Expression> Parser::expressionFromIndexAccessStructure( void Parser::expectToken(Token::Value _value) { if (m_scanner->currentToken() != _value) - BOOST_THROW_EXCEPTION(createParserError(string("Expected token ") + string(Token::name(_value)))); + fatalParserError(std::string(string("Expected token ") + string(Token::name(_value)))); m_scanner->next(); } @@ -1130,7 +1140,7 @@ Token::Value Parser::expectAssignmentOperator() { Token::Value op = m_scanner->currentToken(); if (!Token::isAssignmentOp(op)) - BOOST_THROW_EXCEPTION(createParserError("Expected assignment operator")); + fatalParserError(std::string("Expected assignment operator")); m_scanner->next(); return op; } @@ -1138,7 +1148,7 @@ Token::Value Parser::expectAssignmentOperator() ASTPointer<ASTString> Parser::expectIdentifierToken() { if (m_scanner->currentToken() != Token::Identifier) - BOOST_THROW_EXCEPTION(createParserError("Expected identifier")); + fatalParserError(std::string("Expected identifier")); return getLiteralAndAdvance(); } @@ -1156,13 +1166,21 @@ ASTPointer<ParameterList> Parser::createEmptyParameterList() return nodeFactory.createNode<ParameterList>(vector<ASTPointer<VariableDeclaration>>()); } -Error Parser::createParserError(string const& _description) const +void Parser::parserError(string const& _description) { - return Error(Error::Type::ParserError) << - errinfo_sourceLocation(SourceLocation(position(), position(), sourceName())) << - errinfo_comment(_description); + auto err = make_shared<Error>(Error::Type::ParserError); + *err << + errinfo_sourceLocation(SourceLocation(position(), position(), sourceName())) << + errinfo_comment(_description); + + m_errors.push_back(err); } +void Parser::fatalParserError(string const& _description) +{ + parserError(_description); + BOOST_THROW_EXCEPTION(fatalError()); +} } } diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index c9acb47d..3fc3768e 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -34,7 +34,8 @@ class Scanner; class Parser { public: - Parser() {} + Parser(ErrorList& errors): + m_errors(errors){}; ASTPointer<SourceUnit> parse(std::shared_ptr<Scanner> const& _scanner); std::shared_ptr<std::string const> const& sourceName() const; @@ -145,13 +146,19 @@ private: /// Creates an empty ParameterList at the current location (used if parameters can be omitted). ASTPointer<ParameterList> createEmptyParameterList(); - /// Creates a @ref ParserError exception and annotates it with the current position and the + /// Creates a @ref ParserError and annotates it with the current position and the /// given @a _description. - Error createParserError(std::string const& _description) const; + void parserError(std::string const& _description); + + /// Creates a @ref ParserError and annotates it with the current position and the + /// given @a _description. Throws the FatalError. + void fatalParserError(std::string const& _description); std::shared_ptr<Scanner> m_scanner; /// Flag that signifies whether '_' is parsed as a PlaceholderStatement or a regular identifier. bool m_insideModifier = false; + /// The reference to the list of errors and warning to add errors/warnings during parsing + ErrorList& m_errors; }; } diff --git a/libsolidity/TypeChecker.cpp b/libsolidity/TypeChecker.cpp index e3264429..cc7ad2f3 100644 --- a/libsolidity/TypeChecker.cpp +++ b/libsolidity/TypeChecker.cpp @@ -36,24 +36,26 @@ bool TypeChecker::checkTypeRequirements(const ContractDefinition& _contract) { visit(_contract); } - catch (FatalError const&) + catch (fatalError const&) { // We got a fatal error which required to stop further type checking, but we can // continue normally from here. if (m_errors.empty()) throw; // Something is weird here, rather throw again. } - bool success = true; - for (auto const& it: m_errors) - { - Error const& e = dynamic_cast<Error const&>(it.get()); - if (e.type() != Error::Type::Warning) - { - success = false; - break; - } - } - return success; + +return Error::containsOnlyWarnings(m_errors); +// bool success = true; +// for (auto const& it: m_errors) +// { +// auto e = dynamic_cast<Error const*>(it.get()); +// if (e->type() != Error::Type::Warning) +// { +// success = false; +// break; +// } +// } +// return success; } TypePointer const& TypeChecker::type(Expression const& _expression) const @@ -1255,7 +1257,7 @@ void TypeChecker::requireLValue(Expression const& _expression) void TypeChecker::typeError(ASTNode const& _node, string const& _description) { - auto err = make_shared<Error>(Error(Error::Type::TypeError));; + auto err = make_shared<Error>(Error::Type::TypeError); *err << errinfo_sourceLocation(_node.location()) << errinfo_comment(_description); @@ -1266,5 +1268,5 @@ void TypeChecker::typeError(ASTNode const& _node, string const& _description) void TypeChecker::fatalTypeError(ASTNode const& _node, string const& _description) { typeError(_node, _description); - BOOST_THROW_EXCEPTION(FatalError()); + BOOST_THROW_EXCEPTION(fatalError()); } diff --git a/libsolidity/TypeChecker.h b/libsolidity/TypeChecker.h index c654c698..de095e3b 100644 --- a/libsolidity/TypeChecker.h +++ b/libsolidity/TypeChecker.h @@ -42,26 +42,26 @@ namespace solidity class TypeChecker: private ASTConstVisitor { public: + /// @_errors the reference to the list of errors and warnings to add them found during type checking. + TypeChecker(ErrorList& _errors): m_errors(_errors) {} + /// Performs type checking on the given contract and all of its sub-nodes. /// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings bool checkTypeRequirements(ContractDefinition const& _contract); - /// @returns the list of errors and warnings found during type checking. - ErrorList const& errors() const { return m_errors; } - /// @returns the type of an expression and asserts that it is present. TypePointer const& type(Expression const& _expression) const; /// @returns the type of the given variable and throws if the type is not present /// (this can happen for variables with non-explicit types before their types are resolved) TypePointer const& type(VariableDeclaration const& _variable) const; +private: /// Adds a new error to the list of errors. void typeError(ASTNode const& _node, std::string const& _description); /// Adds a new error to the list of errors and throws to abort type checking. void fatalTypeError(ASTNode const& _node, std::string const& _description); -private: virtual bool visit(ContractDefinition const& _contract) override; /// Checks that two functions defined in this contract with the same name have different /// arguments and that there is at most one constructor. @@ -114,7 +114,7 @@ private: /// Runs type checks on @a _expression to infer its type and then checks that it is an LValue. void requireLValue(Expression const& _expression); - ErrorList m_errors; + ErrorList& m_errors; }; } |