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) \
MACRO(ContractGenerator) SEP \
MACRO(FunctionGenerator) SEP \
MACRO(ImportGenerator) SEP \
MACRO(PragmaGenerator) SEP \
MACRO(SourceUnitGenerator) SEP \

View File

@ -135,7 +135,8 @@ void SourceUnitGenerator::setup()
addGenerators({
{mutator->generator<ImportGenerator>(), s_maxImports},
{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();
}
void ContractGenerator::setup()
{
addGenerators({
{mutator->generator<FunctionGenerator>(), s_maxFunctions}
});
}
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();
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>

View File

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