2019-01-24 09:48:01 +00:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
|
2020-01-06 10:52:23 +00:00
|
|
|
#include <libsolutil/CommonData.h>
|
2019-01-24 09:48:01 +00:00
|
|
|
#include <libsolidity/ast/Types.h>
|
|
|
|
#include <liblangutil/Exceptions.h>
|
2019-07-03 19:37:55 +00:00
|
|
|
#include <test/libsolidity/util/SoltestTypes.h>
|
2019-01-24 09:48:01 +00:00
|
|
|
|
|
|
|
#include <iosfwd>
|
2019-05-15 15:25:35 +00:00
|
|
|
#include <iterator>
|
2019-02-01 05:29:34 +00:00
|
|
|
#include <numeric>
|
2019-01-24 09:48:01 +00:00
|
|
|
#include <stdexcept>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
#include <utility>
|
|
|
|
|
2019-12-23 15:50:30 +00:00
|
|
|
namespace solidity::frontend::test
|
2019-01-24 09:48:01 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 #
|
2020-02-18 11:57:48 +00:00
|
|
|
* // g(), 1 wei # (Optional) Wei to be sent with the call #
|
2019-01-24 09:48:01 +00:00
|
|
|
* // -> 2, 3
|
|
|
|
* // h(uint256), 1 ether: 42
|
|
|
|
* // -> FAILURE # If REVERT or other EVM failure was detected #
|
2019-09-09 18:09:15 +00:00
|
|
|
* // () # Call fallback function #
|
|
|
|
* // (), 1 ether # Call ether function #
|
2019-01-24 09:48:01 +00:00
|
|
|
* ...
|
|
|
|
*/
|
|
|
|
class TestFileParser
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/// Constructor that takes an input stream \param _stream to operate on
|
|
|
|
/// and creates the internal scanner.
|
|
|
|
TestFileParser(std::istream& _stream): m_scanner(_stream) {}
|
|
|
|
|
|
|
|
/// 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.
|
2019-07-13 10:04:22 +00:00
|
|
|
/// 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);
|
2019-01-24 09:48:01 +00:00
|
|
|
|
|
|
|
private:
|
2019-02-05 15:52:19 +00:00
|
|
|
using Token = soltest::Token;
|
2019-01-24 09:48:01 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
2019-02-01 05:29:34 +00:00
|
|
|
/// It reads all lines into one single line, keeping the newlines.
|
2019-01-24 09:48:01 +00:00
|
|
|
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();
|
|
|
|
|
2019-02-05 15:52:19 +00:00
|
|
|
soltest::Token currentToken() { return m_currentToken.first; }
|
2019-01-24 09:48:01 +00:00
|
|
|
std::string currentLiteral() { return m_currentToken.second; }
|
|
|
|
|
|
|
|
std::string scanComment();
|
|
|
|
std::string scanIdentifierOrKeyword();
|
2019-02-21 00:13:14 +00:00
|
|
|
std::string scanDecimalNumber();
|
|
|
|
std::string scanHexNumber();
|
2019-05-06 08:08:10 +00:00
|
|
|
std::string scanString();
|
2019-07-10 15:11:03 +00:00
|
|
|
char scanHexPart();
|
2019-01-24 09:48:01 +00:00
|
|
|
|
|
|
|
private:
|
2019-02-05 15:52:19 +00:00
|
|
|
using TokenDesc = std::pair<Token, std::string>;
|
2019-01-24 09:48:01 +00:00
|
|
|
|
|
|
|
/// Advances current position in the input stream.
|
2019-07-10 15:11:03 +00:00
|
|
|
void advance(unsigned n = 1)
|
2019-05-15 15:25:35 +00:00
|
|
|
{
|
|
|
|
solAssert(m_char != m_line.end(), "Cannot advance beyond end.");
|
2019-07-10 15:11:03 +00:00
|
|
|
m_char = std::next(m_char, n);
|
2019-05-15 15:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the current character or '\0' if at end of input.
|
|
|
|
char current() const noexcept
|
|
|
|
{
|
|
|
|
if (m_char == m_line.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;
|
|
|
|
|
2019-01-24 09:48:01 +00:00
|
|
|
/// Returns true if the end of a line is reached, false otherwise.
|
|
|
|
bool isEndOfLine() const { return m_char == m_line.end(); }
|
|
|
|
|
|
|
|
std::string m_line;
|
2019-05-15 15:25:35 +00:00
|
|
|
std::string::const_iterator m_char;
|
2019-01-24 09:48:01 +00:00
|
|
|
|
|
|
|
std::string m_currentLiteral;
|
|
|
|
|
|
|
|
TokenDesc m_currentToken;
|
|
|
|
};
|
|
|
|
|
2019-02-05 15:52:19 +00:00
|
|
|
bool accept(soltest::Token _token, bool const _expect = false);
|
|
|
|
bool expect(soltest::Token _token, bool const _advance = true);
|
2019-01-24 09:48:01 +00:00
|
|
|
|
2019-09-09 18:09:15 +00:00
|
|
|
/// 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();
|
2019-01-24 09:48:01 +00:00
|
|
|
|
|
|
|
/// 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`.
|
2020-02-18 11:57:48 +00:00
|
|
|
FunctionValue parseFunctionCallValue();
|
2019-01-24 09:48:01 +00:00
|
|
|
|
|
|
|
/// 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();
|
|
|
|
|
2019-02-01 05:29:34 +00:00
|
|
|
/// 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.
|
2019-07-04 13:23:47 +00:00
|
|
|
/// Parses and converts the current literal to its byte representation and
|
2019-02-06 11:10:48 +00:00
|
|
|
/// 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:
|
2019-02-01 05:29:34 +00:00
|
|
|
/// - 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
|
2019-01-24 09:48:01 +00:00
|
|
|
/// if data type is not supported.
|
2019-07-04 13:23:47 +00:00
|
|
|
Parameter parseParameter();
|
2019-01-24 09:48:01 +00:00
|
|
|
|
2019-02-05 15:52:19 +00:00
|
|
|
/// Recursively parses an identifier or a tuple definition that contains identifiers
|
|
|
|
/// and / or parentheses like `((uint, uint), (uint, (uint, uint)), uint)`.
|
|
|
|
std::string parseIdentifierOrTuple();
|
|
|
|
|
2019-02-21 22:25:12 +00:00
|
|
|
/// Parses a boolean literal.
|
|
|
|
std::string parseBoolean();
|
|
|
|
|
2019-02-05 15:52:19 +00:00
|
|
|
/// Parses a comment that is defined like this:
|
|
|
|
/// # A nice comment. #
|
2019-02-01 05:29:34 +00:00
|
|
|
std::string parseComment();
|
|
|
|
|
2019-02-21 00:13:14 +00:00
|
|
|
/// Parses the current decimal number literal.
|
|
|
|
std::string parseDecimalNumber();
|
|
|
|
|
|
|
|
/// Parses the current hex number literal.
|
|
|
|
std::string parseHexNumber();
|
2019-01-24 09:48:01 +00:00
|
|
|
|
2019-05-06 08:08:10 +00:00
|
|
|
/// Parses the current string literal.
|
|
|
|
std::string parseString();
|
|
|
|
|
2019-01-24 09:48:01 +00:00
|
|
|
/// A scanner instance
|
|
|
|
Scanner m_scanner;
|
2019-07-13 10:04:22 +00:00
|
|
|
|
|
|
|
/// The current line number. Incremented when Token::Newline (//) is found and
|
|
|
|
/// used to enhance parser error messages.
|
|
|
|
size_t m_lineNumber = 0;
|
2019-01-24 09:48:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|