Skip to content

Commit c9c4578

Browse files
committed
Adds support for tuples in test file parser.
1 parent 161b22b commit c9c4578

File tree

3 files changed

+256
-100
lines changed

3 files changed

+256
-100
lines changed

test/libsolidity/util/TestFileParser.cpp

+97-81
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ using namespace langutil;
3131
using namespace solidity;
3232
using namespace dev::solidity::test;
3333
using namespace std;
34+
using namespace soltest;
3435

3536
namespace
3637
{
@@ -47,14 +48,14 @@ namespace
4748
vector<dev::solidity::test::FunctionCall> TestFileParser::parseFunctionCalls()
4849
{
4950
vector<FunctionCall> calls;
50-
if (!accept(SoltToken::EOS))
51+
if (!accept(Token::EOS))
5152
{
52-
assert(m_scanner.currentToken() == SoltToken::Unknown);
53+
assert(m_scanner.currentToken() == Token::Unknown);
5354
m_scanner.scanNextToken();
5455

55-
while (!accept(SoltToken::EOS))
56+
while (!accept(Token::EOS))
5657
{
57-
if (!accept(SoltToken::Whitespace))
58+
if (!accept(Token::Whitespace))
5859
{
5960
FunctionCall call;
6061

@@ -64,63 +65,47 @@ vector<dev::solidity::test::FunctionCall> TestFileParser::parseFunctionCalls()
6465
/// token lookahead that checks parseParameter
6566
/// if the next token is an identifier.
6667
if (calls.empty())
67-
expect(SoltToken::Newline);
68+
expect(Token::Newline);
6869
else
69-
accept(SoltToken::Newline, true);
70+
accept(Token::Newline, true);
7071

7172
call.signature = parseFunctionSignature();
72-
if (accept(SoltToken::Comma, true))
73+
if (accept(Token::Comma, true))
7374
call.value = parseFunctionCallValue();
74-
if (accept(SoltToken::Colon, true))
75+
if (accept(Token::Colon, true))
7576
call.arguments = parseFunctionCallArguments();
7677

77-
if (accept(SoltToken::Newline, true))
78+
if (accept(Token::Newline, true))
7879
call.displayMode = FunctionCall::DisplayMode::MultiLine;
7980

8081
call.arguments.comment = parseComment();
8182

82-
if (accept(SoltToken::Newline, true))
83+
if (accept(Token::Newline, true))
8384
call.displayMode = FunctionCall::DisplayMode::MultiLine;
8485

85-
expect(SoltToken::Arrow);
86+
expect(Token::Arrow);
8687
call.expectations = parseFunctionCallExpectations();
8788
call.expectations.comment = parseComment();
8889

8990
calls.emplace_back(std::move(call));
9091
}
91-
else
92-
m_scanner.scanNextToken();
9392
}
9493
}
9594
return calls;
9695
}
9796

98-
string TestFileParser::formatToken(SoltToken _token)
97+
bool TestFileParser::accept(soltest::Token _token, bool const _expect)
9998
{
100-
switch (_token)
101-
{
102-
#define T(name, string, precedence) case SoltToken::name: return string;
103-
SOLT_TOKEN_LIST(T, T)
104-
#undef T
105-
default: // Token::NUM_TOKENS:
106-
return "";
107-
}
108-
}
109-
110-
bool TestFileParser::accept(SoltToken _token, bool const _expect)
111-
{
112-
if (m_scanner.currentToken() == _token)
113-
{
114-
if (_expect)
115-
expect(_token);
116-
return true;
117-
}
118-
return false;
99+
if (m_scanner.currentToken() != _token)
100+
return false;
101+
if (_expect)
102+
return expect(_token);
103+
return true;
119104
}
120105

121-
bool TestFileParser::expect(SoltToken _token, bool const _advance)
106+
bool TestFileParser::expect(soltest::Token _token, bool const _advance)
122107
{
123-
if (m_scanner.currentToken() != _token)
108+
if (m_scanner.currentToken() != _token || m_scanner.currentToken() == Token::Invalid)
124109
throw Error(
125110
Error::Type::ParserError,
126111
"Unexpected " + formatToken(m_scanner.currentToken()) + ": \"" +
@@ -135,32 +120,35 @@ bool TestFileParser::expect(SoltToken _token, bool const _advance)
135120
string TestFileParser::parseFunctionSignature()
136121
{
137122
string signature = m_scanner.currentLiteral();
138-
expect(SoltToken::Identifier);
123+
expect(Token::Identifier);
139124

140-
signature += formatToken(SoltToken::LParen);
141-
expect(SoltToken::LParen);
125+
signature += formatToken(Token::LParen);
126+
expect(Token::LParen);
142127

143-
while (!accept(SoltToken::RParen))
128+
string parameters;
129+
if (!accept(Token::RParen, false))
130+
parameters = parseIdentifierOrTuple();
131+
132+
while (accept(Token::Comma))
144133
{
145-
signature += m_scanner.currentLiteral();
146-
expect(SoltToken::Identifier);
147-
while (accept(SoltToken::Comma))
148-
{
149-
signature += m_scanner.currentLiteral();
150-
expect(SoltToken::Comma);
151-
signature += m_scanner.currentLiteral();
152-
expect(SoltToken::Identifier);
153-
}
134+
parameters += formatToken(Token::Comma);
135+
expect(Token::Comma);
136+
parameters += parseIdentifierOrTuple();
154137
}
155-
signature += formatToken(SoltToken::RParen);
156-
expect(SoltToken::RParen);
138+
if (accept(Token::Arrow, true))
139+
throw Error(Error::Type::ParserError, "Invalid signature detected: " + signature);
140+
141+
signature += parameters;
142+
143+
expect(Token::RParen);
144+
signature += formatToken(Token::RParen);
157145
return signature;
158146
}
159147

160148
u256 TestFileParser::parseFunctionCallValue()
161149
{
162150
u256 value = convertNumber(parseNumber());
163-
expect(SoltToken::Ether);
151+
expect(Token::Ether);
164152
return value;
165153
}
166154

@@ -173,7 +161,7 @@ FunctionCallArgs TestFileParser::parseFunctionCallArguments()
173161
throw Error(Error::Type::ParserError, "No argument provided.");
174162
arguments.parameters.emplace_back(param);
175163

176-
while (accept(SoltToken::Comma, true))
164+
while (accept(Token::Comma, true))
177165
arguments.parameters.emplace_back(parseParameter());
178166
return arguments;
179167
}
@@ -190,7 +178,7 @@ FunctionCallExpectations TestFileParser::parseFunctionCallExpectations()
190178
}
191179
expectations.result.emplace_back(param);
192180

193-
while (accept(SoltToken::Comma, true))
181+
while (accept(Token::Comma, true))
194182
expectations.result.emplace_back(parseParameter());
195183

196184
/// We have always one virtual parameter in the parameter list.
@@ -203,7 +191,7 @@ FunctionCallExpectations TestFileParser::parseFunctionCallExpectations()
203191
Parameter TestFileParser::parseParameter()
204192
{
205193
Parameter parameter;
206-
if (accept(SoltToken::Newline, true))
194+
if (accept(Token::Newline, true))
207195
parameter.format.newline = true;
208196
auto literal = parseABITypeLiteral();
209197
parameter.rawBytes = literal.first;
@@ -218,20 +206,20 @@ pair<bytes, ABIType> TestFileParser::parseABITypeLiteral()
218206
u256 number{0};
219207
ABIType abiType{ABIType::None, 0};
220208

221-
if (accept(SoltToken::Sub))
209+
if (accept(Token::Sub))
222210
{
223211
abiType = ABIType{ABIType::SignedDec, 32};
224-
expect(SoltToken::Sub);
212+
expect(Token::Sub);
225213
number = convertNumber(parseNumber()) * -1;
226214
}
227215
else
228216
{
229-
if (accept(SoltToken::Number))
217+
if (accept(Token::Number))
230218
{
231219
abiType = ABIType{ABIType::UnsignedDec, 32};
232220
number = convertNumber(parseNumber());
233221
}
234-
else if (accept(SoltToken::Failure, true))
222+
else if (accept(Token::Failure, true))
235223
{
236224
abiType = ABIType{ABIType::Failure, 0};
237225
return make_pair(bytes{}, abiType);
@@ -245,18 +233,43 @@ pair<bytes, ABIType> TestFileParser::parseABITypeLiteral()
245233
}
246234
}
247235

236+
string TestFileParser::parseIdentifierOrTuple()
237+
{
238+
string identOrTuple;
239+
240+
if (accept(Token::Identifier))
241+
{
242+
identOrTuple = m_scanner.currentLiteral();
243+
expect(Token::Identifier);
244+
return identOrTuple;
245+
}
246+
expect(Token::LParen);
247+
identOrTuple += formatToken(Token::LParen);
248+
identOrTuple += parseIdentifierOrTuple();
249+
250+
while (accept(Token::Comma))
251+
{
252+
identOrTuple += formatToken(Token::Comma);
253+
expect(Token::Comma);
254+
identOrTuple += parseIdentifierOrTuple();
255+
}
256+
expect(Token::RParen);
257+
identOrTuple += formatToken(Token::RParen);
258+
return identOrTuple;
259+
}
260+
248261
string TestFileParser::parseComment()
249262
{
250263
string comment = m_scanner.currentLiteral();
251-
if (accept(SoltToken::Comment, true))
264+
if (accept(Token::Comment, true))
252265
return comment;
253266
return string{};
254267
}
255268

256269
string TestFileParser::parseNumber()
257270
{
258271
string literal = m_scanner.currentLiteral();
259-
expect(SoltToken::Number);
272+
expect(Token::Number);
260273
return literal;
261274
}
262275

@@ -281,69 +294,72 @@ void TestFileParser::Scanner::readStream(istream& _stream)
281294

282295
void TestFileParser::Scanner::scanNextToken()
283296
{
284-
auto detectToken = [](std::string const& _literal = "") -> TokenDesc {
285-
if (_literal == "ether") return TokenDesc{SoltToken::Ether, _literal};
286-
if (_literal == "FAILURE") return TokenDesc{SoltToken::Failure, _literal};
287-
return TokenDesc{SoltToken::Identifier, _literal};
297+
// Make code coverage happy.
298+
assert(formatToken(Token::NUM_TOKENS) == "");
299+
300+
auto detectKeyword = [](std::string const& _literal = "") -> TokenDesc {
301+
if (_literal == "ether") return TokenDesc{Token::Ether, _literal};
302+
if (_literal == "FAILURE") return TokenDesc{Token::Failure, _literal};
303+
return TokenDesc{Token::Identifier, _literal};
288304
};
289305

290-
auto selectToken = [this](SoltToken _token, std::string const& _literal = "") -> TokenDesc {
306+
auto selectToken = [this](Token _token, std::string const& _literal = "") -> TokenDesc {
291307
advance();
292308
return make_pair(_token, !_literal.empty() ? _literal : formatToken(_token));
293309
};
294310

295-
TokenDesc token = make_pair(SoltToken::Unknown, "");
311+
TokenDesc token = make_pair(Token::Unknown, "");
296312
do
297313
{
298314
switch(current())
299315
{
300316
case '/':
301317
advance();
302318
if (current() == '/')
303-
token = selectToken(SoltToken::Newline);
319+
token = selectToken(Token::Newline);
320+
else
321+
token = selectToken(Token::Invalid);
304322
break;
305323
case '-':
306324
if (peek() == '>')
307325
{
308326
advance();
309-
token = selectToken(SoltToken::Arrow);
327+
token = selectToken(Token::Arrow);
310328
}
311329
else
312-
token = selectToken(SoltToken::Sub);
330+
token = selectToken(Token::Sub);
313331
break;
314332
case ':':
315-
token = selectToken(SoltToken::Colon);
333+
token = selectToken(Token::Colon);
316334
break;
317335
case '#':
318-
token = selectToken(SoltToken::Comment, scanComment());
336+
token = selectToken(Token::Comment, scanComment());
319337
break;
320338
case ',':
321-
token = selectToken(SoltToken::Comma);
339+
token = selectToken(Token::Comma);
322340
break;
323341
case '(':
324-
token = selectToken(SoltToken::LParen);
342+
token = selectToken(Token::LParen);
325343
break;
326344
case ')':
327-
token = selectToken(SoltToken::RParen);
345+
token = selectToken(Token::RParen);
328346
break;
329347
default:
330348
if (isIdentifierStart(current()))
331349
{
332-
TokenDesc detectedToken = detectToken(scanIdentifierOrKeyword());
350+
TokenDesc detectedToken = detectKeyword(scanIdentifierOrKeyword());
333351
token = selectToken(detectedToken.first, detectedToken.second);
334352
}
335353
else if (isdigit(current()))
336-
token = selectToken(SoltToken::Number, scanNumber());
354+
token = selectToken(Token::Number, scanNumber());
337355
else if (isspace(current()))
338-
token = selectToken(SoltToken::Whitespace);
356+
token = selectToken(Token::Whitespace);
339357
else if (isEndOfLine())
340-
token = selectToken(SoltToken::EOS);
341-
else
342-
token = selectToken(SoltToken::Invalid);
358+
token = selectToken(Token::EOS);
343359
break;
344360
}
345361
}
346-
while (token.first == SoltToken::Whitespace);
362+
while (token.first == Token::Whitespace);
347363
m_currentToken = token;
348364
}
349365

0 commit comments

Comments
 (0)