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) \
MACRO(AssignmentStmtGenerator) SEP \
MACRO(BlockStmtGenerator) SEP \
MACRO(BreakStmtGenerator) SEP \
MACRO(ContinueStmtGenerator) SEP \
MACRO(ContractGenerator) SEP \
MACRO(ExpressionStmtGenerator) SEP \
MACRO(FunctionCallGenerator) SEP \

View File

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

View File

@ -504,6 +504,13 @@ struct ContractState
std::string name;
};
struct LoopState
{
explicit LoopState(bool _inLoop, bool _wasLoop): inLoop(_inLoop), wasLoop(_wasLoop) {}
bool inLoop;
bool wasLoop;
};
struct TestState
{
explicit TestState(std::shared_ptr<UniformRandomDistribution>& _urd):
@ -517,7 +524,8 @@ struct TestState
numContracts(0),
numFunctions(0),
indentationLevel(0),
insideContract(false)
insideContract(false),
loopState(false, false)
{}
/// Adds @param _path to @name sourceUnitPaths updates
/// @name currentSourceUnitPath.
@ -642,6 +650,19 @@ struct TestState
{
insideContract = false;
}
void enterLoop()
{
loopState.wasLoop = loopState.inLoop;
loopState.inLoop = true;
}
void exitLoop()
{
loopState.inLoop = loopState.wasLoop;
}
bool inLoop()
{
return loopState.inLoop;
}
~TestState()
{
sourceUnitState.clear();
@ -681,6 +702,8 @@ struct TestState
unsigned indentationLevel;
/// Contract scope
bool insideContract;
/// Loop state
LoopState loopState;
/// Source name prefix
std::string const sourceUnitNamePrefix = "su";
/// Contract name prefix
@ -1096,6 +1119,38 @@ private:
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
{
public: