Browse Source

solidity scanner takes triple slash doc comments into account

- Conditionally scanning for the documentation comments and gettings their
  contents.

- Adding tests for this functionality of the scanner
cl-refactor
Lefteris Karapetsas 10 years ago
parent
commit
0c101d89f8
  1. 36
      libsolidity/Scanner.cpp
  2. 19
      libsolidity/Scanner.h
  3. 1
      libsolidity/Token.h
  4. 44
      test/solidityScanner.cpp

36
libsolidity/Scanner.cpp

@ -102,13 +102,13 @@ int HexValue(char c)
} }
} // end anonymous namespace } // end anonymous namespace
void Scanner::reset(CharStream const& _source) void Scanner::reset(CharStream const& _source, bool _skipDocumentationComments)
{ {
m_source = _source; m_source = _source;
m_char = m_source.get(); m_char = m_source.get();
skipWhitespace(); skipWhitespace();
scanToken(); scanToken(_skipDocumentationComments);
next(); next(_skipDocumentationComments);
} }
@ -134,10 +134,10 @@ bool Scanner::scanHexByte(char& o_scannedByte)
// Ensure that tokens can be stored in a byte. // Ensure that tokens can be stored in a byte.
BOOST_STATIC_ASSERT(Token::NUM_TOKENS <= 0x100); BOOST_STATIC_ASSERT(Token::NUM_TOKENS <= 0x100);
Token::Value Scanner::next() Token::Value Scanner::next(bool _skipDocumentationComments)
{ {
m_current_token = m_next_token; m_current_token = m_next_token;
scanToken(); scanToken(_skipDocumentationComments);
return m_current_token.token; return m_current_token.token;
} }
@ -171,6 +171,21 @@ Token::Value Scanner::skipSingleLineComment()
return Token::WHITESPACE; return Token::WHITESPACE;
} }
// For the moment this function simply consumes a single line triple slash doc comment
Token::Value Scanner::scanDocumentationComment()
{
LiteralScope literal(this);
advance(); //consume the last '/'
while (!isSourcePastEndOfInput() && !IsLineTerminator(m_char))
{
char c = m_char;
advance();
addLiteralChar(c);
}
literal.Complete();
return Token::COMMENT_LITERAL;
}
Token::Value Scanner::skipMultiLineComment() Token::Value Scanner::skipMultiLineComment()
{ {
if (asserts(m_char == '*')) if (asserts(m_char == '*'))
@ -194,7 +209,7 @@ Token::Value Scanner::skipMultiLineComment()
return Token::ILLEGAL; return Token::ILLEGAL;
} }
void Scanner::scanToken() void Scanner::scanToken(bool _skipDocumentationComments)
{ {
m_next_token.literal.clear(); m_next_token.literal.clear();
Token::Value token; Token::Value token;
@ -297,7 +312,14 @@ void Scanner::scanToken()
// / // /* /= // / // /* /=
advance(); advance();
if (m_char == '/') if (m_char == '/')
token = skipSingleLineComment(); {
if (!advance()) /* double slash comment directly before EOS */
token = Token::WHITESPACE;
else if (!_skipDocumentationComments)
token = scanDocumentationComment();
else
token = skipSingleLineComment();
}
else if (m_char == '*') else if (m_char == '*')
token = skipMultiLineComment(); token = skipMultiLineComment();
else if (m_char == '=') else if (m_char == '=')

19
libsolidity/Scanner.h

@ -111,19 +111,27 @@ public:
}; };
Scanner() { reset(CharStream()); } Scanner() { reset(CharStream()); }
explicit Scanner(CharStream const& _source) { reset(_source); } explicit Scanner(CharStream const& _source, bool _skipDocumentationComments = true)
{
reset(_source, _skipDocumentationComments);
}
/// Resets the scanner as if newly constructed with _input as input. /// Resets the scanner as if newly constructed with _input as input.
void reset(CharStream const& _source); void reset(CharStream const& _source, bool _skipDocumentationComments = true);
/// Returns the next token and advances input. /// Returns the next token and advances input.
Token::Value next(); Token::Value next(bool _skipDocumentationComments = true);
///@{ ///@{
///@name Information about the current token ///@name Information about the current token
/// Returns the current token /// Returns the current token
Token::Value getCurrentToken() { return m_current_token.token; } Token::Value getCurrentToken(bool _skipDocumentationComments = true)
{
if (!_skipDocumentationComments)
next(_skipDocumentationComments);
return m_current_token.token;
}
Location getCurrentLocation() const { return m_current_token.location; } Location getCurrentLocation() const { return m_current_token.location; }
std::string const& getCurrentLiteral() const { return m_current_token.literal; } std::string const& getCurrentLiteral() const { return m_current_token.literal; }
///@} ///@}
@ -172,7 +180,7 @@ private:
bool scanHexByte(char& o_scannedByte); bool scanHexByte(char& o_scannedByte);
/// Scans a single JavaScript token. /// Scans a single JavaScript token.
void scanToken(); void scanToken(bool _skipDocumentationComments = true);
/// Skips all whitespace and @returns true if something was skipped. /// Skips all whitespace and @returns true if something was skipped.
bool skipWhitespace(); bool skipWhitespace();
@ -184,6 +192,7 @@ private:
Token::Value scanIdentifierOrKeyword(); Token::Value scanIdentifierOrKeyword();
Token::Value scanString(); Token::Value scanString();
Token::Value scanDocumentationComment();
/// Scans an escape-sequence which is part of a string and adds the /// Scans an escape-sequence which is part of a string and adds the
/// decoded character to the current literal. Returns true if a pattern /// decoded character to the current literal. Returns true if a pattern

1
libsolidity/Token.h

@ -281,6 +281,7 @@ namespace solidity
K(FALSE_LITERAL, "false", 0) \ K(FALSE_LITERAL, "false", 0) \
T(NUMBER, NULL, 0) \ T(NUMBER, NULL, 0) \
T(STRING_LITERAL, NULL, 0) \ T(STRING_LITERAL, NULL, 0) \
T(COMMENT_LITERAL, NULL, 0) \
\ \
/* Identifiers (not keywords or future reserved words). */ \ /* Identifiers (not keywords or future reserved words). */ \
T(IDENTIFIER, NULL, 0) \ T(IDENTIFIER, NULL, 0) \

44
test/solidityScanner.cpp

@ -153,6 +153,50 @@ BOOST_AUTO_TEST_CASE(ambiguities)
BOOST_CHECK_EQUAL(scanner.next(), Token::SHL); BOOST_CHECK_EQUAL(scanner.next(), Token::SHL);
} }
BOOST_AUTO_TEST_CASE(documentation_comments_parsed_begin)
{
Scanner scanner(CharStream("/// Send $(value / 1000) chocolates to the user"), false);
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::COMMENT_LITERAL);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), " Send $(value / 1000) chocolates to the user");
}
BOOST_AUTO_TEST_CASE(documentation_comments_skipped_begin)
{
Scanner scanner(CharStream("/// Send $(value / 1000) chocolates to the user"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::EOS);
}
BOOST_AUTO_TEST_CASE(documentation_comments_parsed)
{
Scanner scanner(CharStream("some other tokens /// Send $(value / 1000) chocolates to the user"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.next(false), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.next(false), Token::COMMENT_LITERAL);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), " Send $(value / 1000) chocolates to the user");
}
BOOST_AUTO_TEST_CASE(documentation_comments_skipped)
{
Scanner scanner(CharStream("some other tokens /// Send $(value / 1000) chocolates to the user"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
}
BOOST_AUTO_TEST_CASE(comment_before_eos)
{
Scanner scanner(CharStream("//"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::EOS);
}
BOOST_AUTO_TEST_CASE(documentation_comment_before_eos)
{
Scanner scanner(CharStream("///"), false);
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::COMMENT_LITERAL);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "");
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

Loading…
Cancel
Save