Fix scalar parsing when a line starts with a comment.

This commit is contained in:
Jesse Beder 2016-04-02 16:02:26 -05:00
parent 091ddfa52d
commit 7d2873ce9f
2 changed files with 81 additions and 26 deletions

View File

@ -39,16 +39,18 @@ std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) {
std::size_t lastNonWhitespaceChar = scalar.size(); std::size_t lastNonWhitespaceChar = scalar.size();
bool escapedNewline = false; bool escapedNewline = false;
while (!params.end->Matches(INPUT) && !Exp::Break().Matches(INPUT)) { while (!params.end->Matches(INPUT) && !Exp::Break().Matches(INPUT)) {
if (!INPUT) if (!INPUT) {
break; break;
}
// document indicator? // document indicator?
if (INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT)) { if (INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT)) {
if (params.onDocIndicator == BREAK) if (params.onDocIndicator == BREAK) {
break; break;
else if (params.onDocIndicator == THROW) } else if (params.onDocIndicator == THROW) {
throw ParserException(INPUT.mark(), ErrorMsg::DOC_IN_SCALAR); throw ParserException(INPUT.mark(), ErrorMsg::DOC_IN_SCALAR);
} }
}
foundNonEmptyLine = true; foundNonEmptyLine = true;
pastOpeningBreak = true; pastOpeningBreak = true;
@ -74,27 +76,31 @@ std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) {
// otherwise, just add the damn character // otherwise, just add the damn character
char ch = INPUT.get(); char ch = INPUT.get();
scalar += ch; scalar += ch;
if (ch != ' ' && ch != '\t') if (ch != ' ' && ch != '\t') {
lastNonWhitespaceChar = scalar.size(); lastNonWhitespaceChar = scalar.size();
} }
}
// eof? if we're looking to eat something, then we throw // eof? if we're looking to eat something, then we throw
if (!INPUT) { if (!INPUT) {
if (params.eatEnd) if (params.eatEnd) {
throw ParserException(INPUT.mark(), ErrorMsg::EOF_IN_SCALAR); throw ParserException(INPUT.mark(), ErrorMsg::EOF_IN_SCALAR);
}
break; break;
} }
// doc indicator? // doc indicator?
if (params.onDocIndicator == BREAK && INPUT.column() == 0 && if (params.onDocIndicator == BREAK && INPUT.column() == 0 &&
Exp::DocIndicator().Matches(INPUT)) Exp::DocIndicator().Matches(INPUT)) {
break; break;
}
// are we done via character match? // are we done via character match?
int n = params.end->Match(INPUT); int n = params.end->Match(INPUT);
if (n >= 0) { if (n >= 0) {
if (params.eatEnd) if (params.eatEnd) {
INPUT.eat(n); INPUT.eat(n);
}
break; break;
} }
@ -111,23 +117,33 @@ std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) {
// Phase #3: scan initial spaces // Phase #3: scan initial spaces
// first the required indentation // first the required indentation
while (INPUT.peek() == ' ' && (INPUT.column() < params.indent || while (INPUT.peek() == ' ' &&
(params.detectIndent && !foundNonEmptyLine))) (INPUT.column() < params.indent ||
(params.detectIndent && !foundNonEmptyLine)) &&
!params.end->Matches(INPUT)) {
INPUT.eat(1); INPUT.eat(1);
}
// update indent if we're auto-detecting // update indent if we're auto-detecting
if (params.detectIndent && !foundNonEmptyLine) if (params.detectIndent && !foundNonEmptyLine) {
params.indent = std::max(params.indent, INPUT.column()); params.indent = std::max(params.indent, INPUT.column());
}
// and then the rest of the whitespace // and then the rest of the whitespace
while (Exp::Blank().Matches(INPUT)) { while (Exp::Blank().Matches(INPUT)) {
// we check for tabs that masquerade as indentation // we check for tabs that masquerade as indentation
if (INPUT.peek() == '\t' && INPUT.column() < params.indent && if (INPUT.peek() == '\t' && INPUT.column() < params.indent &&
params.onTabInIndentation == THROW) params.onTabInIndentation == THROW) {
throw ParserException(INPUT.mark(), ErrorMsg::TAB_IN_INDENTATION); throw ParserException(INPUT.mark(), ErrorMsg::TAB_IN_INDENTATION);
}
if (!params.eatLeadingWhitespace) if (!params.eatLeadingWhitespace) {
break; break;
}
if (params.end->Matches(INPUT)) {
break;
}
INPUT.eat(1); INPUT.eat(1);
} }
@ -147,26 +163,29 @@ std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) {
break; break;
case FOLD_BLOCK: case FOLD_BLOCK:
if (!emptyLine && !nextEmptyLine && !moreIndented && if (!emptyLine && !nextEmptyLine && !moreIndented &&
!nextMoreIndented && INPUT.column() >= params.indent) !nextMoreIndented && INPUT.column() >= params.indent) {
scalar += " "; scalar += " ";
else if (nextEmptyLine) } else if (nextEmptyLine) {
foldedNewlineCount++; foldedNewlineCount++;
else } else {
scalar += "\n"; scalar += "\n";
}
if (!nextEmptyLine && foldedNewlineCount > 0) { if (!nextEmptyLine && foldedNewlineCount > 0) {
scalar += std::string(foldedNewlineCount - 1, '\n'); scalar += std::string(foldedNewlineCount - 1, '\n');
if (foldedNewlineStartedMoreIndented || if (foldedNewlineStartedMoreIndented ||
nextMoreIndented | !foundNonEmptyLine) nextMoreIndented | !foundNonEmptyLine) {
scalar += "\n"; scalar += "\n";
}
foldedNewlineCount = 0; foldedNewlineCount = 0;
} }
break; break;
case FOLD_FLOW: case FOLD_FLOW:
if (nextEmptyLine) if (nextEmptyLine) {
scalar += "\n"; scalar += "\n";
else if (!emptyLine && !nextEmptyLine && !escapedNewline) } else if (!emptyLine && !nextEmptyLine && !escapedNewline) {
scalar += " "; scalar += " ";
}
break; break;
} }
} }
@ -186,35 +205,41 @@ std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) {
if (params.trimTrailingSpaces) { if (params.trimTrailingSpaces) {
std::size_t pos = scalar.find_last_not_of(' '); std::size_t pos = scalar.find_last_not_of(' ');
if (lastEscapedChar != std::string::npos) { if (lastEscapedChar != std::string::npos) {
if (pos < lastEscapedChar || pos == std::string::npos) if (pos < lastEscapedChar || pos == std::string::npos) {
pos = lastEscapedChar; pos = lastEscapedChar;
} }
if (pos < scalar.size()) }
if (pos < scalar.size()) {
scalar.erase(pos + 1); scalar.erase(pos + 1);
} }
}
switch (params.chomp) { switch (params.chomp) {
case CLIP: { case CLIP: {
std::size_t pos = scalar.find_last_not_of('\n'); std::size_t pos = scalar.find_last_not_of('\n');
if (lastEscapedChar != std::string::npos) { if (lastEscapedChar != std::string::npos) {
if (pos < lastEscapedChar || pos == std::string::npos) if (pos < lastEscapedChar || pos == std::string::npos) {
pos = lastEscapedChar; pos = lastEscapedChar;
} }
if (pos == std::string::npos) }
if (pos == std::string::npos) {
scalar.erase(); scalar.erase();
else if (pos + 1 < scalar.size()) } else if (pos + 1 < scalar.size()) {
scalar.erase(pos + 2); scalar.erase(pos + 2);
}
} break; } break;
case STRIP: { case STRIP: {
std::size_t pos = scalar.find_last_not_of('\n'); std::size_t pos = scalar.find_last_not_of('\n');
if (lastEscapedChar != std::string::npos) { if (lastEscapedChar != std::string::npos) {
if (pos < lastEscapedChar || pos == std::string::npos) if (pos < lastEscapedChar || pos == std::string::npos) {
pos = lastEscapedChar; pos = lastEscapedChar;
} }
if (pos == std::string::npos) }
if (pos == std::string::npos) {
scalar.erase(); scalar.erase();
else if (pos < scalar.size()) } else if (pos < scalar.size()) {
scalar.erase(pos + 1); scalar.erase(pos + 1);
}
} break; } break;
default: default:
break; break;

View File

@ -42,5 +42,35 @@ TEST_F(HandlerTest, NullStringScalar) {
EXPECT_CALL(handler, OnDocumentEnd()); EXPECT_CALL(handler, OnDocumentEnd());
Parse("foo: null"); Parse("foo: null");
} }
TEST_F(HandlerTest, CommentOnNewlineOfMapValueWithNoSpaces) {
EXPECT_CALL(handler, OnDocumentStart(_));
EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block));
EXPECT_CALL(handler, OnScalar(_, "?", 0, "key"));
EXPECT_CALL(handler, OnScalar(_, "?", 0, "value"));
EXPECT_CALL(handler, OnMapEnd());
EXPECT_CALL(handler, OnDocumentEnd());
Parse("key: value\n# comment");
} }
TEST_F(HandlerTest, CommentOnNewlineOfMapValueWithOneSpace) {
EXPECT_CALL(handler, OnDocumentStart(_));
EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block));
EXPECT_CALL(handler, OnScalar(_, "?", 0, "key"));
EXPECT_CALL(handler, OnScalar(_, "?", 0, "value"));
EXPECT_CALL(handler, OnMapEnd());
EXPECT_CALL(handler, OnDocumentEnd());
Parse("key: value\n # comment");
} }
TEST_F(HandlerTest, CommentOnNewlineOfMapValueWithManySpace) {
EXPECT_CALL(handler, OnDocumentStart(_));
EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block));
EXPECT_CALL(handler, OnScalar(_, "?", 0, "key"));
EXPECT_CALL(handler, OnScalar(_, "?", 0, "value"));
EXPECT_CALL(handler, OnMapEnd());
EXPECT_CALL(handler, OnDocumentEnd());
Parse("key: value\n # comment");
}
} // namespace
} // namespace YAML