diff options
-rw-r--r-- | libsolidity/CompilerStack.cpp | 37 | ||||
-rw-r--r-- | libsolidity/CompilerStack.h | 22 | ||||
-rw-r--r-- | libsolidity/Exceptions.h | 11 | ||||
-rw-r--r-- | libsolidity/TypeChecker.h | 4 | ||||
-rw-r--r-- | solc/CommandLineInterface.cpp | 7 | ||||
-rw-r--r-- | solc/jsonCompiler.cpp | 34 |
6 files changed, 64 insertions, 51 deletions
diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index b8139187..e6b87264 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -77,6 +77,7 @@ void CompilerStack::reset(bool _keepSources, bool _addStandardSources) m_globalContext.reset(); m_sourceOrder.clear(); m_contracts.clear(); + m_errors.clear(); } bool CompilerStack::addSource(string const& _name, string const& _content, bool _isLibrary) @@ -94,8 +95,10 @@ void CompilerStack::setSource(string const& _sourceCode) addSource("", _sourceCode); } -void CompilerStack::parse() +bool CompilerStack::parse() { + m_errors.clear(); + for (auto& sourcePair: m_sources) { sourcePair.second.scanner->reset(); @@ -117,6 +120,7 @@ void CompilerStack::parse() resolver.resolveNamesAndTypes(*contract); m_contracts[contract->name()].contract = contract; } + InterfaceHandler interfaceHandler; for (Source const* source: m_sourceOrder) for (ASTPointer<ASTNode> const& node: source->ast->nodes()) @@ -127,20 +131,19 @@ void CompilerStack::parse() TypeChecker typeChecker; bool typesFine = typeChecker.checkTypeRequirements(*contract); if (!typesFine) - BOOST_THROW_EXCEPTION(*typeChecker.errors().front()); - //@todo extract warnings and errors - // store whether we had an error + m_errors += typeChecker.errors(); contract->setDevDocumentation(interfaceHandler.devDocumentation(*contract)); contract->setUserDocumentation(interfaceHandler.userDocumentation(*contract)); m_contracts[contract->name()].contract = contract; } - m_parseSuccessful = true; + m_parseSuccessful = m_errors.empty(); + return m_parseSuccessful; } -void CompilerStack::parse(string const& _sourceCode) +bool CompilerStack::parse(string const& _sourceCode) { setSource(_sourceCode); - parse(); + return parse(); } vector<string> CompilerStack::contractNames() const @@ -154,12 +157,11 @@ vector<string> CompilerStack::contractNames() const } -void CompilerStack::compile(bool _optimize, unsigned _runs) +bool CompilerStack::compile(bool _optimize, unsigned _runs) { if (!m_parseSuccessful) - parse(); - - //@todo do not compile or error (also in other places) + if (!parse()) + return false; map<ContractDefinition const*, eth::Assembly const*> compiledContracts; for (Source const* source: m_sourceOrder) @@ -180,13 +182,12 @@ void CompilerStack::compile(bool _optimize, unsigned _runs) cloneCompiler.compileClone(*contract, compiledContracts); compiledContract.cloneObject = cloneCompiler.assembledObject(); } + return true; } -eth::LinkerObject const& CompilerStack::compile(string const& _sourceCode, bool _optimize) +bool CompilerStack::compile(string const& _sourceCode, bool _optimize) { - parse(_sourceCode); - compile(_optimize); - return object(); + return parse(_sourceCode) && compile(_optimize); } void CompilerStack::link(const std::map<string, h160>& _libraries) @@ -325,12 +326,6 @@ size_t CompilerStack::functionEntryPoint( return 0; } -eth::LinkerObject CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize) -{ - CompilerStack stack; - return stack.compile(_sourceCode, _optimize); -} - tuple<int, int, int, int> CompilerStack::positionFromSourceLocation(SourceLocation const& _sourceLocation) const { int startLine; diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 4d9c1ec5..235bdaa2 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -54,6 +54,7 @@ class SourceUnit; class Compiler; class GlobalContext; class InterfaceHandler; +struct Error; enum class DocumentationType: uint8_t { @@ -85,18 +86,21 @@ public: bool addSource(std::string const& _name, std::string const& _content, bool _isLibrary = false); void setSource(std::string const& _sourceCode); /// Parses all source units that were added - void parse(); + /// @returns false on error. + bool parse(); /// Sets the given source code as the only source unit apart from standard sources and parses it. - void parse(std::string const& _sourceCode); + /// @returns false on error. + bool parse(std::string const& _sourceCode); /// Returns a list of the contract names in the sources. std::vector<std::string> contractNames() const; std::string defaultContractName() const; /// Compiles the source units that were previously added and parsed. - void compile(bool _optimize = false, unsigned _runs = 200); + /// @returns false on error. + bool compile(bool _optimize = false, unsigned _runs = 200); /// Parses and compiles the given source code. - /// @returns the compiled linker object - eth::LinkerObject const& compile(std::string const& _sourceCode, bool _optimize = false); + /// @returns false on error. + bool compile(std::string const& _sourceCode, bool _optimize = false); /// Inserts the given addresses into the linker objects of all compiled contracts. void link(std::map<std::string, h160> const& _libraries); @@ -152,15 +156,14 @@ public: FunctionDefinition const& _function ) const; - /// Compile the given @a _sourceCode to bytecode. If a scanner is provided, it is used for - /// scanning the source code - this is useful for printing exception information. - static eth::LinkerObject staticCompile(std::string const& _sourceCode, bool _optimize = false); - /// Helper function for logs printing. Do only use in error cases, it's quite expensive. /// line and columns are numbered starting from 1 with following order: /// start line, start column, end line, end column std::tuple<int, int, int, int> positionFromSourceLocation(SourceLocation const& _sourceLocation) const; + /// @returns the list of errors that occured during parsing and type checking. + std::vector<std::shared_ptr<Error const>> const& errors() const { return m_errors; } + private: /** * Information pertaining to one source unit, filled gradually during parsing and compilation. @@ -200,6 +203,7 @@ private: std::shared_ptr<GlobalContext> m_globalContext; std::vector<Source const*> m_sourceOrder; std::map<std::string const, Contract> m_contracts; + std::vector<std::shared_ptr<Error const>> m_errors; }; } diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index d5cb7eb5..645b368f 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -32,12 +32,15 @@ namespace dev namespace solidity { -struct ParserError: virtual Exception {}; -struct TypeError: virtual Exception {}; -struct DeclarationError: virtual Exception {}; +struct Error: virtual Exception {}; + +struct ParserError: virtual Error {}; +struct TypeError: virtual Error {}; +struct DeclarationError: virtual Error {}; +struct DocstringParsingError: virtual Error {}; + struct CompilerError: virtual Exception {}; struct InternalCompilerError: virtual Exception {}; -struct DocstringParsingError: virtual Exception {}; struct FatalError: virtual Exception {}; using errorSourceLocationInfo = std::pair<std::string, SourceLocation>; diff --git a/libsolidity/TypeChecker.h b/libsolidity/TypeChecker.h index 90e2a01b..cc539e22 100644 --- a/libsolidity/TypeChecker.h +++ b/libsolidity/TypeChecker.h @@ -47,7 +47,7 @@ public: bool checkTypeRequirements(ContractDefinition const& _contract); /// @returns the list of errors found during type checking. - std::vector<std::shared_ptr<Exception const>> const& errors() const { return m_errors; } + std::vector<std::shared_ptr<Error const>> 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; @@ -107,7 +107,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); - std::vector<std::shared_ptr<Exception const>> m_errors; + std::vector<std::shared_ptr<Error const>> m_errors; }; } diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index cfc8a5e0..587dcded 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -490,7 +490,12 @@ bool CommandLineInterface::processInput() // TODO: Perhaps we should not compile unless requested bool optimize = m_args.count("optimize") > 0; unsigned runs = m_args["optimize-runs"].as<unsigned>(); - m_compiler->compile(optimize, runs); + if (!m_compiler->compile(optimize, runs)) + { + for (auto const& error: m_compiler->errors()) + SourceReferenceFormatter::printExceptionInformation(cerr, *error, "Error", *m_compiler); + return false; + } m_compiler->link(m_libraries); } catch (ParserError const& _exception) diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp index d265ed9c..ba3e6912 100644 --- a/solc/jsonCompiler.cpp +++ b/solc/jsonCompiler.cpp @@ -46,10 +46,7 @@ string formatError(Exception const& _exception, string const& _name, CompilerSta { ostringstream errorOutput; SourceReferenceFormatter::printExceptionInformation(errorOutput, _exception, _name, _compiler); - - Json::Value output(Json::objectValue); - output["error"] = errorOutput.str(); - return Json::FastWriter().write(output); + return errorOutput.str(); } Json::Value functionHashes(ContractDefinition const& _contract) @@ -123,43 +120,52 @@ string compile(string _input, bool _optimize) sources[""] = _input; Json::Value output(Json::objectValue); + Json::Value errors(Json::arrayValue); CompilerStack compiler; try { - compiler.compile(_input, _optimize); + if (!compiler.compile(_input, _optimize)) + { + for (auto const& error: compiler.errors()) + errors.append(formatError(*error, "Error", compiler)); + } } catch (ParserError const& exception) { - return formatError(exception, "Parser error", compiler); + errors.append(formatError(exception, "Parser error", compiler)); } catch (DeclarationError const& exception) { - return formatError(exception, "Declaration error", compiler); + errors.append(formatError(exception, "Declaration error", compiler)); } catch (TypeError const& exception) { - return formatError(exception, "Type error", compiler); + errors.append(formatError(exception, "Type error", compiler)); } catch (CompilerError const& exception) { - return formatError(exception, "Compiler error", compiler); + errors.append(formatError(exception, "Compiler error", compiler)); } catch (InternalCompilerError const& exception) { - return formatError(exception, "Internal compiler error", compiler); + errors.append(formatError(exception, "Internal compiler error", compiler)); } catch (DocstringParsingError const& exception) { - return formatError(exception, "Documentation parsing error", compiler); + errors.append(formatError(exception, "Documentation parsing error", compiler)); } catch (Exception const& exception) { - output["error"] = "Exception during compilation: " + boost::diagnostic_information(exception); - return Json::FastWriter().write(output); + errors.append("Exception during compilation: " + boost::diagnostic_information(exception)); } catch (...) { - output["error"] = "Unknown exception during compilation."; + errors.append("Unknown exception during compilation."); + } + + if (errors.size() > 0) + { + output["errors"] = errors; return Json::FastWriter().write(output); } |