Skip to content
Snippets Groups Projects
Commit 2ce5761b authored by Bienchen's avatar Bienchen
Browse files

Extended STAR parser with better error messages and more test cases. Asserts...

Extended STAR parser with better error messages and more test cases. Asserts are removed up to one single item.
parent 544c8d48
No related branches found
No related tags found
No related merge requests found
Showing with 168 additions and 40 deletions
...@@ -96,11 +96,7 @@ bool StarParser::SplitLine(const StringRef& line, ...@@ -96,11 +96,7 @@ bool StarParser::SplitLine(const StringRef& line,
while (s!=line.end() && !isspace(*s)) { while (s!=line.end() && !isspace(*s)) {
++s; ++s;
} }
if (s-start) { parts.push_back(StringRef(start, s-start));
parts.push_back(StringRef(start, s-start));
} else {
return false;
}
} }
} }
return true; return true;
...@@ -110,18 +106,28 @@ bool StarParser::ParseMultilineValue(String& value, bool skip) ...@@ -110,18 +106,28 @@ bool StarParser::ParseMultilineValue(String& value, bool skip)
{ {
std::stringstream valuebuf; std::stringstream valuebuf;
StringRef line; StringRef line;
bool r=this->GetLine(line); if (!this->GetLine(line)) {
assert(r);r=r; throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
"Unexpected end of input",
line_num_));
}
valuebuf << line.substr(1); valuebuf << line.substr(1);
bool found_semicolon = false;
while (this->NextLine(line)) { while (this->NextLine(line)) {
StringRef tline=line.rtrim(); StringRef tline=line.rtrim();
if (!tline.empty() && tline[0]==';') { if (!tline.empty() && tline[0]==';') {
found_semicolon = true;
break; break;
} }
if (!skip) { if (!skip) {
valuebuf << tline << "\n"; valuebuf << tline << "\n";
} }
} }
if (!found_semicolon) {
throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
"Unterminated multiline value",
line_num_));
}
if (!skip) { if (!skip) {
value=valuebuf.str(); value=valuebuf.str();
} }
...@@ -148,7 +154,14 @@ void StarParser::ParseLoop() ...@@ -148,7 +154,14 @@ void StarParser::ParseLoop()
prefix_len=tline.find('.')-tline.begin(); prefix_len=tline.find('.')-tline.begin();
header.SetCategory(tline.substr(1, prefix_len-1)); header.SetCategory(tline.substr(1, prefix_len-1));
} else { } else {
assert(tline[prefix_len]=='.'); if (tline[prefix_len] != '.' ||
StringRef(header.GetCategory().data(),
header.GetCategory().size())!=tline.substr(1,
prefix_len-1)) {
throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
"Change of category in loop",
line_num_));
}
} }
header.Add(tline.substr(prefix_len+1)); header.Add(tline.substr(prefix_len+1));
this->ConsumeLine(); this->ConsumeLine();
...@@ -182,8 +195,7 @@ void StarParser::ParseLoop() ...@@ -182,8 +195,7 @@ void StarParser::ParseLoop()
case ';': case ';':
if (process_rows) { if (process_rows) {
tmp_values.push_back(String()); tmp_values.push_back(String());
bool r=this->ParseMultilineValue(tmp_values.back()); this->ParseMultilineValue(tmp_values.back());
assert(r);r=r;
columns.push_back(StringRef(tmp_values.back().data(), columns.push_back(StringRef(tmp_values.back().data(),
tmp_values.back().length()).trim()); tmp_values.back().length()).trim());
if (columns.size()==header.GetSize()) { if (columns.size()==header.GetSize()) {
...@@ -193,8 +205,7 @@ void StarParser::ParseLoop() ...@@ -193,8 +205,7 @@ void StarParser::ParseLoop()
} }
} else { } else {
String s; String s;
bool r=this->ParseMultilineValue(s, true); this->ParseMultilineValue(s, true);
assert(r);r=r;
} }
break; break;
case 'd': case 'd':
...@@ -210,8 +221,7 @@ void StarParser::ParseLoop() ...@@ -210,8 +221,7 @@ void StarParser::ParseLoop()
default: default:
if (process_rows) { if (process_rows) {
int before=columns.size(); int before=columns.size();
bool r=StarParser::SplitLine(tline, columns, false); StarParser::SplitLine(tline, columns, false);
assert(r);r=r;
if (columns.size()==header.GetSize()) { if (columns.size()==header.GetSize()) {
this->OnDataRow(header, columns); this->OnDataRow(header, columns);
tmp_values.clear(); tmp_values.clear();
...@@ -278,8 +288,7 @@ void StarParser::ParseEndDataItemRow() ...@@ -278,8 +288,7 @@ void StarParser::ParseEndDataItemRow()
void StarParser::ParseDataItem() void StarParser::ParseDataItem()
{ {
StringRef line; StringRef line;
bool r=this->GetLine(line); this->GetLine(line);
assert(r);r=r;
// optimize for common case when name/value are present on the same line. // optimize for common case when name/value are present on the same line.
// We don't have to allocate any additional strings in that case. // We don't have to allocate any additional strings in that case.
std::vector<StringRef> nv; std::vector<StringRef> nv;
...@@ -302,42 +311,59 @@ void StarParser::ParseDataItem() ...@@ -302,42 +311,59 @@ void StarParser::ParseDataItem()
StarParser::SplitLine(StringRef(value.data(), value.length()), StarParser::SplitLine(StringRef(value.data(), value.length()),
nv, false); nv, false);
if (nv.size()!=2) { if (nv.size()!=2) {
std::cout << "ERROR:" << line_num_ << ":" << tline << std::endl; throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
"More than 1 value for data item "+ identifier,
line_num_));
} }
assert(nv.size()==2);
this->ConsumeLine(); this->ConsumeLine();
} }
break; break;
} }
size_t i=identifier.find('.'); if (value.empty()) {
assert(i!=String::npos); throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
"Unexpected end of input",
line_num_));
}
StringRef id_ref(identifier.data(), identifier.size()); StringRef id_ref(identifier.data(), identifier.size());
StringRef cat=StringRef(id_ref.substr(1, i-1)); StringRef cat;
StringRef name=id_ref.substr(i+1); StringRef name;
StringRef value_ref=StringRef(value.data(), StringRef value_ref=StringRef(value.data(),
value.length()).trim(); value.length()).trim();
this->ParseDataItemIdent(id_ref, cat, name);
StarDataItem data_item(cat, name, value_ref); StarDataItem data_item(cat, name, value_ref);
this->ParseDataItemOrRow(data_item); this->ParseDataItemOrRow(data_item);
} else { } else {
if (nv.size()!=2) { if (nv.size()!=2) {
std::cout << "ERROR:" << line_num_ << ":" << line << std::endl; throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
} "More than 1 value for data item "+ line.str(),
assert(nv.size()==2); line_num_));
StringRef::const_iterator i=nv[0].find('.'); }
assert(i!=nv[0].end()); StringRef cat;
StringRef cat=nv[0].substr(1, i-nv[0].begin()-1); StringRef name;
StringRef name=nv[0].substr(i-nv[0].begin()+1); this->ParseDataItemIdent(nv[0], cat, name);
StarDataItem data_item(cat, name, nv[1]); StarDataItem data_item(cat, name, nv[1]);
this->ParseDataItemOrRow(data_item); this->ParseDataItemOrRow(data_item);
this->ConsumeLine(); this->ConsumeLine();
} }
} }
void StarParser::ParseDataItemIdent(const StringRef ident,
StringRef& cat, StringRef& name)
{
StringRef::const_iterator i=ident.find('.');
if (i == ident.end()) {
throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
"Invalid data-item identifier '" + ident.str() + "'",
line_num_));
}
cat=ident.substr(1, i-ident.begin()-1);
name=ident.substr(i-ident.begin()+1);
}
void StarParser::ParseData() void StarParser::ParseData()
{ {
StringRef line; StringRef line;
bool r=this->GetLine(line); this->GetLine(line);
assert(r);r=r;
StringRef data_id=line.rtrim().substr(5); StringRef data_id=line.rtrim().substr(5);
bool skip=!this->OnBeginData(data_id); bool skip=!this->OnBeginData(data_id);
this->ConsumeLine(); this->ConsumeLine();
...@@ -364,10 +390,7 @@ void StarParser::ParseData() ...@@ -364,10 +390,7 @@ void StarParser::ParseData()
case ';': case ';':
if (skip) { if (skip) {
String s; String s;
bool r=this->ParseMultilineValue(s, true); this->ParseMultilineValue(s, true);
assert(r);r=r;
} else {
assert(0 && "';' when skip==false");
} }
break; break;
case 'l': case 'l':
...@@ -394,8 +417,7 @@ void StarParser::DiagnoseUnknown() ...@@ -394,8 +417,7 @@ void StarParser::DiagnoseUnknown()
{ {
std::stringstream ss; std::stringstream ss;
StringRef line; StringRef line;
bool r=this->GetLine(line); this->GetLine(line);
assert(r);r=r;
ss << "unknown control structure '"<< line.rtrim() << "'"; ss << "unknown control structure '"<< line.rtrim() << "'";
throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR, ss.str(), throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR, ss.str(),
line_num_)); line_num_));
......
...@@ -151,6 +151,11 @@ public: ...@@ -151,6 +151,11 @@ public:
/// \brief format diagnostic and returns it as a string. /// \brief format diagnostic and returns it as a string.
String FormatDiagnostic(StarDiagType type, const String& message, String FormatDiagnostic(StarDiagType type, const String& message,
int line=-1); int line=-1);
void SetFilename(const String& filename)
{
filename_ = filename;
}
public: public:
void Parse(); void Parse();
...@@ -194,6 +199,9 @@ private: ...@@ -194,6 +199,9 @@ private:
assert(has_current_line_); assert(has_current_line_);
has_current_line_=false; has_current_line_=false;
} }
void ParseDataItemIdent(const StringRef ident,
StringRef& cat, StringRef& name);
void ParseGlobal(); void ParseGlobal();
void ParseData(); void ParseData();
void ParseDataItem(); void ParseDataItem();
......
...@@ -247,7 +247,7 @@ BOOST_AUTO_TEST_CASE(star_data_item) ...@@ -247,7 +247,7 @@ BOOST_AUTO_TEST_CASE(star_data_item)
BOOST_AUTO_TEST_CASE(format_diag_stream) BOOST_AUTO_TEST_CASE(format_diag_stream)
{ {
BOOST_MESSAGE(" Running star_data_item tests..."); BOOST_MESSAGE(" Running format_diag_stream tests...");
std::ifstream s("testfiles/data-item.cif"); std::ifstream s("testfiles/data-item.cif");
DataItemTestParser star_p(s); DataItemTestParser star_p(s);
BOOST_CHECK_EQUAL(star_p.FormatDiagnostic(STAR_DIAG_WARNING, "bad", -1), BOOST_CHECK_EQUAL(star_p.FormatDiagnostic(STAR_DIAG_WARNING, "bad", -1),
...@@ -256,11 +256,14 @@ BOOST_AUTO_TEST_CASE(format_diag_stream) ...@@ -256,11 +256,14 @@ BOOST_AUTO_TEST_CASE(format_diag_stream)
"<stream>: error: really bad"); "<stream>: error: really bad");
BOOST_CHECK_EQUAL(star_p.FormatDiagnostic(STAR_DIAG_ERROR, "bad", 55), BOOST_CHECK_EQUAL(star_p.FormatDiagnostic(STAR_DIAG_ERROR, "bad", 55),
"<stream>:55: error: bad"); "<stream>:55: error: bad");
star_p.SetFilename("testname");
BOOST_CHECK_EQUAL(star_p.FormatDiagnostic(STAR_DIAG_ERROR, "bad", 55),
"testname:55: error: bad");
} }
BOOST_AUTO_TEST_CASE(format_diag_filename) BOOST_AUTO_TEST_CASE(format_diag_filename)
{ {
BOOST_MESSAGE(" Running star_data_item tests..."); BOOST_MESSAGE(" Running format_diag_filename tests...");
DataItemTestParser star_p("testfiles/data-item.cif"); DataItemTestParser star_p("testfiles/data-item.cif");
BOOST_CHECK_EQUAL(star_p.FormatDiagnostic(STAR_DIAG_WARNING, "bad", -1), BOOST_CHECK_EQUAL(star_p.FormatDiagnostic(STAR_DIAG_WARNING, "bad", -1),
"testfiles/data-item.cif: warning: bad"); "testfiles/data-item.cif: warning: bad");
...@@ -335,5 +338,62 @@ BOOST_AUTO_TEST_CASE(star_missing_data) ...@@ -335,5 +338,62 @@ BOOST_AUTO_TEST_CASE(star_missing_data)
LoopTestParser star_p(s); LoopTestParser star_p(s);
BOOST_CHECK_THROW(star_p.Parse(), IOException); BOOST_CHECK_THROW(star_p.Parse(), IOException);
} }
BOOST_AUTO_TEST_CASE(star_unterminated_dataitem)
{
std::ifstream s("testfiles/unterminated_dataitem.cif");
LoopTestParser star_p(s);
BOOST_CHECK_THROW(star_p.Parse(), IOException);
}
BOOST_AUTO_TEST_CASE(star_incomplete_dataitem)
{
std::ifstream s("testfiles/incomplete_dataitem.cif");
LoopTestParser star_p(s);
BOOST_CHECK_THROW(star_p.Parse(), IOException);
}
BOOST_AUTO_TEST_CASE(star_singleline_multiple_values)
{
std::ifstream s("testfiles/singleline_multivalue_dataitem.cif");
DataItemTestParser star_p(s);
BOOST_CHECK_THROW(star_p.Parse(), IOException);
}
BOOST_AUTO_TEST_CASE(star_multiline_multiple_values)
{
std::ifstream s("testfiles/multiline_multivalue_dataitem.cif");
DataItemTestParser star_p(s);
BOOST_CHECK_THROW(star_p.Parse(), IOException);
}
BOOST_AUTO_TEST_CASE(star_multiline_invalid_ident)
{
std::ifstream s("testfiles/multiline_invalid_ident.cif");
DataItemTestParser star_p(s);
BOOST_CHECK_THROW(star_p.Parse(), IOException);
}
BOOST_AUTO_TEST_CASE(star_singleline_invalid_ident)
{
std::ifstream s("testfiles/singleline_invalid_ident.cif");
DataItemTestParser star_p(s);
BOOST_CHECK_THROW(star_p.Parse(), IOException);
}
BOOST_AUTO_TEST_CASE(star_loop_category_change)
{
std::ifstream s("testfiles/loop_category_change.cif");
DataItemTestParser star_p(s);
BOOST_CHECK_THROW(star_p.Parse(), IOException);
}
BOOST_AUTO_TEST_CASE(star_loop_category_change_inplace)
{
std::ifstream s("testfiles/loop_category_change_inplace.cif");
DataItemTestParser star_p(s);
BOOST_CHECK_THROW(star_p.Parse(), IOException);
}
BOOST_AUTO_TEST_SUITE_END(); BOOST_AUTO_TEST_SUITE_END();
data_incomplete data-item
_a.x
data_singleline multi value data-item
_loop
_a.x
_a.y
_ab.z
1 2 3
data_singleline multi value data-item
_loop
_a.x
_a.y
_b.z
1 2 3
data_singleline multi value data-item
_ax
;
b
;
data_singleline multi value data-item
_a.x
a b
data_singleline multi value data-item
_ax b
data_singleline multi value data-item
_a.x a b
data_incomplete data-item
_a.x
;
2
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment