Introduce break/continue statements and fix stmt genarator logic

This commit is contained in:
Bhargava Shastry 2021-06-07 18:45:34 +02:00
parent 3d4787bb15
commit 67644c0763
3 changed files with 78 additions and 21 deletions

View File

@ -43,6 +43,8 @@
#define GENERATORLIST(MACRO, SEP, ENDSEP) \ #define GENERATORLIST(MACRO, SEP, ENDSEP) \
MACRO(AssignmentStmtGenerator) SEP \ MACRO(AssignmentStmtGenerator) SEP \
MACRO(BlockStmtGenerator) SEP \ MACRO(BlockStmtGenerator) SEP \
MACRO(BreakStmtGenerator) SEP \
MACRO(ContinueStmtGenerator) SEP \
MACRO(ContractGenerator) SEP \ MACRO(ContractGenerator) SEP \
MACRO(ExpressionStmtGenerator) SEP \ MACRO(ExpressionStmtGenerator) SEP \
MACRO(FunctionCallGenerator) SEP \ MACRO(FunctionCallGenerator) SEP \

View File

@ -511,6 +511,8 @@ void WhileStmtGenerator::setup()
string WhileStmtGenerator::visit() string WhileStmtGenerator::visit()
{ {
ostringstream whileStmt; ostringstream whileStmt;
state->enterLoop();
ScopeGuard exitLoop([&]() { state->exitLoop(); });
ExpressionGenerator exprGen{state}; ExpressionGenerator exprGen{state};
auto boolType = make_shared<BoolType>(); auto boolType = make_shared<BoolType>();
pair<SolidityTypePtr, string> boolTypeName = {boolType, {}}; pair<SolidityTypePtr, string> boolTypeName = {boolType, {}};
@ -538,7 +540,9 @@ void StatementGenerator::setup()
{mutator->generator<FunctionCallGenerator>(), 1}, {mutator->generator<FunctionCallGenerator>(), 1},
{mutator->generator<ExpressionStmtGenerator>(), 1}, {mutator->generator<ExpressionStmtGenerator>(), 1},
{mutator->generator<IfStmtGenerator>(), 2}, {mutator->generator<IfStmtGenerator>(), 2},
{mutator->generator<WhileStmtGenerator>(), 1} {mutator->generator<WhileStmtGenerator>(), 1},
{mutator->generator<BreakStmtGenerator>(), 1},
{mutator->generator<ContinueStmtGenerator>(), 1}
}; };
addGenerators(std::move(dependsOn)); addGenerators(std::move(dependsOn));
} }
@ -553,14 +557,11 @@ string StatementGenerator::visit()
mutator->generator<BlockStmtGenerator>()->unchecked(true); mutator->generator<BlockStmtGenerator>()->unchecked(true);
ostringstream os; ostringstream os;
// Randomise visit order // Choose random statement type
vector<std::pair<GeneratorPtr, unsigned>> randomisedChildren; auto genIterator = generators.begin();
for (auto const& child: generators) auto advanceBy = uRandDist()->distributionOneToN(generators.size()) - 1;
randomisedChildren.push_back(child); std::advance(genIterator, advanceBy);
shuffle(randomisedChildren.begin(), randomisedChildren.end(), *uRandDist()->randomEngine); auto child = *genIterator;
for (auto const& child: randomisedChildren)
if (uRandDist()->likely(child.second + 1))
{
os << std::visit(GenericVisitor{ os << std::visit(GenericVisitor{
[](auto const& _item) { return _item->generate(); } [](auto const& _item) { return _item->generate(); }
}, child.first); }, child.first);
@ -571,7 +572,6 @@ string StatementGenerator::visit()
get<shared_ptr<BlockStmtGenerator>>(child.first)->unchecked(false); get<shared_ptr<BlockStmtGenerator>>(child.first)->unchecked(false);
get<shared_ptr<BlockStmtGenerator>>(child.first)->resetInUnchecked(); get<shared_ptr<BlockStmtGenerator>>(child.first)->resetInUnchecked();
} }
}
return os.str(); return os.str();
} }

View File

@ -504,6 +504,13 @@ struct ContractState
std::string name; std::string name;
}; };
struct LoopState
{
explicit LoopState(bool _inLoop, bool _wasLoop): inLoop(_inLoop), wasLoop(_wasLoop) {}
bool inLoop;
bool wasLoop;
};
struct TestState struct TestState
{ {
explicit TestState(std::shared_ptr<UniformRandomDistribution>& _urd): explicit TestState(std::shared_ptr<UniformRandomDistribution>& _urd):
@ -517,7 +524,8 @@ struct TestState
numContracts(0), numContracts(0),
numFunctions(0), numFunctions(0),
indentationLevel(0), indentationLevel(0),
insideContract(false) insideContract(false),
loopState(false, false)
{} {}
/// Adds @param _path to @name sourceUnitPaths updates /// Adds @param _path to @name sourceUnitPaths updates
/// @name currentSourceUnitPath. /// @name currentSourceUnitPath.
@ -642,6 +650,19 @@ struct TestState
{ {
insideContract = false; insideContract = false;
} }
void enterLoop()
{
loopState.wasLoop = loopState.inLoop;
loopState.inLoop = true;
}
void exitLoop()
{
loopState.inLoop = loopState.wasLoop;
}
bool inLoop()
{
return loopState.inLoop;
}
~TestState() ~TestState()
{ {
sourceUnitState.clear(); sourceUnitState.clear();
@ -681,6 +702,8 @@ struct TestState
unsigned indentationLevel; unsigned indentationLevel;
/// Contract scope /// Contract scope
bool insideContract; bool insideContract;
/// Loop state
LoopState loopState;
/// Source name prefix /// Source name prefix
std::string const sourceUnitNamePrefix = "su"; std::string const sourceUnitNamePrefix = "su";
/// Contract name prefix /// Contract name prefix
@ -1096,6 +1119,38 @@ private:
static constexpr size_t s_maxConditionalStmts = 5; static constexpr size_t s_maxConditionalStmts = 5;
}; };
class BreakStmtGenerator: public GeneratorBase
{
public:
explicit BreakStmtGenerator(SolidityGenerator* _mutator):
GeneratorBase(std::move(_mutator))
{}
std::string visit() override
{
if (state->inLoop())
return indentation() + "break;\n";
else
return "\n";
}
std::string name() override { return "Break statement generator"; }
};
class ContinueStmtGenerator: public GeneratorBase
{
public:
explicit ContinueStmtGenerator(SolidityGenerator* _mutator):
GeneratorBase(std::move(_mutator))
{}
std::string visit() override
{
if (state->inLoop())
return indentation() + "continue;\n";
else
return "\n";
}
std::string name() override { return "Continue statement generator"; }
};
class WhileStmtGenerator: public GeneratorBase class WhileStmtGenerator: public GeneratorBase
{ {
public: public: