Error formatting.

This commit is contained in:
chriseth 2015-09-21 19:43:56 +02:00
parent 39d1e2bc06
commit 42c0009205
6 changed files with 64 additions and 51 deletions

View File

@ -77,6 +77,7 @@ void CompilerStack::reset(bool _keepSources, bool _addStandardSources)
m_globalContext.reset(); m_globalContext.reset();
m_sourceOrder.clear(); m_sourceOrder.clear();
m_contracts.clear(); m_contracts.clear();
m_errors.clear();
} }
bool CompilerStack::addSource(string const& _name, string const& _content, bool _isLibrary) bool CompilerStack::addSource(string const& _name, string const& _content, bool _isLibrary)
@ -94,8 +95,10 @@ void CompilerStack::setSource(string const& _sourceCode)
addSource("", _sourceCode); addSource("", _sourceCode);
} }
void CompilerStack::parse() bool CompilerStack::parse()
{ {
m_errors.clear();
for (auto& sourcePair: m_sources) for (auto& sourcePair: m_sources)
{ {
sourcePair.second.scanner->reset(); sourcePair.second.scanner->reset();
@ -117,6 +120,7 @@ void CompilerStack::parse()
resolver.resolveNamesAndTypes(*contract); resolver.resolveNamesAndTypes(*contract);
m_contracts[contract->name()].contract = contract; m_contracts[contract->name()].contract = contract;
} }
InterfaceHandler interfaceHandler; InterfaceHandler interfaceHandler;
for (Source const* source: m_sourceOrder) for (Source const* source: m_sourceOrder)
for (ASTPointer<ASTNode> const& node: source->ast->nodes()) for (ASTPointer<ASTNode> const& node: source->ast->nodes())
@ -127,20 +131,19 @@ void CompilerStack::parse()
TypeChecker typeChecker; TypeChecker typeChecker;
bool typesFine = typeChecker.checkTypeRequirements(*contract); bool typesFine = typeChecker.checkTypeRequirements(*contract);
if (!typesFine) if (!typesFine)
BOOST_THROW_EXCEPTION(*typeChecker.errors().front()); m_errors += typeChecker.errors();
//@todo extract warnings and errors
// store whether we had an error
contract->setDevDocumentation(interfaceHandler.devDocumentation(*contract)); contract->setDevDocumentation(interfaceHandler.devDocumentation(*contract));
contract->setUserDocumentation(interfaceHandler.userDocumentation(*contract)); contract->setUserDocumentation(interfaceHandler.userDocumentation(*contract));
m_contracts[contract->name()].contract = 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); setSource(_sourceCode);
parse(); return parse();
} }
vector<string> CompilerStack::contractNames() const 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) if (!m_parseSuccessful)
parse(); if (!parse())
return false;
//@todo do not compile or error (also in other places)
map<ContractDefinition const*, eth::Assembly const*> compiledContracts; map<ContractDefinition const*, eth::Assembly const*> compiledContracts;
for (Source const* source: m_sourceOrder) for (Source const* source: m_sourceOrder)
@ -180,13 +182,12 @@ void CompilerStack::compile(bool _optimize, unsigned _runs)
cloneCompiler.compileClone(*contract, compiledContracts); cloneCompiler.compileClone(*contract, compiledContracts);
compiledContract.cloneObject = cloneCompiler.assembledObject(); 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); return parse(_sourceCode) && compile(_optimize);
compile(_optimize);
return object();
} }
void CompilerStack::link(const std::map<string, h160>& _libraries) void CompilerStack::link(const std::map<string, h160>& _libraries)
@ -325,12 +326,6 @@ size_t CompilerStack::functionEntryPoint(
return 0; 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 tuple<int, int, int, int> CompilerStack::positionFromSourceLocation(SourceLocation const& _sourceLocation) const
{ {
int startLine; int startLine;

View File

@ -54,6 +54,7 @@ class SourceUnit;
class Compiler; class Compiler;
class GlobalContext; class GlobalContext;
class InterfaceHandler; class InterfaceHandler;
struct Error;
enum class DocumentationType: uint8_t enum class DocumentationType: uint8_t
{ {
@ -85,18 +86,21 @@ public:
bool addSource(std::string const& _name, std::string const& _content, bool _isLibrary = false); bool addSource(std::string const& _name, std::string const& _content, bool _isLibrary = false);
void setSource(std::string const& _sourceCode); void setSource(std::string const& _sourceCode);
/// Parses all source units that were added /// 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. /// 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. /// Returns a list of the contract names in the sources.
std::vector<std::string> contractNames() const; std::vector<std::string> contractNames() const;
std::string defaultContractName() const; std::string defaultContractName() const;
/// Compiles the source units that were previously added and parsed. /// 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. /// Parses and compiles the given source code.
/// @returns the compiled linker object /// @returns false on error.
eth::LinkerObject const& compile(std::string const& _sourceCode, bool _optimize = false); bool compile(std::string const& _sourceCode, bool _optimize = false);
/// Inserts the given addresses into the linker objects of all compiled contracts. /// Inserts the given addresses into the linker objects of all compiled contracts.
void link(std::map<std::string, h160> const& _libraries); void link(std::map<std::string, h160> const& _libraries);
@ -152,15 +156,14 @@ public:
FunctionDefinition const& _function FunctionDefinition const& _function
) const; ) 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. /// 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: /// line and columns are numbered starting from 1 with following order:
/// start line, start column, end line, end column /// start line, start column, end line, end column
std::tuple<int, int, int, int> positionFromSourceLocation(SourceLocation const& _sourceLocation) const; 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: private:
/** /**
* Information pertaining to one source unit, filled gradually during parsing and compilation. * Information pertaining to one source unit, filled gradually during parsing and compilation.
@ -200,6 +203,7 @@ private:
std::shared_ptr<GlobalContext> m_globalContext; std::shared_ptr<GlobalContext> m_globalContext;
std::vector<Source const*> m_sourceOrder; std::vector<Source const*> m_sourceOrder;
std::map<std::string const, Contract> m_contracts; std::map<std::string const, Contract> m_contracts;
std::vector<std::shared_ptr<Error const>> m_errors;
}; };
} }

View File

@ -32,12 +32,15 @@ namespace dev
namespace solidity namespace solidity
{ {
struct ParserError: virtual Exception {}; struct Error: virtual Exception {};
struct TypeError: virtual Exception {};
struct DeclarationError: virtual Exception {}; struct ParserError: virtual Error {};
struct TypeError: virtual Error {};
struct DeclarationError: virtual Error {};
struct DocstringParsingError: virtual Error {};
struct CompilerError: virtual Exception {}; struct CompilerError: virtual Exception {};
struct InternalCompilerError: virtual Exception {}; struct InternalCompilerError: virtual Exception {};
struct DocstringParsingError: virtual Exception {};
struct FatalError: virtual Exception {}; struct FatalError: virtual Exception {};
using errorSourceLocationInfo = std::pair<std::string, SourceLocation>; using errorSourceLocationInfo = std::pair<std::string, SourceLocation>;

View File

@ -47,7 +47,7 @@ public:
bool checkTypeRequirements(ContractDefinition const& _contract); bool checkTypeRequirements(ContractDefinition const& _contract);
/// @returns the list of errors found during type checking. /// @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. /// @returns the type of an expression and asserts that it is present.
TypePointer const& type(Expression const& _expression) const; 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. /// Runs type checks on @a _expression to infer its type and then checks that it is an LValue.
void requireLValue(Expression const& _expression); void requireLValue(Expression const& _expression);
std::vector<std::shared_ptr<Exception const>> m_errors; std::vector<std::shared_ptr<Error const>> m_errors;
}; };
} }

View File

@ -490,7 +490,12 @@ bool CommandLineInterface::processInput()
// TODO: Perhaps we should not compile unless requested // TODO: Perhaps we should not compile unless requested
bool optimize = m_args.count("optimize") > 0; bool optimize = m_args.count("optimize") > 0;
unsigned runs = m_args["optimize-runs"].as<unsigned>(); 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); m_compiler->link(m_libraries);
} }
catch (ParserError const& _exception) catch (ParserError const& _exception)

View File

@ -46,10 +46,7 @@ string formatError(Exception const& _exception, string const& _name, CompilerSta
{ {
ostringstream errorOutput; ostringstream errorOutput;
SourceReferenceFormatter::printExceptionInformation(errorOutput, _exception, _name, _compiler); SourceReferenceFormatter::printExceptionInformation(errorOutput, _exception, _name, _compiler);
return errorOutput.str();
Json::Value output(Json::objectValue);
output["error"] = errorOutput.str();
return Json::FastWriter().write(output);
} }
Json::Value functionHashes(ContractDefinition const& _contract) Json::Value functionHashes(ContractDefinition const& _contract)
@ -123,43 +120,52 @@ string compile(string _input, bool _optimize)
sources[""] = _input; sources[""] = _input;
Json::Value output(Json::objectValue); Json::Value output(Json::objectValue);
Json::Value errors(Json::arrayValue);
CompilerStack compiler; CompilerStack compiler;
try 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) catch (ParserError const& exception)
{ {
return formatError(exception, "Parser error", compiler); errors.append(formatError(exception, "Parser error", compiler));
} }
catch (DeclarationError const& exception) catch (DeclarationError const& exception)
{ {
return formatError(exception, "Declaration error", compiler); errors.append(formatError(exception, "Declaration error", compiler));
} }
catch (TypeError const& exception) catch (TypeError const& exception)
{ {
return formatError(exception, "Type error", compiler); errors.append(formatError(exception, "Type error", compiler));
} }
catch (CompilerError const& exception) catch (CompilerError const& exception)
{ {
return formatError(exception, "Compiler error", compiler); errors.append(formatError(exception, "Compiler error", compiler));
} }
catch (InternalCompilerError const& exception) catch (InternalCompilerError const& exception)
{ {
return formatError(exception, "Internal compiler error", compiler); errors.append(formatError(exception, "Internal compiler error", compiler));
} }
catch (DocstringParsingError const& exception) catch (DocstringParsingError const& exception)
{ {
return formatError(exception, "Documentation parsing error", compiler); errors.append(formatError(exception, "Documentation parsing error", compiler));
} }
catch (Exception const& exception) catch (Exception const& exception)
{ {
output["error"] = "Exception during compilation: " + boost::diagnostic_information(exception); errors.append("Exception during compilation: " + boost::diagnostic_information(exception));
return Json::FastWriter().write(output);
} }
catch (...) 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); return Json::FastWriter().write(output);
} }