mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10618 from ethereum/develop
Merge develop into breaking.
This commit is contained in:
@@ -98,6 +98,20 @@ public:
|
||||
std::tuple<int, int> translatePositionToLineColumn(int _position) const;
|
||||
///@}
|
||||
|
||||
/// Tests whether or not given octet sequence is present at the current position in stream.
|
||||
/// @returns true if the sequence could be found, false otherwise.
|
||||
bool prefixMatch(std::string_view _sequence)
|
||||
{
|
||||
if (isPastEndOfInput(_sequence.size()))
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < _sequence.size(); ++i)
|
||||
if (_sequence[i] != get(i))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_source;
|
||||
std::string m_name;
|
||||
|
||||
+71
-5
@@ -54,9 +54,10 @@
|
||||
#include <liblangutil/Exceptions.h>
|
||||
#include <liblangutil/Scanner.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
|
||||
using namespace std;
|
||||
@@ -79,6 +80,8 @@ string to_string(ScannerError _errorCode)
|
||||
case ScannerError::IllegalExponent: return "Invalid exponent.";
|
||||
case ScannerError::IllegalNumberEnd: return "Identifier-start is not allowed at end of a number.";
|
||||
case ScannerError::OctalNotAllowed: return "Octal numbers not allowed.";
|
||||
case ScannerError::DirectionalOverrideUnderflow: return "Unicode direction override underflow in comment or string literal.";
|
||||
case ScannerError::DirectionalOverrideMismatch: return "Mismatching directional override markers in comment or string literal.";
|
||||
default:
|
||||
solAssert(false, "Unhandled case in to_string(ScannerError)");
|
||||
return "";
|
||||
@@ -271,12 +274,61 @@ bool Scanner::skipWhitespaceExceptUnicodeLinebreak()
|
||||
return sourcePos() != startPosition;
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/// Tries to scan for an RLO/LRO/RLE/LRE/PDF and keeps track of script writing direction override depth.
|
||||
///
|
||||
/// @returns ScannerError::NoError in case of successful parsing and directional encodings are paired
|
||||
/// and error code in case the input's lexical parser state is invalid and this error should be reported
|
||||
/// to the user.
|
||||
static ScannerError validateBiDiMarkup(CharStream& _stream, size_t _startPosition)
|
||||
{
|
||||
static array<pair<string_view, int>, 5> constexpr directionalSequences{
|
||||
pair<string_view, int>{"\xE2\x80\xAD", 1}, // U+202D (LRO - Left-to-Right Override)
|
||||
pair<string_view, int>{"\xE2\x80\xAE", 1}, // U+202E (RLO - Right-to-Left Override)
|
||||
pair<string_view, int>{"\xE2\x80\xAA", 1}, // U+202A (LRE - Left-to-Right Embedding)
|
||||
pair<string_view, int>{"\xE2\x80\xAB", 1}, // U+202B (RLE - Right-to-Left Embedding)
|
||||
pair<string_view, int>{"\xE2\x80\xAC", -1} // U+202C (PDF - Pop Directional Formatting
|
||||
};
|
||||
|
||||
size_t endPosition = _stream.position();
|
||||
_stream.setPosition(_startPosition);
|
||||
|
||||
int directionOverrideDepth = 0;
|
||||
|
||||
for (size_t currentPos = _startPosition; currentPos < endPosition; ++currentPos)
|
||||
{
|
||||
_stream.setPosition(currentPos);
|
||||
|
||||
for (auto const& [sequence, depthChange]: directionalSequences)
|
||||
if (_stream.prefixMatch(sequence))
|
||||
directionOverrideDepth += depthChange;
|
||||
|
||||
if (directionOverrideDepth < 0)
|
||||
return ScannerError::DirectionalOverrideUnderflow;
|
||||
}
|
||||
|
||||
_stream.setPosition(endPosition);
|
||||
|
||||
return directionOverrideDepth > 0 ? ScannerError::DirectionalOverrideMismatch : ScannerError::NoError;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Token Scanner::skipSingleLineComment()
|
||||
{
|
||||
// Line terminator is not part of the comment. If it is a
|
||||
// non-ascii line terminator, it will result in a parser error.
|
||||
size_t startPosition = m_source->position();
|
||||
while (!isUnicodeLinebreak())
|
||||
if (!advance()) break;
|
||||
if (!advance())
|
||||
break;
|
||||
|
||||
ScannerError unicodeDirectionError = validateBiDiMarkup(*m_source, startPosition);
|
||||
if (unicodeDirectionError != ScannerError::NoError)
|
||||
return setError(unicodeDirectionError);
|
||||
|
||||
return Token::Whitespace;
|
||||
}
|
||||
@@ -349,16 +401,21 @@ size_t Scanner::scanSingleLineDocComment()
|
||||
|
||||
Token Scanner::skipMultiLineComment()
|
||||
{
|
||||
size_t startPosition = m_source->position();
|
||||
while (!isSourcePastEndOfInput())
|
||||
{
|
||||
char ch = m_char;
|
||||
char prevChar = m_char;
|
||||
advance();
|
||||
|
||||
// If we have reached the end of the multi-line comment, we
|
||||
// consume the '/' and insert a whitespace. This way all
|
||||
// multi-line comments are treated as whitespace.
|
||||
if (ch == '*' && m_char == '/')
|
||||
if (prevChar == '*' && m_char == '/')
|
||||
{
|
||||
ScannerError unicodeDirectionError = validateBiDiMarkup(*m_source, startPosition);
|
||||
if (unicodeDirectionError != ScannerError::NoError)
|
||||
return setError(unicodeDirectionError);
|
||||
|
||||
m_char = ' ';
|
||||
return Token::Whitespace;
|
||||
}
|
||||
@@ -776,6 +833,7 @@ bool Scanner::isUnicodeLinebreak()
|
||||
|
||||
Token Scanner::scanString(bool const _isUnicode)
|
||||
{
|
||||
size_t startPosition = m_source->position();
|
||||
char const quote = m_char;
|
||||
advance(); // consume quote
|
||||
LiteralScope literal(this, LITERAL_TYPE_STRING);
|
||||
@@ -803,6 +861,14 @@ Token Scanner::scanString(bool const _isUnicode)
|
||||
}
|
||||
if (m_char != quote)
|
||||
return setError(ScannerError::IllegalStringEndQuote);
|
||||
|
||||
if (_isUnicode)
|
||||
{
|
||||
ScannerError unicodeDirectionError = validateBiDiMarkup(*m_source, startPosition);
|
||||
if (unicodeDirectionError != ScannerError::NoError)
|
||||
return setError(unicodeDirectionError);
|
||||
}
|
||||
|
||||
literal.complete();
|
||||
advance(); // consume quote
|
||||
return _isUnicode ? Token::UnicodeStringLiteral : Token::StringLiteral;
|
||||
|
||||
@@ -89,6 +89,9 @@ enum class ScannerError
|
||||
IllegalExponent,
|
||||
IllegalNumberEnd,
|
||||
|
||||
DirectionalOverrideUnderflow,
|
||||
DirectionalOverrideMismatch,
|
||||
|
||||
OctalNotAllowed,
|
||||
};
|
||||
|
||||
@@ -183,6 +186,7 @@ public:
|
||||
///@}
|
||||
|
||||
private:
|
||||
|
||||
inline Token setError(ScannerError _error) noexcept
|
||||
{
|
||||
m_tokens[NextNext].error = _error;
|
||||
|
||||
Reference in New Issue
Block a user