mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Adds support for string literals to soltest.
This commit is contained in:
parent
befadea0c6
commit
9956319e8b
@ -20,6 +20,15 @@ contract C {
|
||||
function m(bytes memory b) public returns (bytes memory) {
|
||||
return b;
|
||||
}
|
||||
function n() public returns (string memory) {
|
||||
return "any";
|
||||
}
|
||||
function o() public returns (string memory, string memory) {
|
||||
return ("any", "any");
|
||||
}
|
||||
function p() public returns (string memory, uint, string memory) {
|
||||
return ("any", 42, "any");
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// _() -> FAILURE
|
||||
@ -33,3 +42,6 @@ contract C {
|
||||
// m(bytes): 32, 32, 0x20 -> 32, 32, 0x20
|
||||
// m(bytes): 32, 3, hex"AB33BB" -> 32, 3, left(0xAB33BB)
|
||||
// m(bytes): 32, 3, hex"AB33FF" -> 32, 3, hex"ab33ff0000000000000000000000000000000000000000000000000000000000"
|
||||
// n() -> 0x20, 3, "any"
|
||||
// o() -> 0x40, 0x80, 3, "any", 3, "any"
|
||||
// p() -> 0x60, 0x2a, 0xa0, 3, "any", 3, "any"
|
||||
|
@ -290,11 +290,22 @@ tuple<bytes, ABIType, string> TestFileParser::parseABITypeLiteral()
|
||||
throw Error(Error::Type::ParserError, "Invalid hex string literal.");
|
||||
if (alignment != DeclaredAlignment::None)
|
||||
throw Error(Error::Type::ParserError, "Hex string literals cannot be aligned or padded.");
|
||||
string parsed = parseHexNumber();
|
||||
string parsed = parseString();
|
||||
rawString += "hex\"" + parsed + "\"";
|
||||
result = convertHexString(parsed);
|
||||
result = convertHexNumber(parsed);
|
||||
abiType = ABIType{ABIType::HexString, ABIType::AlignNone, result.size()};
|
||||
}
|
||||
else if (accept(Token::String))
|
||||
{
|
||||
if (isSigned)
|
||||
throw Error(Error::Type::ParserError, "Invalid string literal.");
|
||||
if (alignment != DeclaredAlignment::None)
|
||||
throw Error(Error::Type::ParserError, "String literals cannot be aligned or padded.");
|
||||
abiType = ABIType{ABIType::String, ABIType::AlignLeft, 32};
|
||||
string parsed = parseString();
|
||||
rawString += "\"" + parsed + "\"";
|
||||
result = applyAlign(DeclaredAlignment::Left, abiType, convertString(parsed));
|
||||
}
|
||||
else if (accept(Token::Number))
|
||||
{
|
||||
auto type = isSigned ? ABIType::SignedDec : ABIType::UnsignedDec;
|
||||
@ -395,6 +406,13 @@ string TestFileParser::parseHexNumber()
|
||||
return literal;
|
||||
}
|
||||
|
||||
string TestFileParser::parseString()
|
||||
{
|
||||
string literal = m_scanner.currentLiteral();
|
||||
expect(Token::String);
|
||||
return literal;
|
||||
}
|
||||
|
||||
bytes TestFileParser::convertBoolean(string const& _literal)
|
||||
{
|
||||
if (_literal == "true")
|
||||
@ -422,13 +440,9 @@ bytes TestFileParser::convertHexNumber(string const& _literal)
|
||||
try
|
||||
{
|
||||
if (_literal.size() % 2)
|
||||
{
|
||||
throw Error(Error::Type::ParserError, "Hex number encoding invalid.");
|
||||
}
|
||||
else
|
||||
{
|
||||
return fromHex(_literal);
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
@ -436,18 +450,15 @@ bytes TestFileParser::convertHexNumber(string const& _literal)
|
||||
}
|
||||
}
|
||||
|
||||
bytes TestFileParser::convertHexString(string const& _literal)
|
||||
bytes TestFileParser::convertString(string const& _literal)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_literal.size() % 2)
|
||||
throw Error(Error::Type::ParserError, "Hex string encoding invalid.");
|
||||
else
|
||||
return fromHex(_literal);
|
||||
return asBytes(_literal);
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
throw Error(Error::Type::ParserError, "Hex string encoding invalid.");
|
||||
throw Error(Error::Type::ParserError, "String encoding invalid.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -525,9 +536,7 @@ void TestFileParser::Scanner::scanNextToken()
|
||||
token = selectToken(Token::RBrack);
|
||||
break;
|
||||
case '\"':
|
||||
advance();
|
||||
token = selectToken(Token::HexNumber, scanHexNumber());
|
||||
advance();
|
||||
token = selectToken(Token::String, scanString());
|
||||
break;
|
||||
default:
|
||||
if (isIdentifierStart(current()))
|
||||
@ -610,3 +619,16 @@ string TestFileParser::Scanner::scanHexNumber()
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
string TestFileParser::Scanner::scanString()
|
||||
{
|
||||
string str;
|
||||
advance();
|
||||
|
||||
while (current() != '\"')
|
||||
{
|
||||
str += current();
|
||||
advance();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ namespace test
|
||||
T(Comment, "#", 0) \
|
||||
T(Number, "number", 0) \
|
||||
T(HexNumber, "hex_number", 0) \
|
||||
T(String, "string", 0) \
|
||||
T(Identifier, "identifier", 0) \
|
||||
/* type keywords */ \
|
||||
K(Ether, "ether", 0) \
|
||||
@ -111,7 +112,8 @@ struct ABIType
|
||||
UnsignedDec,
|
||||
SignedDec,
|
||||
Hex,
|
||||
HexString
|
||||
HexString,
|
||||
String
|
||||
};
|
||||
enum Align
|
||||
{
|
||||
@ -300,6 +302,7 @@ private:
|
||||
std::string scanIdentifierOrKeyword();
|
||||
std::string scanDecimalNumber();
|
||||
std::string scanHexNumber();
|
||||
std::string scanString();
|
||||
|
||||
private:
|
||||
using TokenDesc = std::pair<Token, std::string>;
|
||||
@ -375,6 +378,9 @@ private:
|
||||
/// Parses the current hex number literal.
|
||||
std::string parseHexNumber();
|
||||
|
||||
/// Parses the current string literal.
|
||||
std::string parseString();
|
||||
|
||||
/// Tries to convert \param _literal to an unpadded `bytes`
|
||||
/// representation of the boolean number literal. Throws if conversion fails.
|
||||
bytes convertBoolean(std::string const& _literal);
|
||||
@ -387,9 +393,9 @@ private:
|
||||
/// representation of the hex literal. Throws if conversion fails.
|
||||
bytes convertHexNumber(std::string const& _literal);
|
||||
|
||||
/// Tries to convert \param _literal to left-aligned, unpadded `bytes`
|
||||
/// representation of the hex string literal. Throws if conversion fails.
|
||||
bytes convertHexString(std::string const& _literal);
|
||||
/// Tries to convert \param _literal to an unpadded `bytes`
|
||||
/// representation of the string literal. Throws if conversion fails.
|
||||
bytes convertString(std::string const& _literal);
|
||||
|
||||
/// A scanner instance
|
||||
Scanner m_scanner;
|
||||
|
@ -344,6 +344,39 @@ BOOST_AUTO_TEST_CASE(call_arguments_hex_string_lowercase)
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(call_arguments_string)
|
||||
{
|
||||
char const* source = R"(
|
||||
// f(string): 0x20, 3, "any" ->
|
||||
)";
|
||||
auto const calls = parse(source);
|
||||
BOOST_REQUIRE_EQUAL(calls.size(), 1);
|
||||
testFunctionCall(
|
||||
calls.at(0),
|
||||
Mode::SingleLine,
|
||||
"f(string)",
|
||||
false,
|
||||
fmt::encodeDyn(string{"any"})
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(call_return_string)
|
||||
{
|
||||
char const* source = R"(
|
||||
// f() -> 0x20, 3, "any"
|
||||
)";
|
||||
auto const calls = parse(source);
|
||||
BOOST_REQUIRE_EQUAL(calls.size(), 1);
|
||||
testFunctionCall(
|
||||
calls.at(0),
|
||||
Mode::SingleLine,
|
||||
"f()",
|
||||
false,
|
||||
fmt::encodeArgs(),
|
||||
fmt::encodeDyn(string{"any"})
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(call_arguments_tuple)
|
||||
{
|
||||
char const* source = R"(
|
||||
|
@ -35,6 +35,7 @@ static regex s_uintType{"(uint\\d*)"};
|
||||
static regex s_intType{"(int\\d*)"};
|
||||
static regex s_bytesType{"(bytes\\d+)"};
|
||||
static regex s_dynBytesType{"(\\bbytes\\b)"};
|
||||
static regex s_stringType{"(string)"};
|
||||
|
||||
/// Translates Solidity's ABI types into the internal type representation of
|
||||
/// soltest.
|
||||
@ -55,6 +56,12 @@ auto contractABITypes(string const& _type) -> vector<ABIType>
|
||||
abiTypes.push_back(ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32});
|
||||
abiTypes.push_back(ABIType{ABIType::HexString, ABIType::AlignLeft, 32});
|
||||
}
|
||||
else if (regex_match(_type, s_stringType))
|
||||
{
|
||||
abiTypes.push_back(ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32});
|
||||
abiTypes.push_back(ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32});
|
||||
abiTypes.push_back(ABIType{ABIType::String, ABIType::AlignLeft, 32});
|
||||
}
|
||||
else
|
||||
abiTypes.push_back(ABIType{ABIType::None, ABIType::AlignRight, 0});
|
||||
return abiTypes;
|
||||
@ -319,6 +326,25 @@ string TestFunctionCall::formatBytesRange(
|
||||
case ABIType::HexString:
|
||||
os << "hex\"" << toHex(_bytes) << "\"";
|
||||
break;
|
||||
case ABIType::String:
|
||||
{
|
||||
os << "\"";
|
||||
bool expectZeros = false;
|
||||
for (auto const& v: _bytes)
|
||||
{
|
||||
if (expectZeros && v != 0)
|
||||
return {};
|
||||
if (v == 0) expectZeros = true;
|
||||
else
|
||||
{
|
||||
if (!isprint(v) || v == '"')
|
||||
return {};
|
||||
os << v;
|
||||
}
|
||||
}
|
||||
os << "\"";
|
||||
break;
|
||||
}
|
||||
case ABIType::Failure:
|
||||
break;
|
||||
case ABIType::None:
|
||||
|
Loading…
Reference in New Issue
Block a user