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) {
|
function m(bytes memory b) public returns (bytes memory) {
|
||||||
return b;
|
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
|
// _() -> FAILURE
|
||||||
@ -33,3 +42,6 @@ contract C {
|
|||||||
// m(bytes): 32, 32, 0x20 -> 32, 32, 0x20
|
// m(bytes): 32, 32, 0x20 -> 32, 32, 0x20
|
||||||
// m(bytes): 32, 3, hex"AB33BB" -> 32, 3, left(0xAB33BB)
|
// m(bytes): 32, 3, hex"AB33BB" -> 32, 3, left(0xAB33BB)
|
||||||
// m(bytes): 32, 3, hex"AB33FF" -> 32, 3, hex"ab33ff0000000000000000000000000000000000000000000000000000000000"
|
// 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.");
|
throw Error(Error::Type::ParserError, "Invalid hex string literal.");
|
||||||
if (alignment != DeclaredAlignment::None)
|
if (alignment != DeclaredAlignment::None)
|
||||||
throw Error(Error::Type::ParserError, "Hex string literals cannot be aligned or padded.");
|
throw Error(Error::Type::ParserError, "Hex string literals cannot be aligned or padded.");
|
||||||
string parsed = parseHexNumber();
|
string parsed = parseString();
|
||||||
rawString += "hex\"" + parsed + "\"";
|
rawString += "hex\"" + parsed + "\"";
|
||||||
result = convertHexString(parsed);
|
result = convertHexNumber(parsed);
|
||||||
abiType = ABIType{ABIType::HexString, ABIType::AlignNone, result.size()};
|
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))
|
else if (accept(Token::Number))
|
||||||
{
|
{
|
||||||
auto type = isSigned ? ABIType::SignedDec : ABIType::UnsignedDec;
|
auto type = isSigned ? ABIType::SignedDec : ABIType::UnsignedDec;
|
||||||
@ -395,6 +406,13 @@ string TestFileParser::parseHexNumber()
|
|||||||
return literal;
|
return literal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string TestFileParser::parseString()
|
||||||
|
{
|
||||||
|
string literal = m_scanner.currentLiteral();
|
||||||
|
expect(Token::String);
|
||||||
|
return literal;
|
||||||
|
}
|
||||||
|
|
||||||
bytes TestFileParser::convertBoolean(string const& _literal)
|
bytes TestFileParser::convertBoolean(string const& _literal)
|
||||||
{
|
{
|
||||||
if (_literal == "true")
|
if (_literal == "true")
|
||||||
@ -422,13 +440,9 @@ bytes TestFileParser::convertHexNumber(string const& _literal)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_literal.size() % 2)
|
if (_literal.size() % 2)
|
||||||
{
|
|
||||||
throw Error(Error::Type::ParserError, "Hex number encoding invalid.");
|
throw Error(Error::Type::ParserError, "Hex number encoding invalid.");
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return fromHex(_literal);
|
return fromHex(_literal);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (std::exception const&)
|
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
|
try
|
||||||
{
|
{
|
||||||
if (_literal.size() % 2)
|
return asBytes(_literal);
|
||||||
throw Error(Error::Type::ParserError, "Hex string encoding invalid.");
|
|
||||||
else
|
|
||||||
return fromHex(_literal);
|
|
||||||
}
|
}
|
||||||
catch (std::exception const&)
|
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);
|
token = selectToken(Token::RBrack);
|
||||||
break;
|
break;
|
||||||
case '\"':
|
case '\"':
|
||||||
advance();
|
token = selectToken(Token::String, scanString());
|
||||||
token = selectToken(Token::HexNumber, scanHexNumber());
|
|
||||||
advance();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (isIdentifierStart(current()))
|
if (isIdentifierStart(current()))
|
||||||
@ -610,3 +619,16 @@ string TestFileParser::Scanner::scanHexNumber()
|
|||||||
}
|
}
|
||||||
return number;
|
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(Comment, "#", 0) \
|
||||||
T(Number, "number", 0) \
|
T(Number, "number", 0) \
|
||||||
T(HexNumber, "hex_number", 0) \
|
T(HexNumber, "hex_number", 0) \
|
||||||
|
T(String, "string", 0) \
|
||||||
T(Identifier, "identifier", 0) \
|
T(Identifier, "identifier", 0) \
|
||||||
/* type keywords */ \
|
/* type keywords */ \
|
||||||
K(Ether, "ether", 0) \
|
K(Ether, "ether", 0) \
|
||||||
@ -111,7 +112,8 @@ struct ABIType
|
|||||||
UnsignedDec,
|
UnsignedDec,
|
||||||
SignedDec,
|
SignedDec,
|
||||||
Hex,
|
Hex,
|
||||||
HexString
|
HexString,
|
||||||
|
String
|
||||||
};
|
};
|
||||||
enum Align
|
enum Align
|
||||||
{
|
{
|
||||||
@ -300,6 +302,7 @@ private:
|
|||||||
std::string scanIdentifierOrKeyword();
|
std::string scanIdentifierOrKeyword();
|
||||||
std::string scanDecimalNumber();
|
std::string scanDecimalNumber();
|
||||||
std::string scanHexNumber();
|
std::string scanHexNumber();
|
||||||
|
std::string scanString();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using TokenDesc = std::pair<Token, std::string>;
|
using TokenDesc = std::pair<Token, std::string>;
|
||||||
@ -375,6 +378,9 @@ private:
|
|||||||
/// Parses the current hex number literal.
|
/// Parses the current hex number literal.
|
||||||
std::string parseHexNumber();
|
std::string parseHexNumber();
|
||||||
|
|
||||||
|
/// Parses the current string literal.
|
||||||
|
std::string parseString();
|
||||||
|
|
||||||
/// Tries to convert \param _literal to an unpadded `bytes`
|
/// Tries to convert \param _literal to an unpadded `bytes`
|
||||||
/// representation of the boolean number literal. Throws if conversion fails.
|
/// representation of the boolean number literal. Throws if conversion fails.
|
||||||
bytes convertBoolean(std::string const& _literal);
|
bytes convertBoolean(std::string const& _literal);
|
||||||
@ -387,9 +393,9 @@ private:
|
|||||||
/// representation of the hex literal. Throws if conversion fails.
|
/// representation of the hex literal. Throws if conversion fails.
|
||||||
bytes convertHexNumber(std::string const& _literal);
|
bytes convertHexNumber(std::string const& _literal);
|
||||||
|
|
||||||
/// Tries to convert \param _literal to left-aligned, unpadded `bytes`
|
/// Tries to convert \param _literal to an unpadded `bytes`
|
||||||
/// representation of the hex string literal. Throws if conversion fails.
|
/// representation of the string literal. Throws if conversion fails.
|
||||||
bytes convertHexString(std::string const& _literal);
|
bytes convertString(std::string const& _literal);
|
||||||
|
|
||||||
/// A scanner instance
|
/// A scanner instance
|
||||||
Scanner m_scanner;
|
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)
|
BOOST_AUTO_TEST_CASE(call_arguments_tuple)
|
||||||
{
|
{
|
||||||
char const* source = R"(
|
char const* source = R"(
|
||||||
|
@ -35,6 +35,7 @@ static regex s_uintType{"(uint\\d*)"};
|
|||||||
static regex s_intType{"(int\\d*)"};
|
static regex s_intType{"(int\\d*)"};
|
||||||
static regex s_bytesType{"(bytes\\d+)"};
|
static regex s_bytesType{"(bytes\\d+)"};
|
||||||
static regex s_dynBytesType{"(\\bbytes\\b)"};
|
static regex s_dynBytesType{"(\\bbytes\\b)"};
|
||||||
|
static regex s_stringType{"(string)"};
|
||||||
|
|
||||||
/// Translates Solidity's ABI types into the internal type representation of
|
/// Translates Solidity's ABI types into the internal type representation of
|
||||||
/// soltest.
|
/// 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::UnsignedDec, ABIType::AlignRight, 32});
|
||||||
abiTypes.push_back(ABIType{ABIType::HexString, ABIType::AlignLeft, 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
|
else
|
||||||
abiTypes.push_back(ABIType{ABIType::None, ABIType::AlignRight, 0});
|
abiTypes.push_back(ABIType{ABIType::None, ABIType::AlignRight, 0});
|
||||||
return abiTypes;
|
return abiTypes;
|
||||||
@ -319,6 +326,25 @@ string TestFunctionCall::formatBytesRange(
|
|||||||
case ABIType::HexString:
|
case ABIType::HexString:
|
||||||
os << "hex\"" << toHex(_bytes) << "\"";
|
os << "hex\"" << toHex(_bytes) << "\"";
|
||||||
break;
|
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:
|
case ABIType::Failure:
|
||||||
break;
|
break;
|
||||||
case ABIType::None:
|
case ABIType::None:
|
||||||
|
Loading…
Reference in New Issue
Block a user