From 04c8d8bdc08398089225c3e134df8ad533c887b8 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 3 Dec 2014 18:52:28 +0100 Subject: [PATCH] Improved external interface for multi-source and multi-contract compilation. --- alethzero/MainWin.cpp | 2 +- libsolidity/BaseTypes.h | 7 ++- libsolidity/CompilerStack.cpp | 12 +++++- libsolidity/CompilerStack.h | 3 ++ libsolidity/Exceptions.h | 1 - libsolidity/Parser.cpp | 11 ++++- libsolidity/Parser.h | 1 + libsolidity/Scanner.cpp | 10 +---- libsolidity/Scanner.h | 3 ++ libsolidity/SourceReferenceFormatter.cpp | 41 +++++++----------- libsolidity/SourceReferenceFormatter.h | 4 +- libweb3jsonrpc/WebThreeStubServer.cpp | 2 +- mix/ConstantCompilationModel.cpp | 2 +- solc/main.cpp | 55 +++++++++++++++--------- test/solidityExpressionCompiler.cpp | 1 + 15 files changed, 88 insertions(+), 67 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4a32f66b2..4126fbf08 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1625,7 +1625,7 @@ void Main::on_data_textChanged() catch (dev::Exception const& exception) { ostringstream error; - solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler.getScanner()); + solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler); solidity = "

Solidity

" + QString::fromStdString(error.str()).toHtmlEscaped() + "
"; } catch (...) diff --git a/libsolidity/BaseTypes.h b/libsolidity/BaseTypes.h index 627aa7dfd..a8fd77c86 100644 --- a/libsolidity/BaseTypes.h +++ b/libsolidity/BaseTypes.h @@ -37,14 +37,13 @@ namespace solidity */ struct Location { - Location(int _start, int _end): start(_start), end(_end) { } + Location(int _start, int _end, std::shared_ptr _sourceName): + start(_start), end(_end), sourceName(_sourceName) { } Location(): start(-1), end(-1) { } - bool IsValid() const { return !!sourceName && start >= 0 && end >= start; } - - std::shared_ptr sourceName; int start; int end; + std::shared_ptr sourceName; }; /// Stream output for Location (used e.g. in boost exceptions). diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 49ac3b64c..198ded090 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -81,10 +81,20 @@ void CompilerStack::parse(string const& _sourceCode) parse(); } -void CompilerStack::compile(bool _optimize) +vector CompilerStack::getContractNames() { if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + vector contractNames; + for (auto const& contract: m_contracts) + contractNames.push_back(contract.first); + return contractNames; +} + +void CompilerStack::compile(bool _optimize) +{ + if (!m_parseSuccessful) + parse(); for (Source const* source: m_sourceOrder) for (ASTPointer const& node: source->ast->getNodes()) if (ContractDefinition* contract = dynamic_cast(node.get())) diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 0520f2b1b..a5b8ec41e 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -54,6 +54,9 @@ public: void parse(); /// Sets the given source code as the only source unit and parses it. void parse(std::string const& _sourceCode); + /// Returns a list of the contract names in the sources. + std::vector getContractNames(); + /// Compiles the source units that were prevously added and parsed. void compile(bool _optimize = false); /// Parses and compiles the given source code. diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index 1903c1dc2..ffd8a72d4 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -37,7 +37,6 @@ 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/Parser.cpp b/libsolidity/Parser.cpp index c385dd8d1..ddab489b6 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -39,7 +39,8 @@ namespace solidity class Parser::ASTNodeFactory { public: - ASTNodeFactory(Parser const& _parser): m_parser(_parser), m_location(_parser.getPosition(), -1) {} + ASTNodeFactory(Parser const& _parser): + m_parser(_parser), m_location(_parser.getPosition(), -1, _parser.getSourceName()) {} void markEndPosition() { m_location.end = m_parser.getEndPosition(); } void setLocationEmpty() { m_location.end = m_location.start; } @@ -81,6 +82,11 @@ ASTPointer Parser::parse(shared_ptr const& _scanner) return nodeFactory.createNode(nodes); } +std::shared_ptr const& Parser::getSourceName() const +{ + return m_scanner->getSourceName(); +} + int Parser::getPosition() const { return m_scanner->getCurrentLocation().start; @@ -579,7 +585,8 @@ ASTPointer Parser::getLiteralAndAdvance() ParserError Parser::createParserError(string const& _description) const { - return ParserError() << errinfo_sourcePosition(getPosition()) << errinfo_comment(_description); + return ParserError() << errinfo_sourceLocation(Location(getPosition(), getPosition(), getSourceName())) + << errinfo_comment(_description); } diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 98a337b29..52a374e03 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -35,6 +35,7 @@ class Parser { public: ASTPointer parse(std::shared_ptr const& _scanner); + std::shared_ptr const& getSourceName() const; private: class ASTNodeFactory; diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index e155f550d..08bf744d4 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -143,16 +143,10 @@ private: }; // end of LiteralScope class -void Scanner::reset(CharStream const& _source, std::string const& _sourceName) +void Scanner::reset(CharStream const& _source, string const& _sourceName) { m_source = _source; - - shared_ptr sourceName = make_shared(_sourceName); - m_currentToken.location.sourceName = sourceName; - m_nextToken.location.sourceName = sourceName; - m_skippedComment.location.sourceName = sourceName; - m_nextSkippedComment.location.sourceName = sourceName; - + m_sourceName = make_shared(_sourceName); reset(); } diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index deb7df502..18b1f5d3a 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -142,6 +142,8 @@ public: std::string const& peekLiteral() const { return m_nextToken.literal; } ///@} + std::shared_ptr const& getSourceName() const { return m_sourceName; } + ///@{ ///@name Error printing helper functions /// Functions that help pretty-printing parse errors @@ -206,6 +208,7 @@ private: TokenDesc m_nextToken; // desc for next token (one token look-ahead) CharStream m_source; + std::shared_ptr m_sourceName; /// one character look-ahead, equals 0 at end of input char m_char; diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/SourceReferenceFormatter.cpp index d3f2152a6..1a7d12a95 100644 --- a/libsolidity/SourceReferenceFormatter.cpp +++ b/libsolidity/SourceReferenceFormatter.cpp @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -38,7 +39,6 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream, int startLine; int startColumn; tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start); - _stream << "starting at line " << (startLine + 1) << ", column " << (startColumn + 1) << "\n"; int endLine; int endColumn; tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); @@ -58,37 +58,28 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream, << "Spanning multiple lines.\n"; } -void SourceReferenceFormatter::printSourcePosition(ostream& _stream, - int _position, - const Scanner& _scanner) -{ - int line; - int column; - tie(line, column) = _scanner.translatePositionToLineColumn(_position); - _stream << "at line " << (line + 1) << ", column " << (column + 1) << endl - << _scanner.getLineAtPosition(_position) << endl - << string(column, ' ') << "^" << endl; -} - void SourceReferenceFormatter::printExceptionInformation(ostream& _stream, Exception const& _exception, string const& _name, - Scanner const& _scanner) + CompilerStack& _compiler) { - _stream << _name; - if (string const* description = boost::get_error_info(_exception)) - _stream << ": " << *description; + Location const* location = boost::get_error_info(_exception); + Scanner const* scanner; - if (int const* position = boost::get_error_info(_exception)) + if (location) { - _stream << " "; - printSourcePosition(_stream, *position, _scanner); - } - if (Location const* location = boost::get_error_info(_exception)) - { - _stream << " "; - printSourceLocation(_stream, *location, _scanner); + scanner = &_compiler.getScanner(*location->sourceName); + int startLine; + int startColumn; + tie(startLine, startColumn) = scanner->translatePositionToLineColumn(location->start); + _stream << *location->sourceName << ":" << (startLine + 1) << ":" << (startColumn + 1) << ": "; } + _stream << _name; + if (string const* description = boost::get_error_info(_exception)) + _stream << ": " << *description << endl; + + if (location) + printSourceLocation(_stream, *location, *scanner); } } diff --git a/libsolidity/SourceReferenceFormatter.h b/libsolidity/SourceReferenceFormatter.h index 4736066fd..9b5567045 100644 --- a/libsolidity/SourceReferenceFormatter.h +++ b/libsolidity/SourceReferenceFormatter.h @@ -34,14 +34,14 @@ namespace solidity { class Scanner; // forward +class CompilerStack; // 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); + std::string const& _name, CompilerStack& _compiler); }; } diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 7607b7a95..84a0ae42a 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -510,7 +510,7 @@ std::string WebThreeStubServer::eth_solidity(std::string const& _code) catch (dev::Exception const& exception) { ostringstream error; - solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler.getScanner()); + solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler); cwarn << "Solidity compilation error: " << error.str(); } catch (...) diff --git a/mix/ConstantCompilationModel.cpp b/mix/ConstantCompilationModel.cpp index e06734f59..ea12a267c 100644 --- a/mix/ConstantCompilationModel.cpp +++ b/mix/ConstantCompilationModel.cpp @@ -46,7 +46,7 @@ CompilerResult ConstantCompilationModel::compile(QString _code) catch (dev::Exception const& _exception) { ostringstream error; - solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", compiler.getScanner()); + solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", compiler); res.success = false; res.comment = QString::fromStdString(error.str()).toHtmlEscaped(); res.hexCode = ""; diff --git a/solc/main.cpp b/solc/main.cpp index 76d8ef6b7..3284be74a 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -59,7 +59,7 @@ void version() int main(int argc, char** argv) { - string infile; + vector infiles; bool optimize = false; for (int i = 1; i < argc; ++i) { @@ -71,49 +71,52 @@ int main(int argc, char** argv) else if (arg == "-V" || arg == "--version") version(); else - infile = argv[i]; + infiles.push_back(argv[i]); } - string sourceCode; - if (infile.empty()) + map sourceCodes; + if (infiles.empty()) { string s; while (!cin.eof()) { getline(cin, s); - sourceCode.append(s); + sourceCodes[""].append(s); } } else - sourceCode = asString(dev::contents(infile)); + for (string const& infile: infiles) + sourceCodes[infile] = asString(dev::contents(infile)); CompilerStack compiler; try { - compiler.compile(sourceCode, optimize); + for (auto const& sourceCode: sourceCodes) + compiler.addSource(sourceCode.first, sourceCode.second); + compiler.compile(optimize); } catch (ParserError const& exception) { - SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Parser error", compiler.getScanner()); + SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Parser error", compiler); return -1; } catch (DeclarationError const& exception) { - SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Declaration error", compiler.getScanner()); + SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Declaration error", compiler); return -1; } catch (TypeError const& exception) { - SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Type error", compiler.getScanner()); + SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Type error", compiler); return -1; } catch (CompilerError const& exception) { - SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Compiler error", compiler.getScanner()); + SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Compiler error", compiler); return -1; } catch (InternalCompilerError const& exception) { - SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Internal compiler error", compiler.getScanner()); + SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Internal compiler error", compiler); return -1; } catch (Exception const& exception) @@ -127,15 +130,25 @@ int main(int argc, char** argv) return -1; } - cout << "Syntax tree for the source unit:" << endl; - ASTPrinter printer(compiler.getAST(), sourceCode); - printer.print(cout); - cout << "EVM assembly:" << endl; - compiler.streamAssembly(cout); - cout << "Opcodes:" << endl; - cout << eth::disassemble(compiler.getBytecode()) << endl; - cout << "Binary: " << toHex(compiler.getBytecode()) << endl; - cout << "Interface specification: " << compiler.getInterface() << endl; + cout << "Syntax trees:" << endl << endl; + for (auto const& sourceCode: sourceCodes) + { + cout << endl << "======= " << sourceCode.first << " =======" << endl; + ASTPrinter printer(compiler.getAST(sourceCode.first), sourceCode.second); + printer.print(cout); + } + vector contracts = compiler.getContractNames(); + cout << endl << "Contracts:" << endl; + for (string const& contract: contracts) + { + cout << endl << "======= " << contract << " =======" << endl + << "EVM assembly:" << endl; + compiler.streamAssembly(cout, contract); + cout << "Opcodes:" << endl + << eth::disassemble(compiler.getBytecode(contract)) << endl + << "Binary: " << toHex(compiler.getBytecode(contract)) << endl + << "Interface specification: " << compiler.getInterface(contract) << endl; + } return 0; } diff --git a/test/solidityExpressionCompiler.cpp b/test/solidityExpressionCompiler.cpp index cb22d5120..486b46ebb 100644 --- a/test/solidityExpressionCompiler.cpp +++ b/test/solidityExpressionCompiler.cpp @@ -113,6 +113,7 @@ bytes compileFirstExpression(const string& _sourceCode, vector> _ return instructions; } BOOST_FAIL("No contract found in source."); + return bytes(); } } // end anonymous namespace