forked from ethereum/solidity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTestFileParser.h
201 lines (165 loc) · 7.24 KB
/
TestFileParser.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <liblangutil/Exceptions.h>
#include <libsolutil/CommonData.h>
#include <test/libsolidity/util/SoltestTypes.h>
#include <iosfwd>
#include <iterator>
#include <numeric>
#include <stdexcept>
#include <string>
#include <vector>
#include <utility>
namespace solidity::frontend::test
{
/**
* Class that is able to parse an additional and well-formed comment section in a Solidity
* source file used by the file-based unit test environment. For now, it parses function
* calls and their expected result after the call was made.
*
* - Function calls defined in blocks:
* // f(uint256, uint256): 1, 1 # Signature and comma-separated list of arguments #
* // -> 1, 1 # Expected result value #
* // g(), 2 ether # (Optional) Ether to be send with the call #
* // g(), 1 wei # (Optional) Wei to be sent with the call #
* // -> 2, 3
* // h(uint256), 1 ether: 42
* // -> FAILURE # If REVERT or other EVM failure was detected #
* // () # Call fallback function #
* // (), 1 ether # Call receive ether function #
* // EMPTY_STORAGE # Check that storage is empty
* ...
*/
class TestFileParser
{
public:
/// Constructor that takes an input stream \param _stream to operate on
/// and creates the internal scanner.
explicit TestFileParser(std::istream& _stream, std::map<std::string, Builtin> const& _builtins):
m_scanner(_stream),
m_builtins(_builtins)
{}
/// Parses function calls blockwise and returns a list of function calls found.
/// Throws an exception if a function call cannot be parsed because of its
/// incorrect structure, an invalid or unsupported encoding
/// of its arguments or expected results.
/// Passes the source line offset, such that parsing errors can be enhanced
/// with a line number it occurred in.
std::vector<FunctionCall> parseFunctionCalls(std::size_t _lineOffset);
private:
/**
* Token scanner that is used internally to abstract away character traversal.
*/
class Scanner
{
public:
/// Constructor that takes an input stream \param _stream to operate on.
/// It reads all lines into one single line, keeping the newlines.
Scanner(std::istream& _stream) { readStream(_stream); }
/// Reads input stream into a single line and resets the current iterator.
void readStream(std::istream& _stream);
/// Reads character stream and creates token.
void scanNextToken();
soltest::Token currentToken() { return m_currentToken; }
std::string currentLiteral() { return m_currentLiteral; }
std::string scanComment();
std::string scanIdentifierOrKeyword();
std::string scanDecimalNumber();
std::string scanHexNumber();
std::string scanString();
std::string readLine();
char scanHexPart();
private:
/// Advances current position in the input stream.
void advance(unsigned n = 1)
{
solAssert(m_char != m_source.end(), "Cannot advance beyond end.");
m_char = std::next(m_char, static_cast<int>(n));
}
/// Returns the current character or '\0' if at end of input.
char current() const noexcept
{
if (m_char == m_source.end())
return '\0';
return *m_char;
}
/// Retrieves the next character ('\0' if that would be at (or beyond) the end of input)
/// without advancing the input stream iterator.
char peek() const noexcept;
/// Returns true if the end of the file is reached, false otherwise.
bool isEndOfFile() const { return m_char == m_source.end(); }
std::string m_source;
std::string::const_iterator m_char;
std::string m_currentLiteral;
soltest::Token m_currentToken = soltest::Token::Unknown;
};
bool accept(soltest::Token _token, bool const _expect = false);
bool expect(soltest::Token _token, bool const _advance = true);
/// Parses a function call signature in the form of `f(uint256, ...)` and
/// returns the signature and a flag that indicates if the function name was
/// empty. If so, the signature is not allowed to define any parameters.
std::pair<std::string, bool> parseFunctionSignature();
/// Parses the optional ether value that can be passed alongside the
/// function call arguments. Throws an InvalidEtherValueEncoding exception
/// if given value cannot be converted to `u256`.
FunctionValue parseFunctionCallValue();
/// Parses a comma-separated list of arguments passed with a function call.
/// Does not check for a potential mismatch between the signature and the number
/// or types of arguments.
FunctionCallArgs parseFunctionCallArguments();
/// Parses the expected result of a function call execution.
FunctionCallExpectations parseFunctionCallExpectations();
/// Parses the next parameter in a comma separated list.
/// Takes a newly parsed, and type-annotated `bytes` argument,
/// appends it to the internal `bytes` buffer of the parameter. It can also
/// store newlines found in the source, that are needed to
/// format input and output of the interactive update.
/// Parses and converts the current literal to its byte representation and
/// preserves the chosen ABI type, as well as a raw, unformatted string representation
/// of this literal.
/// Based on the type information retrieved, the driver of this parser may format arguments,
/// expectations and results. Supported types:
/// - unsigned and signed decimal number literals.
/// Returns invalid ABI type for empty literal. This is needed in order
/// to detect empty expectations. Throws a ParserError if data is encoded incorrectly or
/// if data type is not supported.
Parameter parseParameter();
/// Recursively parses an identifier or a tuple definition that contains identifiers
/// and / or parentheses like `((uint, uint), (uint, (uint, uint)), uint)`.
std::string parseIdentifierOrTuple();
/// Parses a boolean literal.
std::string parseBoolean();
/// Parses a comment that is defined like this:
/// # A nice comment. #
std::string parseComment();
/// Parses the current decimal number literal.
std::string parseDecimalNumber();
/// Parses the current hex number literal.
std::string parseHexNumber();
/// Parses the current string literal.
std::string parseString();
/// Parses the expected side effects of a function call execution.
std::vector<std::string> parseFunctionCallSideEffects();
/// Checks whether a builtin function with the given signature exist.
/// @returns true, if builtin found, false otherwise
bool isBuiltinFunction(std::string const& _signature);
/// A scanner instance
Scanner m_scanner;
/// The current line number. Incremented when Token::Newline (//) is found and
/// used to enhance parser error messages.
size_t m_lineNumber = 0;
std::map<std::string, Builtin> const& m_builtins;
};
}