Skip to content

Commit ecf21ff

Browse files
committed
Adds support for hex literals in soltest.
1 parent 54d6804 commit ecf21ff

File tree

6 files changed

+133
-16
lines changed

6 files changed

+133
-16
lines changed

Changelog.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Bugfixes:
2121

2222

2323
Build System:
24-
24+
* Soltest: Add support for left-aligned, padded hex literals.
2525

2626
### 0.5.4 (2019-02-12)
2727

test/libsolidity/semanticTests/smoke_test.sol

+4
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@ contract C {
88
function h() public payable returns (uint) {
99
return f();
1010
}
11+
function x(bytes32 b) public returns (bytes32) {
12+
return b;
13+
}
1114
}
1215
// ----
1316
// f() -> 1
1417
// g(uint256,uint256): 1, -2 -> 3
1518
// h(), 1 ether -> 1
1619
// j() -> FAILURE
1720
// i() # Does not exist. # -> FAILURE # Reverts. #
21+
// x(bytes32): 0x31 -> 0x31

test/libsolidity/util/TestFileParser.cpp

+64-8
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ string TestFileParser::parseFunctionSignature()
137137

138138
u256 TestFileParser::parseFunctionCallValue()
139139
{
140-
u256 value = convertNumber(parseNumber());
140+
u256 value = convertNumber(parseDecimalNumber());
141141
expect(Token::Ether);
142142
return value;
143143
}
@@ -203,16 +203,23 @@ tuple<bytes, ABIType, string> TestFileParser::parseABITypeLiteral()
203203
abiType = ABIType{ABIType::SignedDec, ABIType::AlignRight, 32};
204204
expect(Token::Sub);
205205
rawString += formatToken(Token::Sub);
206-
string parsed = parseNumber();
206+
string parsed = parseDecimalNumber();
207207
rawString += parsed;
208208
number = convertNumber(parsed) * -1;
209209
}
210210
else
211211
{
212-
if (accept(Token::Number))
212+
if (accept(Token::HexNumber))
213+
{
214+
abiType = ABIType{ABIType::Hex, ABIType::AlignLeft, 32};
215+
string parsed = parseHexNumber();
216+
rawString += parsed;
217+
return make_tuple(convertHexNumber(parsed), abiType, rawString);
218+
}
219+
else if (accept(Token::Number))
213220
{
214221
abiType = ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32};
215-
string parsed = parseNumber();
222+
string parsed = parseDecimalNumber();
216223
rawString += parsed;
217224
number = convertNumber(parsed);
218225
}
@@ -263,16 +270,24 @@ string TestFileParser::parseComment()
263270
return string{};
264271
}
265272

266-
string TestFileParser::parseNumber()
273+
string TestFileParser::parseDecimalNumber()
267274
{
268275
string literal = m_scanner.currentLiteral();
269276
expect(Token::Number);
270277
return literal;
271278
}
272279

280+
string TestFileParser::parseHexNumber()
281+
{
282+
string literal = m_scanner.currentLiteral();
283+
expect(Token::HexNumber);
284+
return literal;
285+
}
286+
273287
u256 TestFileParser::convertNumber(string const& _literal)
274288
{
275-
try {
289+
try
290+
{
276291
return u256{_literal};
277292
}
278293
catch (std::exception const&)
@@ -281,6 +296,26 @@ u256 TestFileParser::convertNumber(string const& _literal)
281296
}
282297
}
283298

299+
bytes TestFileParser::convertHexNumber(string const& _literal)
300+
{
301+
try
302+
{
303+
if (_literal.size() % 2)
304+
{
305+
throw Error(Error::Type::ParserError, "Hex number encoding invalid.");
306+
}
307+
else
308+
{
309+
bytes result = fromHex(_literal);
310+
return result + bytes(32 - result.size(), 0);
311+
}
312+
}
313+
catch (std::exception const&)
314+
{
315+
throw Error(Error::Type::ParserError, "Hex number encoding invalid.");
316+
}
317+
}
318+
284319
void TestFileParser::Scanner::readStream(istream& _stream)
285320
{
286321
std::string line;
@@ -348,7 +383,16 @@ void TestFileParser::Scanner::scanNextToken()
348383
token = selectToken(detectedToken.first, detectedToken.second);
349384
}
350385
else if (langutil::isDecimalDigit(current()))
351-
token = selectToken(Token::Number, scanNumber());
386+
{
387+
if (current() == '0' && peek() == 'x')
388+
{
389+
advance();
390+
advance();
391+
token = selectToken(Token::HexNumber, "0x" + scanHexNumber());
392+
}
393+
else
394+
token = selectToken(Token::Number, scanDecimalNumber());
395+
}
352396
else if (langutil::isWhiteSpace(current()))
353397
token = selectToken(Token::Whitespace);
354398
else if (isEndOfLine())
@@ -385,7 +429,7 @@ string TestFileParser::Scanner::scanIdentifierOrKeyword()
385429
return identifier;
386430
}
387431

388-
string TestFileParser::Scanner::scanNumber()
432+
string TestFileParser::Scanner::scanDecimalNumber()
389433
{
390434
string number;
391435
number += current();
@@ -396,3 +440,15 @@ string TestFileParser::Scanner::scanNumber()
396440
}
397441
return number;
398442
}
443+
444+
string TestFileParser::Scanner::scanHexNumber()
445+
{
446+
string number;
447+
number += current();
448+
while (langutil::isHexDigit(peek()))
449+
{
450+
advance();
451+
number += current();
452+
}
453+
return number;
454+
}

test/libsolidity/util/TestFileParser.h

+17-7
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ namespace test
5656
/* Literals & identifier */ \
5757
T(Comment, "#", 0) \
5858
T(Number, "number", 0) \
59+
T(HexNumber, "hex_number", 0) \
5960
T(Identifier, "identifier", 0) \
6061
/* type keywords */ \
6162
K(Ether, "ether", 0) \
@@ -102,18 +103,18 @@ struct ABIType
102103
{
103104
UnsignedDec,
104105
SignedDec,
106+
Hex,
105107
Failure,
106108
None
107109
};
108-
109110
enum Align
110111
{
111112
AlignLeft,
112113
AlignRight
113114
};
114115

115116
Type type = ABIType::None;
116-
Align align = Align::AlignRight;
117+
Align align = ABIType::AlignRight;
117118
size_t size = 0;
118119
};
119120

@@ -290,7 +291,8 @@ class TestFileParser
290291

291292
std::string scanComment();
292293
std::string scanIdentifierOrKeyword();
293-
std::string scanNumber();
294+
std::string scanDecimalNumber();
295+
std::string scanHexNumber();
294296

295297
private:
296298
using TokenDesc = std::pair<Token, std::string>;
@@ -357,13 +359,21 @@ class TestFileParser
357359
/// # A nice comment. #
358360
std::string parseComment();
359361

360-
/// Parses the current number literal.
361-
std::string parseNumber();
362+
/// Parses the current decimal number literal.
363+
std::string parseDecimalNumber();
364+
365+
/// Parses the current hex number literal.
366+
std::string parseHexNumber();
362367

363-
/// Tries to convert \param _literal to `uint256` and throws if
364-
/// conversion fails.
368+
/// Tries to convert \param _literal to right-aligned, padded `u256`
369+
/// representation of the decimal number literal.
370+
/// Throws if conversion fails.
365371
u256 convertNumber(std::string const& _literal);
366372

373+
/// Tries to convert \param _literal to left-aligned, padded `bytes`
374+
/// representation of the hex literal. Throws if conversion fails.
375+
bytes convertHexNumber(std::string const& _literal);
376+
367377
/// A scanner instance
368378
Scanner m_scanner;
369379
};

test/libsolidity/util/TestFileParserTests.cpp

+40
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,38 @@ BOOST_AUTO_TEST_CASE(call_arguments_tuple)
305305
testFunctionCall(calls.at(1), Mode::SingleLine, "f((uint8),uint8)", false);
306306
}
307307

308+
BOOST_AUTO_TEST_CASE(call_arguments_left_aligned)
309+
{
310+
char const* source = R"(
311+
// f(bytes32, bytes32): 0x6161, 0x420000EF -> 1
312+
// g(bytes32, bytes32): 0x0616, 0x0042EF00 -> 1
313+
)";
314+
auto const calls = parse(source);
315+
BOOST_REQUIRE_EQUAL(calls.size(), 2);
316+
testFunctionCall(
317+
calls.at(0),
318+
Mode::SingleLine,
319+
"f(bytes32,bytes32)",
320+
false,
321+
fmt::encodeArgs(
322+
u256("0x6161000000000000000000000000000000000000000000000000000000000000"),
323+
u256("0x420000EF00000000000000000000000000000000000000000000000000000000")
324+
),
325+
fmt::encodeArgs(1)
326+
);
327+
testFunctionCall(
328+
calls.at(1),
329+
Mode::SingleLine,
330+
"g(bytes32,bytes32)",
331+
false,
332+
fmt::encodeArgs(
333+
u256("0x0616000000000000000000000000000000000000000000000000000000000000"),
334+
u256("0x0042EF0000000000000000000000000000000000000000000000000000000000")
335+
),
336+
fmt::encodeArgs(1)
337+
);
338+
}
339+
308340
BOOST_AUTO_TEST_CASE(call_arguments_tuple_of_tuples)
309341
{
310342
char const* source = R"(
@@ -546,6 +578,14 @@ BOOST_AUTO_TEST_CASE(call_ether_type_invalid)
546578
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
547579
}
548580

581+
BOOST_AUTO_TEST_CASE(call_hex_number_invalid)
582+
{
583+
char const* source = R"(
584+
// f(bytes32, bytes32): 0x616, 0x042 -> 1
585+
)";
586+
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
587+
}
588+
549589
BOOST_AUTO_TEST_CASE(call_arguments_colon)
550590
{
551591
char const* source = R"(

test/libsolidity/util/TestFunctionCall.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ string TestFunctionCall::formatBytesParameters(bytes const& _bytes, ParameterLis
144144
else
145145
resultStream << fromBigEndian<u256>(byteRange);
146146
break;
147+
case ABIType::Hex:
148+
soltestAssert(param.abiType.align == ABIType::AlignLeft, "Hex numbers must be left-aligned.");
149+
byteRange.erase(
150+
std::remove(byteRange.begin(), byteRange.end(), 0), byteRange.end()
151+
);
152+
resultStream << toHex(byteRange, HexPrefix::Add);
153+
break;
147154
case ABIType::Failure:
148155
break;
149156
case ABIType::None:

0 commit comments

Comments
 (0)