mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #6658 from ethereum/stringLiterals
[SolYul] String literals
This commit is contained in:
commit
8a3006a0fa
@ -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."
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
|
29
test/libsolidity/semanticTests/viaYul/string_literals.sol
Normal file
29
test/libsolidity/semanticTests/viaYul/string_literals.sol
Normal 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
|
Loading…
Reference in New Issue
Block a user