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)
|
string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
||||||
{
|
{
|
||||||
|
if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1)
|
||||||
|
return conversionFunctionSpecial(_from, _to);
|
||||||
|
|
||||||
string functionName =
|
string functionName =
|
||||||
"convert_" +
|
"convert_" +
|
||||||
_from.identifier() +
|
_from.identifier() +
|
||||||
@ -923,3 +926,69 @@ string YulUtilFunctions::suffixedVariableNameList(string const& _baseName, size_
|
|||||||
}
|
}
|
||||||
return result;
|
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);
|
static std::string suffixedVariableNameList(std::string const& _baseName, size_t _startSuffix, size_t _endSuffix);
|
||||||
|
|
||||||
private:
|
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;
|
langutil::EVMVersion m_evmVersion;
|
||||||
std::shared_ptr<MultiUseYulFunctionCollector> m_functionCollector;
|
std::shared_ptr<MultiUseYulFunctionCollector> m_functionCollector;
|
||||||
};
|
};
|
||||||
|
@ -357,7 +357,6 @@ bool IRGeneratorForStatements::visit(Literal const& _literal)
|
|||||||
defineExpression(_literal) << toCompactHexWithPrefix(literalType.literalValue(&_literal)) << "\n";
|
defineExpression(_literal) << toCompactHexWithPrefix(literalType.literalValue(&_literal)) << "\n";
|
||||||
break;
|
break;
|
||||||
case Type::Category::StringLiteral:
|
case Type::Category::StringLiteral:
|
||||||
solUnimplemented("");
|
|
||||||
break; // will be done during conversion
|
break; // will be done during conversion
|
||||||
default:
|
default:
|
||||||
solUnimplemented("Only integer, boolean and string literals implemented for now.");
|
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)
|
string IRGeneratorForStatements::expressionAsType(Expression const& _expression, Type const& _to)
|
||||||
{
|
{
|
||||||
Type const& from = type(_expression);
|
Type const& from = type(_expression);
|
||||||
string varName = m_context.variable(_expression);
|
if (from.sizeOnStack() == 0)
|
||||||
|
{
|
||||||
if (from == _to)
|
solAssert(from != _to, "");
|
||||||
return varName;
|
return m_utils.conversionFunction(from, _to) + "()";
|
||||||
|
}
|
||||||
else
|
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)
|
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