Merge pull request #9252 from ethereum/develop

Merge develop into breaking.
This commit is contained in:
chriseth 2020-06-23 18:28:24 +02:00 committed by GitHub
commit af0cd4ab98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 161 additions and 90 deletions

View File

@ -34,6 +34,8 @@ Compiler Features:
Bugfixes: Bugfixes:
* NatSpec: Do not consider ``////`` and ``/***`` as NatSpec comments. * NatSpec: Do not consider ``////`` and ``/***`` as NatSpec comments.
* Type Checker: Fix internal error related to ``using for`` applied to non-libraries. * Type Checker: Fix internal error related to ``using for`` applied to non-libraries.
* Type Checker: Do not disallow assigning to calldata variables.
* Wasm backend: Fix code generation for for-loops with pre statements.
* Yul: Fix source location of variable multi-assignment. * Yul: Fix source location of variable multi-assignment.

View File

@ -11,23 +11,11 @@ sourceUnit
: (pragmaDirective | importDirective | structDefinition | enumDefinition | contractDefinition)* EOF ; : (pragmaDirective | importDirective | structDefinition | enumDefinition | contractDefinition)* EOF ;
pragmaDirective pragmaDirective
: 'pragma' pragmaName pragmaValue ';' ; : 'pragma' pragmaName ( ~';' )* ';' ;
pragmaName pragmaName
: identifier ; : identifier ;
pragmaValue
: version | expression ;
version
: versionConstraint versionConstraint? ;
versionConstraint
: versionOperator? VersionLiteral ;
versionOperator
: '^' | '~' | '>=' | '>' | '<' | '<=' | '=' ;
importDirective importDirective
: 'import' StringLiteralFragment ('as' identifier)? ';' : 'import' StringLiteralFragment ('as' identifier)? ';'
| 'import' ('*' | identifier) ('as' identifier)? 'from' StringLiteralFragment ';' | 'import' ('*' | identifier) ('as' identifier)? 'from' StringLiteralFragment ';'
@ -473,9 +461,6 @@ fragment
SingleQuotedStringCharacter SingleQuotedStringCharacter
: ~['\r\n\\] | ('\\' .) ; : ~['\r\n\\] | ('\\' .) ;
VersionLiteral
: [0-9]+ ( '.' [0-9]+ ('.' [0-9]+)? )? ;
WS WS
: [ \t\r\n\u000C]+ -> skip ; : [ \t\r\n\u000C]+ -> skip ;

View File

@ -492,12 +492,7 @@ DeclarationAnnotation& Declaration::annotation() const
bool VariableDeclaration::isLValue() const bool VariableDeclaration::isLValue() const
{ {
// Constant declared variables are Read-Only // Constant declared variables are Read-Only
if (isConstant()) return !isConstant();
return false;
// External function arguments of reference type are Read-Only
if (isExternalCallableParameter() && dynamic_cast<ReferenceType const*>(type()))
return false;
return true;
} }
bool VariableDeclaration::isLocalVariable() const bool VariableDeclaration::isLocalVariable() const

View File

@ -257,9 +257,10 @@ wasm::Expression WasmCodeTransform::operator()(ForLoop const& _for)
YulString eqz_instruction = YulString(conditionType.str() + ".eqz"); YulString eqz_instruction = YulString(conditionType.str() + ".eqz");
yulAssert(WasmDialect::instance().builtin(eqz_instruction), ""); yulAssert(WasmDialect::instance().builtin(eqz_instruction), "");
std::vector<wasm::Expression> statements = visit(_for.pre.statements);
wasm::Loop loop; wasm::Loop loop;
loop.labelName = newLabel(); loop.labelName = newLabel();
loop.statements = visit(_for.pre.statements);
loop.statements.emplace_back(wasm::BranchIf{wasm::Label{breakLabel}, make_unique<wasm::Expression>( loop.statements.emplace_back(wasm::BranchIf{wasm::Label{breakLabel}, make_unique<wasm::Expression>(
wasm::BuiltinCall{eqz_instruction.str(), make_vector<wasm::Expression>( wasm::BuiltinCall{eqz_instruction.str(), make_vector<wasm::Expression>(
visitReturnByValue(*_for.condition) visitReturnByValue(*_for.condition)
@ -269,7 +270,8 @@ wasm::Expression WasmCodeTransform::operator()(ForLoop const& _for)
loop.statements += visit(_for.post.statements); loop.statements += visit(_for.post.statements);
loop.statements.emplace_back(wasm::Branch{wasm::Label{loop.labelName}}); loop.statements.emplace_back(wasm::Branch{wasm::Label{loop.labelName}});
return { wasm::Block{breakLabel, make_vector<wasm::Expression>(move(loop))} }; statements += make_vector<wasm::Expression>(move(loop));
return wasm::Block{breakLabel, move(statements)};
} }
wasm::Expression WasmCodeTransform::operator()(Break const&) wasm::Expression WasmCodeTransform::operator()(Break const&)

View File

@ -58,10 +58,10 @@ int parseUnsignedInteger(string::iterator& _it, string::iterator _end)
CommonSyntaxTest::CommonSyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion): CommonSyntaxTest::CommonSyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion):
EVMVersionRestrictedTestCase(_filename), EVMVersionRestrictedTestCase(_filename),
m_sources(m_reader.sources().sources),
m_expectations(parseExpectations(m_reader.stream())),
m_evmVersion(_evmVersion) m_evmVersion(_evmVersion)
{ {
m_sources = m_reader.sources();
m_expectations = parseExpectations(m_reader.stream());
} }
TestCase::TestResult CommonSyntaxTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) TestCase::TestResult CommonSyntaxTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
@ -94,12 +94,10 @@ void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix,
if (m_sources.empty()) if (m_sources.empty())
return; return;
bool outputSourceNames = true; bool outputSourceNames = (m_sources.size() != 1 || !m_sources.begin()->first.empty());
if (m_sources.size() == 1 && m_sources.begin()->first.empty())
outputSourceNames = false;
if (_formatted) for (auto const& [name, source]: m_sources)
for (auto const& [name, source]: m_sources) if (_formatted)
{ {
if (source.empty()) if (source.empty())
continue; continue;
@ -139,8 +137,7 @@ void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix,
} }
_stream << formatting::RESET; _stream << formatting::RESET;
} }
else else
for (auto const& [name, source]: m_sources)
{ {
if (outputSourceNames) if (outputSourceNames)
_stream << _linePrefix << "==== Source: " + name << " ====" << endl; _stream << _linePrefix << "==== Source: " + name << " ====" << endl;

View File

@ -61,22 +61,28 @@ public:
virtual ~ExecutionFramework() = default; virtual ~ExecutionFramework() = default;
virtual bytes const& compileAndRunWithoutCheck( virtual bytes const& compileAndRunWithoutCheck(
std::string const& _sourceCode, std::map<std::string, std::string> const& _sourceCode,
u256 const& _value = 0, u256 const& _value = 0,
std::string const& _contractName = "", std::string const& _contractName = "",
bytes const& _arguments = bytes(), bytes const& _arguments = {},
std::map<std::string, Address> const& _libraryAddresses = std::map<std::string, Address>() std::map<std::string, Address> const& _libraryAddresses = {}
) = 0; ) = 0;
bytes const& compileAndRun( bytes const& compileAndRun(
std::string const& _sourceCode, std::string const& _sourceCode,
u256 const& _value = 0, u256 const& _value = 0,
std::string const& _contractName = "", std::string const& _contractName = "",
bytes const& _arguments = bytes(), bytes const& _arguments = {},
std::map<std::string, Address> const& _libraryAddresses = std::map<std::string, Address>() std::map<std::string, Address> const& _libraryAddresses = {}
) )
{ {
compileAndRunWithoutCheck(_sourceCode, _value, _contractName, _arguments, _libraryAddresses); compileAndRunWithoutCheck(
{{"", _sourceCode}},
_value,
_contractName,
_arguments,
_libraryAddresses
);
BOOST_REQUIRE(m_transactionSuccessful); BOOST_REQUIRE(m_transactionSuccessful);
BOOST_REQUIRE(!m_output.empty()); BOOST_REQUIRE(!m_output.empty());
return m_output; return m_output;
@ -293,4 +299,3 @@ protected:
} // end namespaces } // end namespaces

View File

@ -37,11 +37,11 @@ TestCaseReader::TestCaseReader(string const& _filename):
m_unreadSettings = m_settings; m_unreadSettings = m_settings;
} }
string const& TestCaseReader::source() string const& TestCaseReader::source() const
{ {
if (m_sources.size() != 1) if (m_sources.sources.size() != 1)
BOOST_THROW_EXCEPTION(runtime_error("Expected single source definition, but got multiple sources.")); BOOST_THROW_EXCEPTION(runtime_error("Expected single source definition, but got multiple sources."));
return m_sources.begin()->second; return m_sources.sources.at(m_sources.mainSourceFile);
} }
string TestCaseReader::simpleExpectations() string TestCaseReader::simpleExpectations()
@ -93,7 +93,7 @@ void TestCaseReader::ensureAllSettingsRead() const
); );
} }
pair<map<string, string>, size_t> TestCaseReader::parseSourcesAndSettingsWithLineNumber(istream& _stream) pair<SourceMap, size_t> TestCaseReader::parseSourcesAndSettingsWithLineNumber(istream& _stream)
{ {
map<string, string> sources; map<string, string> sources;
string currentSourceName; string currentSourceName;
@ -145,8 +145,9 @@ pair<map<string, string>, size_t> TestCaseReader::parseSourcesAndSettingsWithLin
else else
throw runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source.")); throw runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source."));
} }
// Register the last source as the main one
sources[currentSourceName] = currentSource; sources[currentSourceName] = currentSource;
return { sources, lineNumber }; return {{move(sources), move(currentSourceName)}, lineNumber};
} }
string TestCaseReader::parseSimpleExpectations(istream& _file) string TestCaseReader::parseSimpleExpectations(istream& _file)

View File

@ -23,6 +23,16 @@
namespace solidity::frontend::test namespace solidity::frontend::test
{ {
/**
* A map for registering source names that also contains the main source name in a test case.
*/
struct SourceMap
{
std::map<std::string, std::string> sources;
std::string mainSourceFile;
};
/** /**
* A reader for test case data file, which parses source, settings and (optionally) simple expectations. * A reader for test case data file, which parses source, settings and (optionally) simple expectations.
*/ */
@ -32,10 +42,10 @@ public:
TestCaseReader() = default; TestCaseReader() = default;
explicit TestCaseReader(std::string const& _filename); explicit TestCaseReader(std::string const& _filename);
std::map<std::string, std::string> const& sources() { return m_sources; } SourceMap const& sources() const { return m_sources; }
std::string const& source(); std::string const& source() const;
std::size_t lineNumber() { return m_lineNumber; } std::size_t lineNumber() const { return m_lineNumber; }
std::map<std::string, std::string> const& settings() { return m_settings; } std::map<std::string, std::string> const& settings() const { return m_settings; }
std::ifstream& stream() { return m_file; } std::ifstream& stream() { return m_file; }
std::string simpleExpectations(); std::string simpleExpectations();
@ -47,11 +57,11 @@ public:
void ensureAllSettingsRead() const; void ensureAllSettingsRead() const;
private: private:
std::pair<std::map<std::string, std::string>, std::size_t> parseSourcesAndSettingsWithLineNumber(std::istream& _file); std::pair<SourceMap, std::size_t> parseSourcesAndSettingsWithLineNumber(std::istream& _file);
static std::string parseSimpleExpectations(std::istream& _file); static std::string parseSimpleExpectations(std::istream& _file);
std::ifstream m_file; std::ifstream m_file;
std::map<std::string, std::string> m_sources; SourceMap m_sources;
std::size_t m_lineNumber = 0; std::size_t m_lineNumber = 0;
std::map<std::string, std::string> m_settings; std::map<std::string, std::string> m_settings;
std::map<std::string, std::string> m_unreadSettings; ///< tracks which settings are left unread std::map<std::string, std::string> m_unreadSettings; ///< tracks which settings are left unread

View File

@ -777,7 +777,7 @@ BOOST_AUTO_TEST_CASE(struct_in_constructor_data_short)
NEW_ENCODER( NEW_ENCODER(
BOOST_CHECK( BOOST_CHECK(
compileAndRunWithoutCheck(sourceCode, 0, "C", encodeArgs(0x20, 0x60, 0x03, 0x80, 0x00)).empty() compileAndRunWithoutCheck({{"", sourceCode}}, 0, "C", encodeArgs(0x20, 0x60, 0x03, 0x80, 0x00)).empty()
); );
) )
} }

View File

@ -42,11 +42,10 @@ namespace fs = boost::filesystem;
SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion, bool enforceViaYul): SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion, bool enforceViaYul):
SolidityExecutionFramework(_evmVersion), SolidityExecutionFramework(_evmVersion),
EVMVersionRestrictedTestCase(_filename), EVMVersionRestrictedTestCase(_filename),
m_sources(m_reader.sources()),
m_lineOffset(m_reader.lineNumber()),
m_enforceViaYul(enforceViaYul) m_enforceViaYul(enforceViaYul)
{ {
m_source = m_reader.source();
m_lineOffset = m_reader.lineNumber();
string choice = m_reader.stringSetting("compileViaYul", "false"); string choice = m_reader.stringSetting("compileViaYul", "false");
if (choice == "also") if (choice == "also")
{ {
@ -239,12 +238,48 @@ TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePref
return TestResult::Success; return TestResult::Success;
} }
void SemanticTest::printSource(ostream& _stream, string const& _linePrefix, bool) const void SemanticTest::printSource(ostream& _stream, string const& _linePrefix, bool _formatted) const
{ {
stringstream stream(m_source); if (m_sources.sources.empty())
string line; return;
while (getline(stream, line))
_stream << _linePrefix << line << endl; bool outputNames = (m_sources.sources.size() != 1 || !m_sources.sources.begin()->first.empty());
for (auto const& [name, source]: m_sources.sources)
if (_formatted)
{
if (source.empty())
continue;
if (outputNames)
_stream << _linePrefix << formatting::CYAN << "==== Source: " << name << " ====" << formatting::RESET << endl;
vector<char const*> sourceFormatting(source.length(), formatting::RESET);
_stream << _linePrefix << sourceFormatting.front() << source.front();
for (size_t i = 1; i < source.length(); i++)
{
if (sourceFormatting[i] != sourceFormatting[i - 1])
_stream << sourceFormatting[i];
if (source[i] != '\n')
_stream << source[i];
else
{
_stream << formatting::RESET << endl;
if (i + 1 < source.length())
_stream << _linePrefix << sourceFormatting[i];
}
}
_stream << formatting::RESET;
}
else
{
if (outputNames)
_stream << _linePrefix << "==== Source: " + name << " ====" << endl;
stringstream stream(source);
string line;
while (getline(stream, line))
_stream << _linePrefix << line << endl;
}
} }
void SemanticTest::printUpdatedExpectations(ostream& _stream, string const&) const void SemanticTest::printUpdatedExpectations(ostream& _stream, string const&) const
@ -276,6 +311,6 @@ void SemanticTest::parseExpectations(istream& _stream)
bool SemanticTest::deploy(string const& _contractName, u256 const& _value, bytes const& _arguments, map<string, solidity::test::Address> const& _libraries) bool SemanticTest::deploy(string const& _contractName, u256 const& _value, bytes const& _arguments, map<string, solidity::test::Address> const& _libraries)
{ {
auto output = compileAndRunWithoutCheck(m_source, _value, _contractName, _arguments, _libraries); auto output = compileAndRunWithoutCheck(m_sources.sources, _value, _contractName, _arguments, _libraries);
return !output.empty() && m_transactionSuccessful; return !output.empty() && m_transactionSuccessful;
} }

View File

@ -58,9 +58,8 @@ public:
/// Compiles and deploys currently held source. /// Compiles and deploys currently held source.
/// Returns true if deployment was successful, false otherwise. /// Returns true if deployment was successful, false otherwise.
bool deploy(std::string const& _contractName, u256 const& _value, bytes const& _arguments, std::map<std::string, solidity::test::Address> const& _libraries = {}); bool deploy(std::string const& _contractName, u256 const& _value, bytes const& _arguments, std::map<std::string, solidity::test::Address> const& _libraries = {});
private: private:
std::string m_source; SourceMap m_sources;
std::size_t m_lineOffset; std::size_t m_lineOffset;
std::vector<TestFunctionCall> m_tests; std::vector<TestFunctionCall> m_tests;
bool m_runWithYul = false; bool m_runWithYul = false;

View File

@ -1723,7 +1723,7 @@ BOOST_AUTO_TEST_CASE(internal_constructor)
constructor() internal {} constructor() internal {}
} }
)"; )";
BOOST_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "C").empty()); BOOST_CHECK(compileAndRunWithoutCheck({{"", sourceCode}}, 0, "C").empty());
} }
BOOST_AUTO_TEST_CASE(default_fallback_throws) BOOST_AUTO_TEST_CASE(default_fallback_throws)
@ -3618,7 +3618,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund)
} }
} }
)"; )";
ABI_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "A"), encodeArgs()); ABI_CHECK(compileAndRunWithoutCheck({{"", sourceCode}}, 0, "A"), encodeArgs());
BOOST_CHECK(!m_transactionSuccessful); BOOST_CHECK(!m_transactionSuccessful);
} }

View File

@ -31,22 +31,18 @@ using namespace solidity::frontend;
using namespace solidity::frontend::test; using namespace solidity::frontend::test;
using namespace std; using namespace std;
bytes SolidityExecutionFramework::compileContract( bytes SolidityExecutionFramework::multiSourceCompileContract(
string const& _sourceCode, map<string, string> const& _sourceCode,
string const& _contractName, string const& _contractName,
map<string, Address> const& _libraryAddresses map<string, Address> const& _libraryAddresses
) )
{ {
// Silence compiler version warning map<string, string> sourcesWithPreamble = _sourceCode;
std::string sourceCode = "pragma solidity >=0.0;\n"; for (auto& entry: sourcesWithPreamble)
if ( entry.second = addPreamble(entry.second);
solidity::test::CommonOptions::get().useABIEncoderV2 &&
_sourceCode.find("pragma experimental ABIEncoderV2;") == std::string::npos
)
sourceCode += "pragma experimental ABIEncoderV2;\n";
sourceCode += _sourceCode;
m_compiler.reset(); m_compiler.reset();
m_compiler.setSources({{"", sourceCode}}); m_compiler.setSources(sourcesWithPreamble);
m_compiler.setLibraries(_libraryAddresses); m_compiler.setLibraries(_libraryAddresses);
m_compiler.setRevertStringBehaviour(m_revertStrings); m_compiler.setRevertStringBehaviour(m_revertStrings);
m_compiler.setEVMVersion(m_evmVersion); m_compiler.setEVMVersion(m_evmVersion);
@ -85,3 +81,28 @@ bytes SolidityExecutionFramework::compileContract(
cout << "metadata: " << m_compiler.metadata(contractName) << endl; cout << "metadata: " << m_compiler.metadata(contractName) << endl;
return obj.bytecode; return obj.bytecode;
} }
bytes SolidityExecutionFramework::compileContract(
string const& _sourceCode,
string const& _contractName,
map<string, Address> const& _libraryAddresses
)
{
return multiSourceCompileContract(
{{"", _sourceCode}},
_contractName,
_libraryAddresses
);
}
string SolidityExecutionFramework::addPreamble(string const& _sourceCode)
{
// Silence compiler version warning
string preamble = "pragma solidity >=0.0;\n";
if (
solidity::test::CommonOptions::get().useABIEncoderV2 &&
_sourceCode.find("pragma experimental ABIEncoderV2;") == string::npos
)
preamble += "pragma experimental ABIEncoderV2;\n";
return preamble + _sourceCode;
}

View File

@ -47,14 +47,14 @@ public:
{} {}
bytes const& compileAndRunWithoutCheck( bytes const& compileAndRunWithoutCheck(
std::string const& _sourceCode, std::map<std::string, std::string> const& _sourceCode,
u256 const& _value = 0, u256 const& _value = 0,
std::string const& _contractName = "", std::string const& _contractName = "",
bytes const& _arguments = bytes(), bytes const& _arguments = {},
std::map<std::string, solidity::test::Address> const& _libraryAddresses = std::map<std::string, solidity::test::Address>() std::map<std::string, solidity::test::Address> const& _libraryAddresses = {}
) override ) override
{ {
bytes bytecode = compileContract(_sourceCode, _contractName, _libraryAddresses); bytes bytecode = multiSourceCompileContract(_sourceCode, _contractName, _libraryAddresses);
sendMessage(bytecode + _arguments, true, _value); sendMessage(bytecode + _arguments, true, _value);
return m_output; return m_output;
} }
@ -62,16 +62,23 @@ public:
bytes compileContract( bytes compileContract(
std::string const& _sourceCode, std::string const& _sourceCode,
std::string const& _contractName = "", std::string const& _contractName = "",
std::map<std::string, solidity::test::Address> const& _libraryAddresses = std::map<std::string, solidity::test::Address>() std::map<std::string, solidity::test::Address> const& _libraryAddresses = {}
); );
bytes multiSourceCompileContract(
std::map<std::string, std::string> const& _sources,
std::string const& _contractName = "",
std::map<std::string, solidity::test::Address> const& _libraryAddresses = {}
);
/// Returns @param _sourceCode prefixed with the version pragma and the ABIEncoderV2 pragma,
/// the latter only if it is required.
static std::string addPreamble(std::string const& _sourceCode);
protected: protected:
solidity::frontend::CompilerStack m_compiler; solidity::frontend::CompilerStack m_compiler;
bool m_compileViaYul = false; bool m_compileViaYul = false;
bool m_showMetadata = false; bool m_showMetadata = false;
RevertStrings m_revertStrings = RevertStrings::Default; RevertStrings m_revertStrings = RevertStrings::Default;
}; };
} // end namespaces } // end namespaces

View File

@ -0,0 +1,12 @@
==== Source: A ====
contract A {
function g(uint256 x) public view returns(uint256) { return x + 1; }
}
==== Source: B ====
import "A";
contract B is A {
function f(uint256 x) public view returns(uint256) { return x; }
}
// ----
// f(uint256): 1337 -> 1337
// g(uint256): 1337 -> 1338

View File

@ -4,4 +4,3 @@ contract C {
} }
} }
// ---- // ----
// TypeError 7128: (96-97): External function arguments of reference type are read-only.

View File

@ -0,0 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity < 142857;
pragma solidity >= 0.0;
pragma solidity >= 0.0.0;
contract C {
}

View File

@ -5,7 +5,5 @@ contract Test {
function g(S calldata s) external { S memory m; s = m; } function g(S calldata s) external { S memory m; s = m; }
} }
// ---- // ----
// TypeError 7128: (114-115): External function arguments of reference type are read-only.
// TypeError 7407: (118-122): Type struct Test.S memory is not implicitly convertible to expected type struct Test.S calldata. // TypeError 7407: (118-122): Type struct Test.S memory is not implicitly convertible to expected type struct Test.S calldata.
// TypeError 7128: (178-179): External function arguments of reference type are read-only.
// TypeError 7407: (182-183): Type struct Test.S memory is not implicitly convertible to expected type struct Test.S calldata. // TypeError 7407: (182-183): Type struct Test.S memory is not implicitly convertible to expected type struct Test.S calldata.

View File

@ -21,17 +21,13 @@
#include <memory> #include <memory>
#include <test/Common.h> #include <test/Common.h>
#include <test/tools/IsolTestOptions.h> #include <test/tools/IsolTestOptions.h>
#include <test/libsolidity/AnalysisFramework.h>
#include <test/InteractiveTests.h> #include <test/InteractiveTests.h>
#include <test/EVMHost.h> #include <test/EVMHost.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <cstdlib> #include <cstdlib>
#include <fstream>
#include <iostream> #include <iostream>
#include <queue> #include <queue>
#include <regex> #include <regex>