Add assignment statement.

This commit is contained in:
Bhargava Shastry 2021-04-30 14:20:16 +02:00
parent 4b40b40bb6
commit f6242ef6b7
3 changed files with 124 additions and 7 deletions

View File

@ -41,6 +41,7 @@
*
*/
#define GENERATORLIST(MACRO, SEP, ENDSEP) \
MACRO(AssignmentStmtGenerator) SEP \
MACRO(BlockStmtGenerator) SEP \
MACRO(ContractGenerator) SEP \
MACRO(FunctionGenerator) SEP \

View File

@ -265,9 +265,51 @@ string FunctionState::params(Params _p)
return "(" + boost::algorithm::join(params, ",") + ")";
}
string AssignmentStmtGenerator::visit()
{
ExpressionGenerator exprGen{state};
auto lhs = exprGen.expression();
if (!lhs.has_value())
return "\n";
auto rhs = exprGen.expression(lhs.value().first);
if (!rhs.has_value())
return "\n";
return lhs.value().second + " = " + rhs.value().second + ";\n";
}
void StatementGenerator::setup()
{
addGenerators({
{mutator->generator<BlockStmtGenerator>(), 1},
{mutator->generator<AssignmentStmtGenerator>(), 1}
});
}
string StatementGenerator::visit()
{
return visitChildren();
}
void BlockStmtGenerator::setup()
{
addGenerators({
{mutator->generator<StatementGenerator>(), s_maxStatements},
});
}
string BlockStmtGenerator::visit()
{
return "\n" + indentation() + "{}\n";
if (nestingTooDeep())
return "\n";
incrementNestingDepth();
ostringstream block;
block << indentation() + "{\n";
state->indent();
block << visitChildren();
state->unindent();
block << indentation() << "}\n";
return block.str();
}
void FunctionGenerator::setup()
@ -303,10 +345,54 @@ string FunctionGenerator::visit()
if (!state->currentFunctionState()->outputs.empty())
function << " returns"
<< state->currentFunctionState()->params(FunctionState::Params::OUTPUT);
function << generator<BlockStmtGenerator>()->visit();
function << "\n" << generator<BlockStmtGenerator>()->visit();
return function.str();
}
pair<SolidityTypePtr, string> ExpressionGenerator::randomLValueExpression()
{
LValueExpr exprType = static_cast<LValueExpr>(
state->uRandDist->distributionOneToN(static_cast<size_t>(LValueExpr::TYPEMAX) - 1)
);
switch (exprType)
{
case LValueExpr::VARREF:
{
auto liveVariables = state->currentFunctionState()->inputs |
ranges::views::transform([](auto& _item) { return _item; }) |
ranges::to<vector<pair<SolidityTypePtr, string>>>();
liveVariables += state->currentFunctionState()->outputs |
ranges::views::transform([](auto& _item) { return _item; }) |
ranges::to<vector<pair<SolidityTypePtr, string>>>();
return liveVariables[state->uRandDist->distributionOneToN(liveVariables.size()) - 1];
}
default:
solAssert(false, "");
}
}
optional<pair<SolidityTypePtr, string>> ExpressionGenerator::expression()
{
auto currentFunctionState = state->currentFunctionState();
// TODO: Remove this barrier once we support more expression types.
if (currentFunctionState->inputs.empty() && currentFunctionState->outputs.empty())
return nullopt;
return randomLValueExpression();
}
optional<pair<SolidityTypePtr, string>> ExpressionGenerator::expression(SolidityTypePtr _type)
{
auto liveTypedVariables = state->currentFunctionState()->inputs |
ranges::views::filter([&_type](auto& _item) { return _item.first == _type; }) |
ranges::to<vector<pair<SolidityTypePtr, string>>>();
liveTypedVariables += state->currentFunctionState()->outputs |
ranges::views::filter([&_type](auto& _item) { return _item.first == _type; }) |
ranges::to<vector<pair<SolidityTypePtr, string>>>();
if (liveTypedVariables.empty())
return nullopt;
return liveTypedVariables[state->uRandDist->distributionOneToN(liveTypedVariables.size()) - 1];
}
optional<SolidityTypePtr> TypeProvider::type(SolidityTypePtr _type)
{
vector<SolidityTypePtr> matchingTypes = state->currentFunctionState()->inputs |

View File

@ -619,13 +619,15 @@ struct ExpressionGenerator
ExpressionGenerator(std::shared_ptr<TestState> _state): state(std::move(_state))
{}
enum class Expr: size_t
enum class LValueExpr: size_t
{
VARREF = 1,
TYPEMAX
};
std::string expression(SolidityTypePtr _type);
std::optional<std::pair<SolidityTypePtr, std::string>> expression(SolidityTypePtr _type);
std::optional<std::pair<SolidityTypePtr, std::string>> expression();
std::pair<SolidityTypePtr, std::string> randomLValueExpression();
std::shared_ptr<TestState> state;
};
@ -807,19 +809,47 @@ public:
explicit StatementGenerator(std::shared_ptr<SolidityGenerator> _mutator):
GeneratorBase(std::move(_mutator))
{}
void setup() override {}
std::string visit() override { return {}; }
void setup() override;
std::string visit() override;
std::string name() override { return "Statement generator"; }
};
class AssignmentStmtGenerator: public GeneratorBase
{
public:
explicit AssignmentStmtGenerator(std::shared_ptr<SolidityGenerator> _mutator):
GeneratorBase(std::move(_mutator))
{}
std::string visit() override;
std::string name() override { return "Assignment statement generator"; }
};
class BlockStmtGenerator: public GeneratorBase
{
public:
explicit BlockStmtGenerator(std::shared_ptr<SolidityGenerator> _mutator):
GeneratorBase(std::move(_mutator))
GeneratorBase(std::move(_mutator)),
m_nestingDepth(0)
{}
void endVisit() override
{
m_nestingDepth = 0;
}
void incrementNestingDepth()
{
++m_nestingDepth;
}
bool nestingTooDeep()
{
return m_nestingDepth > s_maxNestingDepth;
}
void setup() override;
std::string visit() override;
std::string name() override { return "Block statement generator"; }
private:
size_t m_nestingDepth;
static constexpr unsigned s_maxStatements = 4;
static constexpr unsigned s_maxNestingDepth = 3;
};
class SolidityGenerator: public std::enable_shared_from_this<SolidityGenerator>