Add function

This commit is contained in:
Bhargava Shastry 2021-04-23 13:33:55 +02:00
parent 10a416c4a8
commit 6d2c990117
3 changed files with 117 additions and 4 deletions

View File

@ -42,6 +42,7 @@
*/ */
#define GENERATORLIST(MACRO, SEP, ENDSEP) \ #define GENERATORLIST(MACRO, SEP, ENDSEP) \
MACRO(ContractGenerator) SEP \ MACRO(ContractGenerator) SEP \
MACRO(FunctionGenerator) SEP \
MACRO(ImportGenerator) SEP \ MACRO(ImportGenerator) SEP \
MACRO(PragmaGenerator) SEP \ MACRO(PragmaGenerator) SEP \
MACRO(SourceUnitGenerator) SEP \ MACRO(SourceUnitGenerator) SEP \

View File

@ -135,7 +135,8 @@ void SourceUnitGenerator::setup()
addGenerators({ addGenerators({
{mutator->generator<ImportGenerator>(), s_maxImports}, {mutator->generator<ImportGenerator>(), s_maxImports},
{mutator->generator<PragmaGenerator>(), 1}, {mutator->generator<PragmaGenerator>(), 1},
{mutator->generator<ContractGenerator>(), 1} {mutator->generator<ContractGenerator>(), 1},
{mutator->generator<FunctionGenerator>(), s_maxFreeFunctions}
}); });
} }
@ -185,11 +186,43 @@ string ImportGenerator::visit()
return os.str(); return os.str();
} }
void ContractGenerator::setup()
{
addGenerators({
{mutator->generator<FunctionGenerator>(), s_maxFunctions}
});
}
string ContractGenerator::visit() string ContractGenerator::visit()
{ {
ScopeGuard reset([&]() {
mutator->generator<FunctionGenerator>()->scope(true);
state->unindent();
});
auto set = [&]() {
state->indent();
mutator->generator<FunctionGenerator>()->scope(false);
};
ostringstream os;
string name = state->newContract(); string name = state->newContract();
state->updateContract(name); state->updateContract(name);
return "contract " + name + " {}\n"; os << "contract " << name << " {" << endl;
set();
os << visitChildren();
os << "}" << endl;
return os.str();
}
string FunctionGenerator::visit()
{
string visibility;
string name = state->newFunction();
state->updateFunction(name);
if (!m_freeFunction)
visibility = "public";
return indentation(state->indentationLevel) +
"function " + name + "() " + visibility + " pure {}\n";
} }
template <typename T> template <typename T>

View File

@ -116,8 +116,17 @@ struct SourceState
{ {
explicit SourceState(std::shared_ptr<UniformRandomDistribution> _urd): explicit SourceState(std::shared_ptr<UniformRandomDistribution> _urd):
uRandDist(std::move(_urd)), uRandDist(std::move(_urd)),
importedSources({}) importedSources({}),
freeFunctions({})
{} {}
void addFreeFunction(std::string& _functionName)
{
freeFunctions.emplace(_functionName);
}
bool freeFunction(std::string const& _functionName)
{
return freeFunctions.count(_functionName);
}
void addImportedSourcePath(std::string& _sourcePath) void addImportedSourcePath(std::string& _sourcePath)
{ {
importedSources.emplace(_sourcePath); importedSources.emplace(_sourcePath);
@ -134,17 +143,24 @@ struct SourceState
void print(std::ostream& _os) const; void print(std::ostream& _os) const;
std::shared_ptr<UniformRandomDistribution> uRandDist; std::shared_ptr<UniformRandomDistribution> uRandDist;
std::set<std::string> importedSources; std::set<std::string> importedSources;
std::set<std::string> freeFunctions;
}; };
struct FunctionState {};
struct TestState struct TestState
{ {
explicit TestState(std::shared_ptr<UniformRandomDistribution> _urd): explicit TestState(std::shared_ptr<UniformRandomDistribution> _urd):
sourceUnitState({}), sourceUnitState({}),
contractState({}), contractState({}),
currentSourceUnitPath({}), currentSourceUnitPath({}),
currentContract({}),
currentFunction({}),
uRandDist(std::move(_urd)), uRandDist(std::move(_urd)),
numSourceUnits(0), numSourceUnits(0),
numContracts(0) numContracts(0),
numFunctions(0),
indentationLevel(0)
{} {}
/// Adds @param _path to @name sourceUnitPaths updates /// Adds @param _path to @name sourceUnitPaths updates
/// @name currentSourceUnitPath. /// @name currentSourceUnitPath.
@ -160,6 +176,11 @@ struct TestState
contractState.emplace(_name, std::make_shared<ContractState>(uRandDist)); contractState.emplace(_name, std::make_shared<ContractState>(uRandDist));
currentContract = _name; currentContract = _name;
} }
void addFunction(std::string const& _name)
{
functionState.emplace(_name, std::make_shared<FunctionState>());
currentFunction = _name;
}
/// Returns true if @name sourceUnitPaths is empty, /// Returns true if @name sourceUnitPaths is empty,
/// false otherwise. /// false otherwise.
[[nodiscard]] bool empty() const [[nodiscard]] bool empty() const
@ -183,6 +204,10 @@ struct TestState
{ {
return contractPrefix + std::to_string(numContracts); return contractPrefix + std::to_string(numContracts);
} }
[[nodiscard]] std::string newFunction() const
{
return functionPrefix + std::to_string(numFunctions);
}
[[nodiscard]] std::string currentPath() const [[nodiscard]] std::string currentPath() const
{ {
solAssert(numSourceUnits > 0, ""); solAssert(numSourceUnits > 0, "");
@ -202,10 +227,25 @@ struct TestState
addContract(_name); addContract(_name);
numContracts++; numContracts++;
} }
void updateFunction(std::string const& _name)
{
addFunction(_name);
numFunctions++;
}
void addSource() void addSource()
{ {
updateSourcePath(newPath()); updateSourcePath(newPath());
} }
/// Increments indentation level globally.
void indent()
{
++indentationLevel;
}
/// Decrements indentation level globally.
void unindent()
{
--indentationLevel;
}
~TestState() ~TestState()
{ {
sourceUnitState.clear(); sourceUnitState.clear();
@ -224,20 +264,30 @@ struct TestState
std::map<std::string, std::shared_ptr<SourceState>> sourceUnitState; std::map<std::string, std::shared_ptr<SourceState>> sourceUnitState;
/// Map of contract name -> state /// Map of contract name -> state
std::map<std::string, std::shared_ptr<ContractState>> contractState; std::map<std::string, std::shared_ptr<ContractState>> contractState;
/// Map of function name -> state
std::map<std::string, std::shared_ptr<FunctionState>> functionState;
/// Source path being currently visited. /// Source path being currently visited.
std::string currentSourceUnitPath; std::string currentSourceUnitPath;
/// Current contract /// Current contract
std::string currentContract; std::string currentContract;
/// Current function
std::string currentFunction;
/// Uniform random distribution. /// Uniform random distribution.
std::shared_ptr<UniformRandomDistribution> uRandDist; std::shared_ptr<UniformRandomDistribution> uRandDist;
/// Number of source units in test input /// Number of source units in test input
size_t numSourceUnits; size_t numSourceUnits;
/// Number of contracts in test input /// Number of contracts in test input
size_t numContracts; size_t numContracts;
/// Number of functions in test input
size_t numFunctions;
/// Indentation level
unsigned indentationLevel;
/// Source name prefix /// Source name prefix
std::string const sourceUnitNamePrefix = "su"; std::string const sourceUnitNamePrefix = "su";
/// Contract name prefix /// Contract name prefix
std::string const contractPrefix = "C"; std::string const contractPrefix = "C";
/// Function name prefix
std::string const functionPrefix = "f";
}; };
struct GeneratorBase struct GeneratorBase
@ -258,6 +308,12 @@ struct GeneratorBase
endVisit(); endVisit();
return generatedCode; return generatedCode;
} }
/// @returns indentation as string. Each indentation level comprises two
/// whitespace characters.
std::string indentation(unsigned _indentationLevel)
{
return std::string(_indentationLevel * 2, ' ');
}
/// @returns a string representing the generation of /// @returns a string representing the generation of
/// the Solidity grammar element. /// the Solidity grammar element.
virtual std::string visit() = 0; virtual std::string visit() = 0;
@ -341,6 +397,7 @@ public:
std::string name() override { return "Source unit generator"; } std::string name() override { return "Source unit generator"; }
private: private:
static unsigned constexpr s_maxImports = 2; static unsigned constexpr s_maxImports = 2;
static unsigned constexpr s_maxFreeFunctions = 2;
}; };
class PragmaGenerator: public GeneratorBase class PragmaGenerator: public GeneratorBase
@ -378,8 +435,30 @@ public:
explicit ContractGenerator(std::shared_ptr<SolidityGenerator> _mutator): explicit ContractGenerator(std::shared_ptr<SolidityGenerator> _mutator):
GeneratorBase(std::move(_mutator)) GeneratorBase(std::move(_mutator))
{} {}
void setup() override;
std::string visit() override; std::string visit() override;
std::string name() override { return "Contract generator"; } std::string name() override { return "Contract generator"; }
private:
static unsigned constexpr s_maxFunctions = 4;
};
class FunctionGenerator: public GeneratorBase
{
public:
explicit FunctionGenerator(std::shared_ptr<SolidityGenerator> _mutator):
GeneratorBase(std::move(_mutator)),
m_freeFunction(true)
{}
std::string visit() override;
std::string name() override { return "Function generator"; }
/// Sets @name m_freeFunction to @param _freeFunction.
void scope(bool _freeFunction)
{
m_freeFunction = _freeFunction;
}
private:
bool m_freeFunction;
}; };
class SolidityGenerator: public std::enable_shared_from_this<SolidityGenerator> class SolidityGenerator: public std::enable_shared_from_this<SolidityGenerator>