Skip to content
Snippets Groups Projects
Commit 3653e54a authored by Frederich Munch's avatar Frederich Munch Committed by Axel Naumann
Browse files

Add block comment support to InputValidator.

parent ec0303e2
No related branches found
No related tags found
No related merge requests found
......@@ -8,20 +8,79 @@
//------------------------------------------------------------------------------
#include "InputValidator.h"
#include "MetaLexer.h"
#include <algorithm>
namespace cling {
bool InputValidator::inBlockComment() const {
return std::find(m_ParenStack.begin(), m_ParenStack.end(), tok::slash)
!= m_ParenStack.end();
}
static int findNestedBlockComments(const char* startPos, const char* endPos) {
// While probably not standard compliant, it should work fine for the indent
// Let the real parser error if the balancing is incorrect
// search forward for //, then backward for block comments
// */ last, comment has ended, doesn't matter how many /* before
// /* last, comment has begun, doesn't matter if priors ended or not
char commentTok = 0;
while (startPos < endPos) {
if (*startPos == '/') {
if (++commentTok == 2) {
while (endPos > startPos) {
switch (*endPos) {
case '*':
if (commentTok == '*')
return -1;
else
commentTok = '/';
break;
case '/':
if (commentTok == '/')
return 1;
else
commentTok = '*';
break;
default:
commentTok = 0;
break;
}
--endPos;
}
return 0;
}
} else if (commentTok)
commentTok = 0; // need a new start to double slash
++startPos;
}
return 0;
}
static void unwindTokens(std::deque<int>& queue, int tok) {
assert(!queue.empty() && "Token stack is empty!");
while (queue.back() != tok) {
queue.pop_back();
assert(!queue.empty() && "Token stack is empty!");
}
queue.pop_back();
}
InputValidator::ValidationResult
InputValidator::validate(llvm::StringRef line) {
ValidationResult Res = kComplete;
Token Tok;
const char* curPos = line.data();
bool multilineComment = inBlockComment();
int commentTok = multilineComment ? tok::asterik : tok::slash;
do {
const char* prevStart = curPos;
MetaLexer::LexPunctuatorAndAdvance(curPos, Tok);
int kind = (int)Tok.getKind();
// if (kind == tok::hash) {
// // Handle #ifdef ...
// // ...
......@@ -40,28 +99,78 @@ namespace cling {
// }
// }
if (kind >= (int)tok::stringlit && kind <= (int)tok::charlit) {
MetaLexer::LexQuotedStringAndAdvance(curPos, Tok);
} else
// In case when we need closing brace.
if (kind >= (int)tok::l_square && kind <= (int)tok::r_brace) {
// The closing paren kind is open paren kind + 1 (i.e odd number)
if (kind % 2) {
// closing the right one?
if (m_ParenStack.empty()) {
Res = kMismatch;
break;
if (kind == commentTok) {
if (kind == tok::slash) {
if (multilineComment) {
// exiting a comment, unwind the stack
multilineComment = false;
commentTok = tok::slash;
unwindTokens(m_ParenStack, tok::slash);
}
int prev = m_ParenStack.back();
if (prev != kind - 1) {
Res = kMismatch;
// If we have a closing comment without a start it will be transformed
// to */; and clang reports an error for both the */ and the ;
// If we return kIncomplete, then just one error is printed, but too
// late: after the user has another expression which will always fail.
// So just deal with two errors for now
// else if (prevKind == tok::asterik) {
// Res = kIncomplete;
// break;
// }
else // wait for an asterik
commentTok = tok::asterik;
}
else {
assert(commentTok == tok::asterik && "Comment token not / or *");
if (!multilineComment) {
// entering a new comment
multilineComment = true;
m_ParenStack.push_back(tok::slash);
}
else // wait for closing / (must be next token)
commentTok = tok::slash;
}
}
else {
// If we're in a multiline, and waiting for the closing slash
// we gonna have to wait for another asterik first
if (multilineComment) {
if (kind == tok::eof) {
switch (findNestedBlockComments(prevStart, curPos)) {
case -1: unwindTokens(m_ParenStack, tok::slash);
case 1:
case 0: break;
default: assert(0 && "Nested block comment count"); break;
}
// eof, were done anyway
break;
}
m_ParenStack.pop_back();
else if (commentTok == tok::slash) {
// Cancel the wait for a slash, but only if current token isn't
// also an asterik.
if (kind != tok::asterik)
commentTok = tok::asterik;
}
}
if (kind >= (int)tok::l_square && kind <= (int)tok::r_brace) {
// The closing paren kind is open paren kind + 1 (i.e odd number)
if (kind % 2) {
int prev = m_ParenStack.empty() ? -1: m_ParenStack.back();
// closing the right one?
if (prev != kind - 1) {
if (multilineComment)
continue;
Res = kMismatch;
break;
}
m_ParenStack.pop_back();
}
else
m_ParenStack.push_back(kind);
}
else if (kind >= (int)tok::stringlit && kind <= (int)tok::charlit) {
MetaLexer::LexQuotedStringAndAdvance(curPos, Tok);
}
else
m_ParenStack.push_back(kind);
}
}
while (Tok.isNot(tok::eof));
......
......@@ -68,6 +68,12 @@ namespace cling {
///\brief Resets the collected input and its corresponding brace stack.
///
void reset();
///\brief Return whether we are inside a mult-line comment
///
///\returns true if currently inside a multi-line comment block
///
bool inBlockComment() const;
};
}
#endif // CLING_INPUT_VALIDATOR_H
......@@ -56,19 +56,18 @@ namespace cling {
return LexQuotedStringAndAdvance(curPos, Tok);
case '[': case ']': case '(': case ')': case '{': case '}':
case '\\': case ',': case '.': case '!': case '?': case '>':
case '&': case '#': case '@':
case '&': case '#': case '@': case '*':
// INTENTIONAL FALL THROUGHs
return LexPunctuator(curPos - 1, Tok);
case '/':
if (*curPos != '/')
return LexPunctuator(curPos - 1, Tok);
else {
if (*curPos == '/') {
++curPos;
Tok.setKind(tok::comment);
Tok.setLength(2);
return;
}
return LexPunctuator(curPos - 1, Tok);
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
......@@ -127,6 +126,7 @@ namespace cling {
case '@' : Tok.setKind(tok::at); break;
case '&' : Tok.setKind(tok::ampersand); break;
case '#' : Tok.setKind(tok::hash); break;
case '*' : Tok.setKind(tok::asterik); break;
case '\0' : Tok.setKind(tok::eof); Tok.setLength(0); break;// if static call
default: Tok.setLength(0); break;
}
......
......@@ -39,6 +39,7 @@ namespace cling {
space, // (' ' | '\t')*
constant, // {0-9}
at, // @
asterik, // *
eof,
unknown
};
......
......@@ -149,7 +149,8 @@ namespace cling {
// Check for and handle meta commands.
m_MetaParser->enterNewInputLine(input_line);
MetaSema::ActionResult actionResult = MetaSema::AR_Success;
if (m_MetaParser->isMetaCommand(actionResult, result)) {
if (!m_InputValidator->inBlockComment() &&
m_MetaParser->isMetaCommand(actionResult, result)) {
if (m_MetaParser->isQuitRequested())
return -1;
......
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
// RUN: cat %s | %cling -Xclang -verify 2>&1 | FileCheck %s
// Test blockComments
(/*
1
2
3 */
8
// single line 1
/* single line 2*/
)
// CHECK: (int) 8
// Check nested indentation works
/*
{
(
[
]
)
}
*/
// Check nested indentation doesn't error on mismatched closures
/*
{
[
(
}
)
]
*/
( 5
/*
+ 1
+ 2
+ 3 */
+ 4
// single line 1
/* single line 2*/
)
// CHECK-NEXT: (int) 9
/*
This should work
// As should this // */
/*
This will warn
// /* */ // expected-warning {{within block comment}}
.rawInput 1
*/ // expected-error {{expected unqualified-id}}
.rawInput 0
// This is a side effect of wrapping, expression is compiled as */; so 2 errors
*/ // expected-error@2 {{expected expression}} expected-error@3 {{expected expression}}
// Check meta-commands are blocked out
/*
.L SomeStuff
.x some more
.q
*/
( 5
/*
+ 10
+ 20 */
/*
+ 30
*/
+ 4
// single line 1
+ 10
/* single line 2*/
/* ) */
)
// CHECK-NEXT: (int) 19
/* 8 + */ 9 /* = 20 */
// CHECK-NEXT: (int) 9
/*
// Check inline asteriks
*******************************************************
* Row * Instance * fEvents.fEventNo * fShowers *
*******************************************************
* 0 * 0 * 0 * 10 *
* 0 * 1 * 0 * 20 *
* 0 * 2 * 2 * 30 *
*******************************************************
*/
32
// CHECK-NEXT: (int) 32
/* Check inline asteriks ****/
62
// CHECK-NEXT: (int) 62
.q
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment