diff options
author | chriseth <c@ethdev.com> | 2016-06-08 01:44:32 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2016-06-09 00:16:46 +0800 |
commit | 3150ab2bcfe6ab66d426916fc1a003ae52799b72 (patch) | |
tree | b7fc2c8c910c97c883816364bd62bb7c646dd75b /libsolidity | |
parent | 63b63056893717a9ec4565ba6c1e7c746592054b (diff) | |
download | dexon-solidity-3150ab2bcfe6ab66d426916fc1a003ae52799b72.tar.gz dexon-solidity-3150ab2bcfe6ab66d426916fc1a003ae52799b72.tar.zst dexon-solidity-3150ab2bcfe6ab66d426916fc1a003ae52799b72.zip |
Allow remappings to change depending on the context.
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 79 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.h | 25 |
2 files changed, 88 insertions, 16 deletions
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 83459183..c28e926b 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -63,6 +63,24 @@ CompilerStack::CompilerStack(bool _addStandardSources, ReadFileCallback const& _ addSources(StandardSources, true); // add them as libraries } +void CompilerStack::setRemappings(vector<string> const& _remappings) +{ + vector<Remapping> remappings; + for (auto const& remapping: _remappings) + { + auto eq = find(remapping.begin(), remapping.end(), '='); + if (eq == remapping.end()) + continue; // ignore + auto colon = find(remapping.begin(), eq, ':'); + Remapping r; + r.context = colon == eq ? string() : string(remapping.begin(), colon); + r.prefix = colon == eq ? string(remapping.begin(), eq) : string(colon + 1, eq); + r.target = string(eq + 1, remapping.end()); + remappings.push_back(r); + } + swap(m_remappings, remappings); +} + void CompilerStack::reset(bool _keepSources, bool _addStandardSources) { m_parseSuccessful = false; @@ -384,37 +402,72 @@ tuple<int, int, int, int> CompilerStack::positionFromSourceLocation(SourceLocati return make_tuple(++startLine, ++startColumn, ++endLine, ++endColumn); } -StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string const& _path) +StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string const& _sourcePath) { StringMap newSources; for (auto const& node: _ast.nodes()) if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get())) { - string path = absolutePath(import->path(), _path); - import->annotation().absolutePath = path; - if (m_sources.count(path) || newSources.count(path)) + string importPath = absolutePath(import->path(), _sourcePath); + // The current value of `path` is the absolute path as seen from this source file. + // We first have to apply remappings before we can store the actual absolute path + // as seen globally. + importPath = applyRemapping(importPath, _sourcePath); + import->annotation().absolutePath = importPath; + if (m_sources.count(importPath) || newSources.count(importPath)) continue; - string contents; - string errorMessage; - if (!m_readFile) - errorMessage = "File not supplied initially."; + + ReadFileResult result{false, string("File not supplied initially.")}; + if (m_readFile) + result = m_readFile(importPath); + + if (result.success) + newSources[importPath] = result.contentsOrErrorMesage; else - tie(contents, errorMessage) = m_readFile(path); - if (!errorMessage.empty()) { auto err = make_shared<Error>(Error::Type::ParserError); *err << errinfo_sourceLocation(import->location()) << - errinfo_comment("Source not found: " + errorMessage); + errinfo_comment("Source \"" + importPath + "\" not found: " + result.contentsOrErrorMesage); m_errors.push_back(std::move(err)); continue; } - else - newSources[path] = contents; } return newSources; } +string CompilerStack::applyRemapping(string const& _path, string const& _context) +{ + // Try to find the longest prefix match in all remappings that are active in the current context. + auto isPrefixOf = [](string const& _a, string const& _b) + { + if (_a.length() > _b.length()) + return false; + return std::equal(_a.begin(), _a.end(), _b.begin()); + }; + + size_t longestPrefix = 0; + string longestPrefixTarget; + for (auto const& redir: m_remappings) + { + // Skip if we already have a closer match. + if (longestPrefix > 0 && redir.prefix.length() <= longestPrefix) + continue; + // Skip if redir.context is not a prefix of _context + if (!isPrefixOf(redir.context, _context)) + continue; + // Skip if the prefix does not match. + if (!isPrefixOf(redir.prefix, _path)) + continue; + + longestPrefix = redir.prefix.length(); + longestPrefixTarget = redir.target; + } + string path = longestPrefixTarget; + path.append(_path.begin() + longestPrefix, _path.end()); + return path; +} + void CompilerStack::resolveImports() { // topological sorting (depth first search) of the import graph, cutting potential cycles diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index c7f98184..e111c982 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -75,15 +75,23 @@ enum class DocumentationType: uint8_t class CompilerStack: boost::noncopyable { public: - /// File reading callback, should return a pair of content and error message (exactly one nonempty) - /// for a given path. - using ReadFileCallback = std::function<std::pair<std::string, std::string>(std::string const&)>; + struct ReadFileResult + { + bool success; + std::string contentsOrErrorMesage; + }; + + /// File reading callback. + using ReadFileCallback = std::function<ReadFileResult(std::string const&)>; /// Creates a new compiler stack. /// @param _readFile callback to used to read files for import statements. Should return /// @param _addStandardSources Adds standard sources if @a _addStandardSources. explicit CompilerStack(bool _addStandardSources = true, ReadFileCallback const& _readFile = ReadFileCallback()); + /// Sets path remappings in the format "context:prefix=target" + void setRemappings(std::vector<std::string> const& _remappings); + /// Resets the compiler to a state where the sources are not parsed or even removed. void reset(bool _keepSources = false, bool _addStandardSources = true); @@ -209,6 +217,7 @@ private: /// @a m_readFile and stores the absolute paths of all imports in the AST annotations. /// @returns the newly loaded sources. StringMap loadMissingSources(SourceUnit const& _ast, std::string const& _path); + std::string applyRemapping(std::string const& _path, std::string const& _context); void resolveImports(); /// Checks whether there are libraries with the same name, reports that as an error and /// @returns false in this case. @@ -226,7 +235,17 @@ private: Contract const& contract(std::string const& _contractName = "") const; Source const& source(std::string const& _sourceName = "") const; + struct Remapping + { + std::string context; + std::string prefix; + std::string target; + }; + ReadFileCallback m_readFile; + /// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum + /// "context:prefix=target" + std::vector<Remapping> m_remappings; bool m_parseSuccessful; std::map<std::string const, Source> m_sources; std::shared_ptr<GlobalContext> m_globalContext; |