Merge pull request #6658 from ethereum/stringLiterals

[SolYul] String literals
This commit is contained in:
chriseth 2019-05-07 12:28:03 +02:00 committed by GitHub
commit 8a3006a0fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 116 additions and 6 deletions

View File

@ -606,6 +606,9 @@ string YulUtilFunctions::allocationFunction()
string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
{
if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1)
return conversionFunctionSpecial(_from, _to);
string functionName =
"convert_" +
_from.identifier() +
@ -923,3 +926,69 @@ string YulUtilFunctions::suffixedVariableNameList(string const& _baseName, size_
}
return result;
}
string YulUtilFunctions::conversionFunctionSpecial(Type const& _from, Type const& _to)
{
string functionName =
"convert_" +
_from.identifier() +
"_to_" +
_to.identifier();
return m_functionCollector->createFunction(functionName, [&]() {
solUnimplementedAssert(
_from.category() == Type::Category::StringLiteral,
"Type conversion " + _from.toString() + " -> " + _to.toString() + " not yet implemented."
);
string const& data = dynamic_cast<StringLiteralType const&>(_from).value();
if (_to.category() == Type::Category::FixedBytes)
{
unsigned const numBytes = dynamic_cast<FixedBytesType const&>(_to).numBytes();
solAssert(data.size() <= 32, "");
Whiskers templ(R"(
function <functionName>() -> converted {
converted := <data>
}
)");
templ("functionName", functionName);
templ("data", formatNumber(
h256::Arith(h256(data, h256::AlignLeft)) &
(~(u256(-1) >> (8 * numBytes)))
));
return templ.render();
}
else if (_to.category() == Type::Category::Array)
{
auto const& arrayType = dynamic_cast<ArrayType const&>(_to);
solAssert(arrayType.isByteArray(), "");
size_t words = (data.size() + 31) / 32;
size_t storageSize = 32 + words * 32;
Whiskers templ(R"(
function <functionName>() -> converted {
converted := <allocate>(<storageSize>)
mstore(converted, <size>)
<#word>
mstore(add(converted, <offset>), <wordValue>)
</word>
}
)");
templ("functionName", functionName);
templ("allocate", allocationFunction());
templ("storageSize", to_string(storageSize));
templ("size", to_string(data.size()));
vector<map<string, string>> wordParams(words);
for (size_t i = 0; i < words; ++i)
{
wordParams[i]["offset"] = to_string(32 + i * 32);
wordParams[i]["wordValue"] = "0x" + h256(data.substr(32 * i, 32), h256::AlignLeft).hex();
}
templ("word", wordParams);
return templ.render();
}
else
solAssert(
false,
"Invalid conversion from string literal to " + _to.toString() + " requested."
);
});
}

View File

@ -155,6 +155,11 @@ public:
static std::string suffixedVariableNameList(std::string const& _baseName, size_t _startSuffix, size_t _endSuffix);
private:
/// Special case of conversionFunction - handles everything that does not
/// use exactly one variable to hold the value.
std::string conversionFunctionSpecial(Type const& _from, Type const& _to);
langutil::EVMVersion m_evmVersion;
std::shared_ptr<MultiUseYulFunctionCollector> m_functionCollector;
};

View File

@ -357,7 +357,6 @@ bool IRGeneratorForStatements::visit(Literal const& _literal)
defineExpression(_literal) << toCompactHexWithPrefix(literalType.literalValue(&_literal)) << "\n";
break;
case Type::Category::StringLiteral:
solUnimplemented("");
break; // will be done during conversion
default:
solUnimplemented("Only integer, boolean and string literals implemented for now.");
@ -368,12 +367,20 @@ bool IRGeneratorForStatements::visit(Literal const& _literal)
string IRGeneratorForStatements::expressionAsType(Expression const& _expression, Type const& _to)
{
Type const& from = type(_expression);
string varName = m_context.variable(_expression);
if (from == _to)
return varName;
if (from.sizeOnStack() == 0)
{
solAssert(from != _to, "");
return m_utils.conversionFunction(from, _to) + "()";
}
else
return m_utils.conversionFunction(from, _to) + "(" + std::move(varName) + ")";
{
string varName = m_context.variable(_expression);
if (from == _to)
return varName;
else
return m_utils.conversionFunction(from, _to) + "(" + std::move(varName) + ")";
}
}
ostream& IRGeneratorForStatements::defineExpression(Expression const& _expression)

View File

@ -0,0 +1,29 @@
contract C {
function short_dyn() public pure returns (string memory x) {
x = "abc";
}
function long_dyn() public pure returns (string memory x) {
x = "12345678901234567890123456789012345678901234567890123456789012345678901234567890";
}
function short_bytes_dyn() public pure returns (bytes memory x) {
x = "abc";
}
function long_bytes_dyn() public pure returns (bytes memory x) {
x = "12345678901234567890123456789012345678901234567890123456789012345678901234567890";
}
function bytesNN() public pure returns (bytes3 x) {
x = "abc";
}
function bytesNN_padded() public pure returns (bytes4 x) {
x = "abc";
}
}
// ====
// compileViaYul: true
// ----
// short_dyn() -> 0x20, 3, "abc"
// long_dyn() -> 0x20, 80, "12345678901234567890123456789012", "34567890123456789012345678901234", "5678901234567890"
// short_bytes_dyn() -> 0x20, 3, "abc"
// long_bytes_dyn() -> 0x20, 80, "12345678901234567890123456789012", "34567890123456789012345678901234", "5678901234567890"
// bytesNN() -> 0x6162630000000000000000000000000000000000000000000000000000000000
// bytesNN_padded() -> 0x6162630000000000000000000000000000000000000000000000000000000000