Refactor initial parsing stage

- Reduced the amount of state in the RawKeyword and ParserState classes.
 - RawKeyword class has normal constructor - remove init method.
 - The Rawxxx symbols are module private and the header files are not installed.
 - Removed several unused static methods from Rawxxx and ParserKeyword.
This commit is contained in:
Joakim Hove 2019-08-15 23:03:23 +02:00
parent 441b065b3d
commit e5013125f1
25 changed files with 539 additions and 698 deletions

View File

@ -154,9 +154,9 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/Parser/ParserItem.cpp src/opm/parser/eclipse/Parser/ParserItem.cpp
src/opm/parser/eclipse/Parser/ParserKeyword.cpp src/opm/parser/eclipse/Parser/ParserKeyword.cpp
src/opm/parser/eclipse/Parser/ParserRecord.cpp src/opm/parser/eclipse/Parser/ParserRecord.cpp
src/opm/parser/eclipse/RawDeck/RawKeyword.cpp src/opm/parser/eclipse/Parser/raw/RawKeyword.cpp
src/opm/parser/eclipse/RawDeck/RawRecord.cpp src/opm/parser/eclipse/Parser/raw/RawRecord.cpp
src/opm/parser/eclipse/RawDeck/StarToken.cpp src/opm/parser/eclipse/Parser/raw/StarToken.cpp
src/opm/parser/eclipse/Units/Dimension.cpp src/opm/parser/eclipse/Units/Dimension.cpp
src/opm/parser/eclipse/Units/UnitSystem.cpp src/opm/parser/eclipse/Units/UnitSystem.cpp
src/opm/parser/eclipse/Utility/Functional.cpp src/opm/parser/eclipse/Utility/Functional.cpp
@ -586,12 +586,7 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/Deck/DeckOutput.hpp opm/parser/eclipse/Deck/DeckOutput.hpp
opm/parser/eclipse/Deck/DeckKeyword.hpp opm/parser/eclipse/Deck/DeckKeyword.hpp
opm/parser/eclipse/Deck/DeckRecord.hpp opm/parser/eclipse/Deck/DeckRecord.hpp
opm/parser/eclipse/Deck/UDAValue.hpp opm/parser/eclipse/Deck/UDAValue.hpp)
opm/parser/eclipse/RawDeck/StarToken.hpp
opm/parser/eclipse/RawDeck/RawEnums.hpp
opm/parser/eclipse/RawDeck/RawRecord.hpp
opm/parser/eclipse/RawDeck/RawKeyword.hpp
opm/parser/eclipse/RawDeck/RawConsts.hpp)
endif() endif()
if(ENABLE_ECL_OUTPUT) if(ENABLE_ECL_OUTPUT)
list(APPEND PUBLIC_HEADER_FILES list(APPEND PUBLIC_HEADER_FILES

View File

@ -14,9 +14,9 @@ set(genkw_SOURCES src/opm/json/JsonObject.cpp
src/opm/parser/eclipse/Parser/ParserItem.cpp src/opm/parser/eclipse/Parser/ParserItem.cpp
src/opm/parser/eclipse/Parser/ParserKeyword.cpp src/opm/parser/eclipse/Parser/ParserKeyword.cpp
src/opm/parser/eclipse/Parser/ParserRecord.cpp src/opm/parser/eclipse/Parser/ParserRecord.cpp
src/opm/parser/eclipse/RawDeck/RawKeyword.cpp src/opm/parser/eclipse/Parser/raw/RawKeyword.cpp
src/opm/parser/eclipse/RawDeck/RawRecord.cpp src/opm/parser/eclipse/Parser/raw/RawRecord.cpp
src/opm/parser/eclipse/RawDeck/StarToken.cpp src/opm/parser/eclipse/Parser/raw/StarToken.cpp
src/opm/parser/eclipse/Units/Dimension.cpp src/opm/parser/eclipse/Units/Dimension.cpp
src/opm/parser/eclipse/Units/UnitSystem.cpp src/opm/parser/eclipse/Units/UnitSystem.cpp
src/opm/parser/eclipse/Utility/Stringview.cpp src/opm/parser/eclipse/Utility/Stringview.cpp

View File

@ -23,6 +23,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <utility>
#include <opm/parser/eclipse/Deck/DeckRecord.hpp> #include <opm/parser/eclipse/Deck/DeckRecord.hpp>
@ -39,7 +40,7 @@ namespace Opm {
const std::string& name() const; const std::string& name() const;
void setFixedSize(); void setFixedSize();
void setLocation(const std::string& fileName, int lineNumber); void setLocation(const std::pair<const std::string&, std::size_t>& location);
const std::string& getFileName() const; const std::string& getFileName() const;
int getLineNumber() const; int getLineNumber() const;

View File

@ -90,7 +90,6 @@ namespace Opm {
typedef std::set<std::string> SectionNameSet; typedef std::set<std::string> SectionNameSet;
static string_view getDeckName(const string_view& rawString);
static bool validInternalName(const std::string& name); static bool validInternalName(const std::string& name);
static bool validDeckName(const string_view& name); static bool validDeckName(const string_view& name);
bool hasMatchRegex() const; bool hasMatchRegex() const;
@ -127,7 +126,7 @@ namespace Opm {
enum ParserKeywordSizeEnum getSizeType() const; enum ParserKeywordSizeEnum getSizeType() const;
const KeywordSize& getKeywordSize() const; const KeywordSize& getKeywordSize() const;
bool isDataKeyword() const; bool isDataKeyword() const;
bool slashTerminatedRecords() const; bool rawStringKeyword() const;
std::string createDeclaration(const std::string& indent) const; std::string createDeclaration(const std::string& indent) const;
std::string createDecl() const; std::string createDecl() const;
@ -149,7 +148,7 @@ namespace Opm {
size_t m_fixedSize; size_t m_fixedSize;
bool m_isTableCollection; bool m_isTableCollection;
std::string m_Description; std::string m_Description;
bool slash_terminated_records = true; bool raw_string_keyword = false;
static bool validNameStart(const string_view& name); static bool validNameStart(const string_view& name);
void initDeckNames( const Json::JsonObject& jsonConfig ); void initDeckNames( const Json::JsonObject& jsonConfig );

View File

@ -54,12 +54,12 @@ namespace Opm {
bool operator==( const ParserRecord& ) const; bool operator==( const ParserRecord& ) const;
bool operator!=( const ParserRecord& ) const; bool operator!=( const ParserRecord& ) const;
bool slashTerminatedRecords() const; bool rawStringRecord() const;
private: private:
bool m_dataRecord; bool m_dataRecord;
std::vector< ParserItem > m_items; std::vector< ParserItem > m_items;
bool slash_terminated_records = true; bool raw_string_record = false;
}; };
std::ostream& operator<<( std::ostream&, const ParserRecord& ); std::ostream& operator<<( std::ostream&, const ParserRecord& );

View File

@ -1,108 +0,0 @@
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RAWKEYWORD_HPP
#define RAWKEYWORD_HPP
#include <memory>
#include <string>
#include <vector>
#include <list>
#include <opm/parser/eclipse/RawDeck/RawEnums.hpp>
#include <opm/parser/eclipse/Utility/Stringview.hpp>
namespace Opm {
class RawRecord;
class string_view;
/// Class representing a RawKeyword, meaning both the actual keyword phrase, and the records,
/// represented as a list of RawRecord objects.
/// The class also contains static functions to aid the parsing of the input file.
/// The creating of an instance is performed by calling the addRawRecordString method repeatedly.
class RawKeyword {
public:
RawKeyword(const string_view& name,
Raw::KeywordSizeEnum sizeType,
const std::string& filename,
size_t lineNR,
bool slash_terminated);
RawKeyword(const string_view& name,
const std::string& filename,
size_t lineNR ,
size_t inputSize,
bool slash_terminated,
bool isTableCollection);
const std::string& getKeywordName() const;
void addRawRecordString( const string_view& );
size_t size() const;
Raw::KeywordSizeEnum getSizeType() const;
// Special case method only for inspecting INCLUDE keywords;
// the general getRecords functionality should use the
// iterator interface.
const RawRecord& getFirstRecord( ) const;
static bool isKeywordPrefix(const string_view& line, std::string& keywordName);
bool isPartialRecordStringEmpty() const;
bool isFinished() const;
bool unKnownSize() const;
void finalizeUnknownSize();
void terminateRecord();
bool slashTerminatedRecords() const;
const std::string& getFilename() const;
size_t getLineNR() const;
using const_iterator = std::list< RawRecord >::const_iterator;
using iterator = std::list< RawRecord >::iterator;
const_iterator begin() const;
const_iterator end() const;
iterator begin();
iterator end();
bool is_title() const;
private:
Raw::KeywordSizeEnum m_sizeType;
bool m_isFinished = false;
size_t m_fixedSize;
size_t m_numTables;
size_t m_currentNumTables = 0;
std::string m_name;
std::list< RawRecord > m_records;
bool slash_terminated_records;
string_view m_partialRecordString;
size_t m_lineNR;
std::string m_filename;
bool m_is_title = false;
void commonInit(const std::string& name,const std::string& filename, size_t lineNR);
void setKeywordName(const std::string& keyword);
static bool isValidKeyword(const std::string& keywordCandidate);
};
}
#endif /* RAWKEYWORD_HPP */

View File

@ -47,9 +47,9 @@ namespace Opm {
m_slashTerminated = false; m_slashTerminated = false;
} }
void DeckKeyword::setLocation(const std::string& fileName, int lineNumber) { void DeckKeyword::setLocation(const std::pair<const std::string&, std::size_t>& location) {
m_fileName = fileName; m_fileName = location.first;
m_lineNumber = lineNumber; m_lineNumber = location.second;
} }
const std::string& DeckKeyword::getFileName() const { const std::string& DeckKeyword::getFileName() const {

View File

@ -23,10 +23,10 @@
#include <opm/parser/eclipse/Parser/ParseContext.hpp> #include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Parser/ErrorGuard.hpp> #include <opm/parser/eclipse/Parser/ErrorGuard.hpp>
#include <opm/parser/eclipse/RawDeck/RawConsts.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.hpp> #include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.hpp> #include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.hpp>
#include "../../../Parser/raw/RawConsts.hpp"
#include "UDQParser.hpp" #include "UDQParser.hpp"
#include "UDQASTNode.hpp" #include "UDQASTNode.hpp"

View File

@ -42,16 +42,20 @@
#include <opm/parser/eclipse/Parser/ParserItem.hpp> #include <opm/parser/eclipse/Parser/ParserItem.hpp>
#include <opm/parser/eclipse/Parser/ParserKeyword.hpp> #include <opm/parser/eclipse/Parser/ParserKeyword.hpp>
#include <opm/parser/eclipse/Parser/ParserRecord.hpp> #include <opm/parser/eclipse/Parser/ParserRecord.hpp>
#include <opm/parser/eclipse/RawDeck/RawConsts.hpp>
#include <opm/parser/eclipse/RawDeck/RawEnums.hpp>
#include <opm/parser/eclipse/RawDeck/RawRecord.hpp>
#include <opm/parser/eclipse/RawDeck/RawKeyword.hpp>
#include <opm/parser/eclipse/RawDeck/StarToken.hpp>
#include <opm/parser/eclipse/Utility/Stringview.hpp> #include <opm/parser/eclipse/Utility/Stringview.hpp>
#include <opm/parser/eclipse/Utility/String.hpp>
#include "raw/RawConsts.hpp"
#include "raw/RawEnums.hpp"
#include "raw/RawRecord.hpp"
#include "raw/RawKeyword.hpp"
#include "raw/StarToken.hpp"
namespace Opm { namespace Opm {
namespace { namespace {
namespace str {
const std::string emptystr = "";
struct find_comment { struct find_comment {
/* /*
@ -124,7 +128,7 @@ inline string_view trim( string_view str ) {
return { fst, lst }; return { fst, lst };
} }
inline string_view strip_slash( string_view view ) { inline string_view del_after_first_slash( string_view view ) {
using itr = string_view::const_iterator; using itr = string_view::const_iterator;
const auto term = []( itr begin, itr end ) { const auto term = []( itr begin, itr end ) {
return std::find( begin, end, '/' ); return std::find( begin, end, '/' );
@ -140,7 +144,7 @@ inline string_view strip_slash( string_view view ) {
return { begin, slash }; return { begin, slash };
} }
inline string_view strip_last_slash( string_view view ) { inline string_view del_after_last_slash( string_view view ) {
auto begin = view.begin(); auto begin = view.begin();
auto end = view.end(); auto end = view.end();
auto slash = end; auto slash = end;
@ -163,6 +167,13 @@ inline string_view strip_last_slash( string_view view ) {
return { begin, slash }; return { begin, slash };
} }
inline string_view del_after_slash(string_view view, bool raw_strings) {
if (raw_strings)
return del_after_last_slash(view);
else
return del_after_first_slash(view);
}
inline bool getline( string_view& input, string_view& line ) { inline bool getline( string_view& input, string_view& line ) {
if( input.empty() ) return false; if( input.empty() ) return false;
@ -203,7 +214,30 @@ inline std::string clean( const std::string& str ) {
return dst; return dst;
} }
const std::string emptystr = ""; inline std::string make_deck_name(const string_view& str) {
auto first_sep = std::find_if( str.begin(), str.end(), RawConsts::is_separator() );
return uppercase( str.substr(0, first_sep - str.begin()) );
}
inline string_view update_record_buffer(const string_view& record_buffer, const string_view& line) {
if (record_buffer.empty())
return line;
else
return { record_buffer.begin(), line.end() };
}
inline bool isTerminator(const string_view& line) {
return (line.size() == 1 && line.back() == RawConsts::slash);
}
inline bool isTerminatedRecordString(const string_view& line) {
return (line.back() == RawConsts::slash);
}
}
struct file { struct file {
file( boost::filesystem::path p, const std::string& in ) : file( boost::filesystem::path p, const std::string& in ) :
@ -215,6 +249,7 @@ struct file {
boost::filesystem::path path; boost::filesystem::path path;
}; };
class InputStack : public std::stack< file, std::vector< file > > { class InputStack : public std::stack< file, std::vector< file > > {
public: public:
void push( std::string&& input, boost::filesystem::path p = "" ); void push( std::string&& input, boost::filesystem::path p = "" );
@ -247,6 +282,7 @@ class ParserState {
bool done() const; bool done() const;
string_view getline(); string_view getline();
void ungetline(const string_view& ln);
void closeFile(); void closeFile();
private: private:
@ -259,7 +295,6 @@ class ParserState {
ParserKeywordSizeEnum lastSizeType = SLASH_TERMINATED; ParserKeywordSizeEnum lastSizeType = SLASH_TERMINATED;
std::string lastKeyWord; std::string lastKeyWord;
string_view nextKeyword = emptystr;
Deck deck; Deck deck;
const ParseContext& parseContext; const ParseContext& parseContext;
ErrorGuard& errors; ErrorGuard& errors;
@ -287,12 +322,25 @@ bool ParserState::done() const {
string_view ParserState::getline() { string_view ParserState::getline() {
string_view ln; string_view ln;
Opm::getline( this->input_stack.top().input, ln ); str::getline( this->input_stack.top().input, ln );
this->input_stack.top().lineNR++; this->input_stack.top().lineNR++;
return ln; return ln;
} }
void ParserState::ungetline(const string_view& line) {
auto& file_view = this->input_stack.top().input;
if (line.end() + 1 != file_view.begin())
throw std::invalid_argument("line view does not immediately proceed file_view");
file_view = string_view(line.begin(), file_view.end());
this->input_stack.top().lineNR--;
}
void ParserState::closeFile() { void ParserState::closeFile() {
this->input_stack.pop(); this->input_stack.pop();
} }
@ -313,7 +361,7 @@ ParserState::ParserState( const ParseContext& context,
} }
void ParserState::loadString(const std::string& input) { void ParserState::loadString(const std::string& input) {
this->input_stack.push( clean( input + "\n" ) ); this->input_stack.push( str::clean( input + "\n" ) );
} }
void ParserState::loadFile(const boost::filesystem::path& inputFile) { void ParserState::loadFile(const boost::filesystem::path& inputFile) {
@ -358,7 +406,7 @@ void ParserState::loadFile(const boost::filesystem::path& inputFile) {
throw std::runtime_error( "Error when reading input file '" throw std::runtime_error( "Error when reading input file '"
+ inputFileCanonical.string() + "'" ); + inputFileCanonical.string() + "'" );
this->input_stack.push( clean( buffer ), inputFileCanonical ); this->input_stack.push( str::clean( buffer ), inputFileCanonical );
} }
/* /*
@ -381,10 +429,10 @@ void ParserState::handleRandomText(const string_view& keywordString ) const {
} }
else if (lastSizeType == OTHER_KEYWORD_IN_DECK) { else if (lastSizeType == OTHER_KEYWORD_IN_DECK) {
errorKey = ParseContext::PARSE_EXTRA_RECORDS; errorKey = ParseContext::PARSE_EXTRA_RECORDS;
msg << "String: \'" msg << "String: \'"
<< keywordString << keywordString
<< "\' invalid." << "\' invalid."
<< "Too many records in keyword: " << "Too many records in keyword: "
<< lastKeyWord << lastKeyWord
<< " at: " << " at: "
<< this->line() << this->line()
@ -442,7 +490,7 @@ void ParserState::addPathAlias( const std::string& alias, const std::string& pat
RawKeyword * newRawKeyword(const ParserKeyword& parserKeyword, const std::string& keywordString, ParserState& parserState, const Parser& parser) { RawKeyword * newRawKeyword(const ParserKeyword& parserKeyword, const std::string& keywordString, ParserState& parserState, const Parser& parser) {
bool slash_terminated_records = parserKeyword.slashTerminatedRecords(); bool raw_string_keyword = parserKeyword.rawStringKeyword();
if( parserKeyword.getSizeType() == SLASH_TERMINATED || parserKeyword.getSizeType() == UNKNOWN) { if( parserKeyword.getSizeType() == SLASH_TERMINATED || parserKeyword.getSizeType() == UNKNOWN) {
@ -450,22 +498,25 @@ RawKeyword * newRawKeyword(const ParserKeyword& parserKeyword, const std::string
? Raw::SLASH_TERMINATED ? Raw::SLASH_TERMINATED
: Raw::UNKNOWN; : Raw::UNKNOWN;
return new RawKeyword( keywordString, rawSizeType, return new RawKeyword( keywordString,
parserState.current_path().string(), parserState.current_path().string(),
parserState.line(), parserState.line(),
slash_terminated_records); raw_string_keyword,
rawSizeType);
} }
if( parserKeyword.hasFixedSize() ) if( parserKeyword.hasFixedSize() )
return new RawKeyword( keywordString, return new RawKeyword( keywordString,
parserState.current_path().string(), parserState.current_path().string(),
parserState.line(), parserState.line(),
parserKeyword.getFixedSize(), raw_string_keyword,
slash_terminated_records, Raw::FIXED,
parserKeyword.isTableCollection() ); parserKeyword.getFixedSize());
const auto& keyword_size = parserKeyword.getKeywordSize(); const auto& keyword_size = parserKeyword.getKeywordSize();
const auto& deck = parserState.deck; const auto& deck = parserState.deck;
auto size_type = parserKeyword.isTableCollection() ? Raw::TABLE_COLLECTION : Raw::FIXED;
if( deck.hasKeyword(keyword_size.keyword ) ) { if( deck.hasKeyword(keyword_size.keyword ) ) {
const auto& sizeDefinitionKeyword = deck.getKeyword(keyword_size.keyword); const auto& sizeDefinitionKeyword = deck.getKeyword(keyword_size.keyword);
@ -474,9 +525,9 @@ RawKeyword * newRawKeyword(const ParserKeyword& parserKeyword, const std::string
return new RawKeyword( keywordString, return new RawKeyword( keywordString,
parserState.current_path().string(), parserState.current_path().string(),
parserState.line(), parserState.line(),
targetSize, raw_string_keyword,
slash_terminated_records, size_type,
parserKeyword.isTableCollection() ); targetSize);
} }
std::string msg = "Expected the kewyord: " +keyword_size.keyword std::string msg = "Expected the kewyord: " +keyword_size.keyword
@ -491,25 +542,23 @@ RawKeyword * newRawKeyword(const ParserKeyword& parserKeyword, const std::string
return new RawKeyword( keywordString, return new RawKeyword( keywordString,
parserState.current_path().string(), parserState.current_path().string(),
parserState.line(), parserState.line(),
targetSize, raw_string_keyword,
slash_terminated_records, size_type,
parserKeyword.isTableCollection() ); targetSize);
} }
RawKeyword * newRawKeyword( const string_view& kw, ParserState& parserState, const Parser& parser ) { RawKeyword * newRawKeyword( const std::string& deck_name, ParserState& parserState, const Parser& parser, const string_view& line ) {
auto keywordString = ParserKeyword::getDeckName( kw ); if (parser.isRecognizedKeyword(deck_name)) {
if (parser.isRecognizedKeyword(keywordString)) {
parserState.unknown_keyword = false; parserState.unknown_keyword = false;
const auto& parserKeyword = parser.getParserKeywordFromDeckName( keywordString.string() ); const auto& parserKeyword = parser.getParserKeywordFromDeckName(deck_name);
return newRawKeyword(parserKeyword, keywordString.string(), parserState, parser); return newRawKeyword(parserKeyword, deck_name, parserState, parser);
} }
if (keywordString.size() > RawConsts::maxKeywordLength) { if (deck_name.size() > RawConsts::maxKeywordLength) {
const std::string keyword8 = {keywordString.begin() , keywordString.begin() + RawConsts::maxKeywordLength}; const std::string keyword8 = deck_name.substr(0, RawConsts::maxKeywordLength);
if (parser.isRecognizedKeyword(keyword8)) { if (parser.isRecognizedKeyword(keyword8)) {
std::string msg = "Keyword: " + keywordString.string() + " too long - only first eight characters recognized"; std::string msg = "Keyword: " + deck_name + " too long - only first eight characters recognized";
parserState.parseContext.handleError(ParseContext::PARSE_LONG_KEYWORD, msg, parserState.errors); parserState.parseContext.handleError(ParseContext::PARSE_LONG_KEYWORD, msg, parserState.errors);
parserState.unknown_keyword = false; parserState.unknown_keyword = false;
@ -518,44 +567,61 @@ RawKeyword * newRawKeyword( const string_view& kw, ParserState& parserState, con
} }
} }
if( ParserKeyword::validDeckName( keywordString ) ) { if( ParserKeyword::validDeckName(deck_name) ) {
parserState.parseContext.handleUnknownKeyword( keywordString.string(), parserState.errors ); parserState.parseContext.handleUnknownKeyword( deck_name, parserState.errors );
parserState.unknown_keyword = true; parserState.unknown_keyword = true;
return {}; return nullptr;
} }
if (!parserState.unknown_keyword) if (!parserState.unknown_keyword)
parserState.handleRandomText( keywordString ); parserState.handleRandomText(line);
return {}; return nullptr;
} }
bool tryParseKeyword( ParserState& parserState, const Parser& parser, std::unique_ptr<RawKeyword>& rawKeyword ) {
if (parserState.nextKeyword.length() > 0) {
rawKeyword.reset( newRawKeyword( parserState.nextKeyword, parserState, parser ));
parserState.nextKeyword = emptystr;
}
if (rawKeyword && rawKeyword->isFinished())
return true;
std::unique_ptr<RawKeyword> tryParseKeyword( ParserState& parserState, const Parser& parser) {
bool is_title = false;
std::unique_ptr<RawKeyword> rawKeyword;
string_view record_buffer(str::emptystr);
while( !parserState.done() ) { while( !parserState.done() ) {
auto line = parserState.getline(); auto line = parserState.getline();
if( line.empty() && !rawKeyword ) continue; if( line.empty() && !rawKeyword ) continue;
if( line.empty() && !rawKeyword->is_title() ) continue; if( line.empty() && !is_title ) continue;
std::string keywordString; std::string keywordString;
if( !rawKeyword ) { if( !rawKeyword ) {
if( RawKeyword::isKeywordPrefix( line, keywordString ) ) { /*
rawKeyword.reset( newRawKeyword( keywordString, parserState, parser )); Extracting a possible keywordname from a line of deck input
parserState.lastSizeType = SLASH_TERMINATED; involves several steps.
if ( parser.isRecognizedKeyword(line) ) {
const auto& parserKeyword = parser.getParserKeywordFromDeckName( line ); 1. The make_deck_name() function will strip off everyhing
parserState.lastSizeType = parserKeyword.getSizeType(); following the first white-space separator and uppercase the
parserState.lastKeyWord = rawKeyword->getKeywordName(); string.
2. The ParserKeyword::validDeckName() verifies that the keyword
candidate only contains valid characters.
3. In the newRawKeyword() function the first 8 characters of the
deck_name is used to look for the keyword in the Parser
container.
*/
std::string deck_name = str::make_deck_name( line );
if (ParserKeyword::validDeckName(deck_name)) {
auto ptr = newRawKeyword( deck_name, parserState, parser, line );
if (ptr) {
rawKeyword.reset( ptr );
const auto& parserKeyword = parser.getParserKeywordFromDeckName(rawKeyword->getKeywordName());
parserState.lastSizeType = parserKeyword.getSizeType();
parserState.lastKeyWord = deck_name;
if (rawKeyword->isFinished())
return rawKeyword;
if (deck_name == "TITLE")
is_title = true;
} }
} else { } else {
/* We are looking at some random gibberish?! */ /* We are looking at some random gibberish?! */
@ -569,7 +635,7 @@ bool tryParseKeyword( ParserState& parserState, const Parser& parser, std::uniqu
When we are spinning through a keyword of size type UNKNOWN it When we are spinning through a keyword of size type UNKNOWN it
is essential to recognize a string as the next keyword. The is essential to recognize a string as the next keyword. The
line starting a new keyword can have arbitrary rubbish line starting a new keyword can have arbitrary rubbish
following the keyword name - i.e. this is legitimate: following the keyword name - i.e. this line
PORO Here comes some random gibberish which should be ignored PORO Here comes some random gibberish which should be ignored
10000*0.15 / 10000*0.15 /
@ -579,49 +645,65 @@ bool tryParseKeyword( ParserState& parserState, const Parser& parser, std::uniqu
line variable before we check if it is the start of a new line variable before we check if it is the start of a new
keyword. keyword.
*/ */
auto space_pos = line.find(' '); std::string deck_name = str::make_deck_name( line );
const std::string candidate_name = line.substr(0, space_pos); if( parser.isRecognizedKeyword( deck_name ) ) {
if( parser.isRecognizedKeyword( candidate_name ) ) { rawKeyword->terminateKeyword();
rawKeyword->finalizeUnknownSize(); parserState.ungetline(line);
parserState.nextKeyword = line; return rawKeyword;
return true;
} }
} }
if (rawKeyword->slashTerminatedRecords()) line = str::del_after_slash(line, rawKeyword->rawStringKeyword());
line = strip_slash(line); record_buffer = str::update_record_buffer(record_buffer, line);
else
line = strip_last_slash(line); if (is_title) {
if (record_buffer.empty()) {
RawRecord record("opm/flow simulation");
rawKeyword->addRecord(record);
} else {
RawRecord record( string_view{ record_buffer.begin(), record_buffer.end()});
rawKeyword->addRecord(record);
}
return rawKeyword;
}
if (str::isTerminator(record_buffer)) {
if (rawKeyword->terminateKeyword())
return rawKeyword;
}
if (str::isTerminatedRecordString(record_buffer)) {
RawRecord record( string_view{ record_buffer.begin(), record_buffer.end( ) - 1});
if (rawKeyword->addRecord(record))
return rawKeyword;
record_buffer = str::emptystr;
}
rawKeyword->addRawRecordString(line);
} }
if (rawKeyword
&& rawKeyword->isFinished()
&& rawKeyword->getSizeType() != Raw::UNKNOWN)
{
return true;
}
} }
if (rawKeyword if (rawKeyword) {
&& rawKeyword->getSizeType() == Raw::UNKNOWN) if (rawKeyword->getSizeType() == Raw::UNKNOWN)
{ rawKeyword->terminateKeyword();
rawKeyword->finalizeUnknownSize();
return true; if (!rawKeyword->isFinished())
throw std::invalid_argument("Keyword " + rawKeyword->getKeywordName() + " is not properly terminated");
} }
return false; return rawKeyword;
} }
bool parseState( ParserState& parserState, const Parser& parser ) { bool parseState( ParserState& parserState, const Parser& parser ) {
std::string filename = parserState.current_path().string(); std::string filename = parserState.current_path().string();
while( !parserState.done() ) { while( !parserState.done() ) {
std::unique_ptr<RawKeyword> rawKeyword; auto rawKeyword = tryParseKeyword( parserState, parser);
if( !rawKeyword )
const bool streamOK = tryParseKeyword( parserState, parser, rawKeyword );
if( !rawKeyword && !streamOK )
continue; continue;
if (rawKeyword->getKeywordName() == Opm::RawConsts::end) if (rawKeyword->getKeywordName() == Opm::RawConsts::end)
@ -657,9 +739,10 @@ bool parseState( ParserState& parserState, const Parser& parser ) {
{ {
std::stringstream ss; std::stringstream ss;
const auto& location = rawKeyword->getLocation();
ss << std::setw(5) << parserState.deck.size() ss << std::setw(5) << parserState.deck.size()
<< " Reading " << std::setw(8) << std::left << rawKeyword->getKeywordName() << " Reading " << std::setw(8) << std::left << rawKeyword->getKeywordName()
<< " from: " << rawKeyword->getFilename() << ":" << std::to_string(rawKeyword->getLineNR()); << " from: " << location.first << ":" << std::to_string(location.second);
OpmLog::info(ss.str()); OpmLog::info(ss.str());
} }
try { try {
@ -670,8 +753,9 @@ bool parseState( ParserState& parserState, const Parser& parser ) {
error message; the parser is quite confused at this state and error message; the parser is quite confused at this state and
we should not be tempted to continue the parsing. we should not be tempted to continue the parsing.
*/ */
const auto& location = rawKeyword->getLocation();
std::string msg = "\nFailed to parse keyword: " + rawKeyword->getKeywordName() + "\n" + std::string msg = "\nFailed to parse keyword: " + rawKeyword->getKeywordName() + "\n" +
"Starting at location: " + filename + "(" + std::to_string(rawKeyword->getLineNR()) + ")\n\n" + "Starting at location: " + location.first + "(" + std::to_string(location.second) + ")\n\n" +
"Inner exception: " + exc.what() + "\n"; "Inner exception: " + exc.what() + "\n";
throw std::invalid_argument(msg); throw std::invalid_argument(msg);
@ -679,8 +763,7 @@ bool parseState( ParserState& parserState, const Parser& parser ) {
} else { } else {
DeckKeyword deckKeyword( rawKeyword->getKeywordName(), false ); DeckKeyword deckKeyword( rawKeyword->getKeywordName(), false );
const std::string msg = "The keyword " + rawKeyword->getKeywordName() + " is not recognized"; const std::string msg = "The keyword " + rawKeyword->getKeywordName() + " is not recognized";
deckKeyword.setLocation( filename, deckKeyword.setLocation( rawKeyword->getLocation() );
rawKeyword->getLineNR());
parserState.deck.addKeyword( std::move( deckKeyword ) ); parserState.deck.addKeyword( std::move( deckKeyword ) );
OpmLog::warning(Log::fileMessage(parserState.current_path().string(), parserState.line(), msg)); OpmLog::warning(Log::fileMessage(parserState.current_path().string(), parserState.line(), msg));
} }
@ -697,7 +780,7 @@ bool parseState( ParserState& parserState, const Parser& parser ) {
*/ */
std::string Parser::stripComments( const std::string& str ) { std::string Parser::stripComments( const std::string& str ) {
return { str.begin(), return { str.begin(),
find_terminator( str.begin(), str.end(), find_comment() ) }; str::find_terminator( str.begin(), str.end(), str::find_comment() ) };
} }
Parser::Parser(bool addDefault) { Parser::Parser(bool addDefault) {

View File

@ -28,10 +28,11 @@
#include <opm/parser/eclipse/Parser/ParserItem.hpp> #include <opm/parser/eclipse/Parser/ParserItem.hpp>
#include <opm/parser/eclipse/Parser/ParserEnums.hpp> #include <opm/parser/eclipse/Parser/ParserEnums.hpp>
#include <opm/parser/eclipse/RawDeck/RawRecord.hpp>
#include <opm/parser/eclipse/RawDeck/StarToken.hpp>
#include <opm/parser/eclipse/Deck/UDAValue.hpp> #include <opm/parser/eclipse/Deck/UDAValue.hpp>
#include "raw/RawRecord.hpp"
#include "raw/StarToken.hpp"
namespace Opm { namespace Opm {
namespace { namespace {

View File

@ -30,9 +30,10 @@
#include <opm/parser/eclipse/Parser/ParserConst.hpp> #include <opm/parser/eclipse/Parser/ParserConst.hpp>
#include <opm/parser/eclipse/Parser/ParserKeyword.hpp> #include <opm/parser/eclipse/Parser/ParserKeyword.hpp>
#include <opm/parser/eclipse/Parser/ParserRecord.hpp> #include <opm/parser/eclipse/Parser/ParserRecord.hpp>
#include <opm/parser/eclipse/RawDeck/RawConsts.hpp>
#include <opm/parser/eclipse/RawDeck/RawKeyword.hpp> #include "raw/RawConsts.hpp"
#include <opm/parser/eclipse/RawDeck/RawRecord.hpp> #include "raw/RawKeyword.hpp"
#include "raw/RawRecord.hpp"
namespace Opm { namespace Opm {
@ -222,12 +223,6 @@ namespace Opm {
return std::all_of( name.begin() + 1, name.end(), ok ); return std::all_of( name.begin() + 1, name.end(), ok );
} }
string_view ParserKeyword::getDeckName( const string_view& str ) {
auto first_sep = std::find_if( str.begin(), str.end(), RawConsts::is_separator() );
return { str.begin(), first_sep };
}
bool ParserKeyword::validDeckName( const string_view& name) { bool ParserKeyword::validDeckName( const string_view& name) {
@ -418,8 +413,8 @@ void set_dimensions( ParserItem& item,
void ParserKeyword::addRecord( ParserRecord record ) { void ParserKeyword::addRecord( ParserRecord record ) {
m_records.push_back( std::move( record ) ); m_records.push_back( std::move( record ) );
if (!record.slashTerminatedRecords()) if (record.rawStringRecord())
this->slash_terminated_records = false; this->raw_string_keyword = true;
} }
@ -475,7 +470,7 @@ void set_dimensions( ParserItem& item,
throw std::invalid_argument("Tried to create a deck keyword from an incomplete raw keyword " + rawKeyword.getKeywordName()); throw std::invalid_argument("Tried to create a deck keyword from an incomplete raw keyword " + rawKeyword.getKeywordName());
DeckKeyword keyword( rawKeyword.getKeywordName() ); DeckKeyword keyword( rawKeyword.getKeywordName() );
keyword.setLocation( rawKeyword.getFilename(), rawKeyword.getLineNR() ); keyword.setLocation( rawKeyword.getLocation( ) );
keyword.setDataKeyword( isDataKeyword() ); keyword.setDataKeyword( isDataKeyword() );
size_t record_nr = 0; size_t record_nr = 0;
@ -483,7 +478,7 @@ void set_dimensions( ParserItem& item,
if( m_records.size() == 0 && rawRecord.size() > 0 ) if( m_records.size() == 0 && rawRecord.size() > 0 )
throw std::invalid_argument("Missing item information " + rawKeyword.getKeywordName()); throw std::invalid_argument("Missing item information " + rawKeyword.getKeywordName());
keyword.addRecord( getRecord( record_nr ).parse( parseContext, errors, rawRecord, rawKeyword.getKeywordName(), filename ) ); keyword.addRecord( this->getRecord( record_nr ).parse( parseContext, errors, rawRecord, rawKeyword.getKeywordName(), filename ) );
record_nr++; record_nr++;
} }
@ -515,8 +510,8 @@ void set_dimensions( ParserItem& item,
return m_keywordSizeType; return m_keywordSizeType;
} }
bool ParserKeyword::slashTerminatedRecords() const { bool ParserKeyword::rawStringKeyword() const {
return this->slash_terminated_records; return this->raw_string_keyword;
} }
const KeywordSize& ParserKeyword::getKeywordSize() const { const KeywordSize& ParserKeyword::getKeywordSize() const {
@ -555,9 +550,8 @@ void set_dimensions( ParserItem& item,
else if( m_deckNames.count( name.string() ) ) else if( m_deckNames.count( name.string() ) )
return true; return true;
else if (hasMatchRegex()) { else if (hasMatchRegex())
return boost::regex_match( name.begin(), name.end(), m_matchRegex); return boost::regex_match( name.begin(), name.end(), m_matchRegex);
}
return false; return false;
} }

View File

@ -22,9 +22,10 @@
#include <opm/parser/eclipse/Parser/ParseContext.hpp> #include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Parser/ParserRecord.hpp> #include <opm/parser/eclipse/Parser/ParserRecord.hpp>
#include <opm/parser/eclipse/Parser/ParserItem.hpp> #include <opm/parser/eclipse/Parser/ParserItem.hpp>
#include <opm/parser/eclipse/RawDeck/RawRecord.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp> #include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include "raw/RawRecord.hpp"
namespace Opm { namespace Opm {
namespace { namespace {
@ -46,8 +47,8 @@ namespace {
return m_items.size(); return m_items.size();
} }
bool ParserRecord::slashTerminatedRecords() const { bool ParserRecord::rawStringRecord() const {
return this->slash_terminated_records; return this->raw_string_record;
} }
void ParserRecord::addItem( ParserItem item ) { void ParserRecord::addItem( ParserItem item ) {
@ -62,7 +63,7 @@ namespace {
throw std::invalid_argument("Itemname: " + item.name() + " already exists."); throw std::invalid_argument("Itemname: " + item.name() + " already exists.");
if (item.parseRaw()) if (item.parseRaw())
this->slash_terminated_records = false; this->raw_string_record = true;
this->m_items.push_back( std::move( item ) ); this->m_items.push_back( std::move( item ) );
} }

View File

@ -28,7 +28,8 @@ namespace Opm {
SLASH_TERMINATED = 0, SLASH_TERMINATED = 0,
FIXED = 1, FIXED = 1,
UNKNOWN = 3, UNKNOWN = 3,
TABLE_COLLECTION = 4 TABLE_COLLECTION = 4,
CODE = 5,
}; };
} }
} }

View File

@ -0,0 +1,164 @@
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdexcept>
#include <boost/algorithm/string.hpp>
#include <opm/parser/eclipse/Parser/ParserKeyword.hpp>
#include <opm/parser/eclipse/Utility/String.hpp>
#include "RawConsts.hpp"
#include "RawKeyword.hpp"
#include "RawRecord.hpp"
namespace Opm {
namespace {
std::string keyword_name(const std::string& input_name) {
std::string name = boost::algorithm::trim_right_copy(input_name);
if (!ParserKeyword::validDeckName(name))
throw std::invalid_argument("Not a valid keyword:" + name);
if (name.size() > Opm::RawConsts::maxKeywordLength)
throw std::invalid_argument("Too long keyword:" + name);
if (name[0] == ' ')
throw std::invalid_argument("Illegal whitespace start of keyword:" + name);
return name;
}
}
RawKeyword::RawKeyword(const std::string& name, const std::string& filename, std::size_t lineNR, bool raw_string, Raw::KeywordSizeEnum sizeType, std::size_t size_arg) :
m_name(keyword_name(name)),
m_filename(filename),
m_lineNR(lineNR),
raw_string_keyword(raw_string),
m_sizeType(sizeType)
{
if (this->m_sizeType == Raw::FIXED) {
this->m_fixedSize = size_arg;
if (size_arg == 0)
this->m_isFinished = true;
}
if (this->m_sizeType == Raw::TABLE_COLLECTION) {
if (size_arg == 0)
throw std::logic_error("Bug in opm/flow: Attempt to create a TableCollection with zero tables. Keyword: " + name + " at " + filename + ":" + std::to_string(lineNR));
this->m_numTables = size_arg;
}
if (this->m_sizeType == Raw::SLASH_TERMINATED || this->m_sizeType == Raw::UNKNOWN) {
if (size_arg != 0)
throw std::logic_error("Bug in opm/flow: Must have size_arg == 0 for SLASH_TEMINATED and UNKNOWN. Keyword: " + name + " at " + filename + ":" + std::to_string(lineNR));
}
if (this->m_sizeType == Raw::CODE) {
if (size_arg != 1)
throw std::logic_error("Bug in opm/flow: Must have size_arg == 1 for CODE. Keyword: " + name + " at " + filename + ":" + std::to_string(lineNR));
this->m_fixedSize = size_arg;
}
}
RawKeyword::RawKeyword(const std::string& name, const std::string& filename, std::size_t lineNR, bool raw_string, Raw::KeywordSizeEnum sizeType) :
RawKeyword(name, filename, lineNR, raw_string, sizeType, sizeType == Raw::CODE ? 1 : 0)
{
if (this->m_sizeType == Raw::FIXED || this->m_sizeType == Raw::TABLE_COLLECTION)
throw std::logic_error("Internal error - wrong constructor has been used. Keyword: " + name + " at " + filename + ":" + std::to_string(lineNR));
}
const std::string& RawKeyword::getKeywordName() const {
return m_name;
}
bool RawKeyword::terminateKeyword() {
if (this->m_sizeType == Raw::SLASH_TERMINATED)
this->m_isFinished = true;
if (m_sizeType == Raw::TABLE_COLLECTION) {
m_currentNumTables += 1;
if (m_currentNumTables == m_numTables)
m_isFinished = true;
}
if( m_sizeType == Raw::UNKNOWN)
m_isFinished = true;
return this->m_isFinished;
}
bool RawKeyword::addRecord(RawRecord record) {
this->m_records.push_back(std::move(record));
if (m_records.size() == this->m_fixedSize) {
if( this->m_sizeType == Raw::FIXED || this->m_sizeType == Raw::CODE)
this->m_isFinished = true;
}
return this->m_isFinished;
}
const RawRecord& RawKeyword::getFirstRecord() const {
return *m_records.begin();
}
bool RawKeyword::isFinished() const {
return m_isFinished;
}
std::pair<std::string, std::size_t> RawKeyword::getLocation() const {
return std::make_pair(this->m_filename, this->m_lineNR);
}
RawKeyword::const_iterator RawKeyword::begin() const {
return this->m_records.begin();
}
RawKeyword::const_iterator RawKeyword::end() const {
return this->m_records.end();
}
RawKeyword::iterator RawKeyword::begin() {
return this->m_records.begin();
}
RawKeyword::iterator RawKeyword::end() {
return this->m_records.end();
}
Raw::KeywordSizeEnum RawKeyword::getSizeType() const {
return m_sizeType;
}
bool RawKeyword::rawStringKeyword() const {
return this->raw_string_keyword;
}
}

View File

@ -0,0 +1,80 @@
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RAWKEYWORD_HPP
#define RAWKEYWORD_HPP
#include <memory>
#include <string>
#include <vector>
#include <cstddef>
#include "RawEnums.hpp"
#include "RawConsts.hpp"
namespace Opm {
class RawRecord;
class string_view;
class RawKeyword {
public:
RawKeyword(const std::string& name, const std::string& filename, std::size_t lineNR, bool raw_string, Raw::KeywordSizeEnum sizeType);
RawKeyword(const std::string& name, const std::string& filename, std::size_t lineNR, bool raw_string, Raw::KeywordSizeEnum sizeType, std::size_t size_arg);
bool terminateKeyword();
bool addRecord(RawRecord record);
const std::string& getKeywordName() const;
Raw::KeywordSizeEnum getSizeType() const;
// Special case method only for inspecting INCLUDE keywords;
// the general getRecords functionality should use the
// iterator interface.
const RawRecord& getFirstRecord( ) const;
bool isFinished() const;
bool unKnownSize() const;
bool rawStringKeyword() const;
std::pair<std::string, std::size_t> getLocation() const;
using const_iterator = std::vector< RawRecord >::const_iterator;
using iterator = std::vector< RawRecord >::iterator;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
private:
std::string m_name;
std::string m_filename;
size_t m_lineNR;
bool raw_string_keyword;
Raw::KeywordSizeEnum m_sizeType;
size_t m_fixedSize = 0;
size_t m_numTables = 0;
size_t m_currentNumTables = 0;
bool m_isFinished = false;
std::vector< RawRecord > m_records;
};
}
#endif /* RAWKEYWORD_HPP */

View File

@ -23,11 +23,12 @@
#include <vector> #include <vector>
#include <deque> #include <deque>
#include <opm/parser/eclipse/RawDeck/RawRecord.hpp>
#include <opm/parser/eclipse/RawDeck/RawConsts.hpp>
#include <opm/parser/eclipse/Utility/Stringview.hpp> #include <opm/parser/eclipse/Utility/Stringview.hpp>
#include "RawRecord.hpp"
#include "RawConsts.hpp"
using namespace Opm; using namespace Opm;
using namespace std; using namespace std;
@ -106,8 +107,4 @@ inline bool even_quotes( const T& str ) {
std::string RawRecord::getRecordString() const { std::string RawRecord::getRecordString() const {
return m_sanitizedRecordString.string(); return m_sanitizedRecordString.string();
} }
bool RawRecord::isTerminatedRecordString( const string_view& str ) {
return str.back() == RawConsts::slash;
}
} }

View File

@ -45,9 +45,7 @@ namespace Opm {
std::string getRecordString() const; std::string getRecordString() const;
inline string_view getItem(size_t index) const; inline string_view getItem(size_t index) const;
static bool isTerminatedRecordString( const string_view& ); void dump() const;
void dump() const;
private: private:
string_view m_sanitizedRecordString; string_view m_sanitizedRecordString;

View File

@ -26,10 +26,11 @@
#include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/qi.hpp>
#include <opm/parser/eclipse/RawDeck/StarToken.hpp>
#include <opm/parser/eclipse/Utility/Stringview.hpp> #include <opm/parser/eclipse/Utility/Stringview.hpp>
#include <opm/parser/eclipse/Deck/UDAValue.hpp> #include <opm/parser/eclipse/Deck/UDAValue.hpp>
#include "StarToken.hpp"
namespace qi = boost::spirit::qi; namespace qi = boost::spirit::qi;
namespace Opm { namespace Opm {

View File

@ -1,218 +0,0 @@
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdexcept>
#include <boost/algorithm/string.hpp>
#include <opm/parser/eclipse/Parser/ParserKeyword.hpp>
#include <opm/parser/eclipse/RawDeck/RawConsts.hpp>
#include <opm/parser/eclipse/RawDeck/RawKeyword.hpp>
#include <opm/parser/eclipse/RawDeck/RawRecord.hpp>
#include <opm/parser/eclipse/Utility/String.hpp>
namespace Opm {
static const std::string emptystr = "";
RawKeyword::RawKeyword(const string_view& name, Raw::KeywordSizeEnum sizeType , const std::string& filename, size_t lineNR, bool slash_terminated) :
slash_terminated_records(slash_terminated),
m_partialRecordString( emptystr )
{
if (sizeType == Raw::SLASH_TERMINATED || sizeType == Raw::UNKNOWN) {
commonInit(name.string(),filename,lineNR);
m_sizeType = sizeType;
} else
throw std::invalid_argument("Error - invalid sizetype on input");
}
RawKeyword::RawKeyword(const string_view& name , const std::string& filename, size_t lineNR , size_t inputSize, bool slash_terminated, bool isTableCollection ) :
slash_terminated_records(slash_terminated)
{
commonInit(name.string(),filename,lineNR);
if (isTableCollection) {
m_sizeType = Raw::TABLE_COLLECTION;
m_numTables = inputSize;
} else {
m_sizeType = Raw::FIXED;
m_fixedSize = inputSize;
if (m_fixedSize == 0)
m_isFinished = true;
else
m_isFinished = false;
}
}
void RawKeyword::commonInit(const std::string& name , const std::string& filename, size_t lineNR) {
setKeywordName( name );
m_filename = filename;
m_lineNR = lineNR;
this->m_is_title = name == "TITLE";
}
const std::string& RawKeyword::getKeywordName() const {
return m_name;
}
size_t RawKeyword::size() const {
return m_records.size();
}
static inline bool isTerminator( const string_view& line ) {
return line.size() == 1 && line.back() == RawConsts::slash;
}
/// Important method, being repeatedly called. When a record is terminated,
/// it is added to the list of records, and a new record is started.
void RawKeyword::addRawRecordString(const string_view& partialRecordString) {
if( m_partialRecordString == emptystr )
m_partialRecordString = partialRecordString;
else
m_partialRecordString = { m_partialRecordString.begin(), partialRecordString.end() };
if( isTerminator( m_partialRecordString ) ) {
if (m_sizeType == Raw::TABLE_COLLECTION) {
m_currentNumTables += 1;
if (m_currentNumTables == m_numTables) {
m_isFinished = true;
m_partialRecordString = emptystr;
return;
}
} else if( m_sizeType == Raw::SLASH_TERMINATED) {
m_isFinished = true;
m_partialRecordString = emptystr;
return;
}
}
if( m_isFinished ) return;
if( this->is_title() ) {
string_view recstr = m_partialRecordString == ""
? "untitled"
: m_partialRecordString;
m_records.emplace_back( recstr );
m_partialRecordString = emptystr;
m_isFinished = true;
return;
}
if( RawRecord::isTerminatedRecordString( partialRecordString ) ) {
this->m_partialRecordString = string_view{ this->m_partialRecordString.begin(), this->m_partialRecordString.end() - 1 };
this->terminateRecord();
}
}
void RawKeyword::terminateRecord() {
this->m_records.emplace_back( this->m_partialRecordString );
m_partialRecordString = emptystr;
if( m_sizeType == Raw::FIXED && m_records.size() == m_fixedSize )
m_isFinished = true;
};
const RawRecord& RawKeyword::getFirstRecord() const {
return *m_records.begin();
}
bool RawKeyword::isKeywordPrefix(const string_view& line, std::string& keyword ) {
// make the keyword string ALL_UPPERCASE because Eclipse seems
// to be case-insensitive (although this is one of its
// undocumented features...)
keyword = uppercase( ParserKeyword::getDeckName( line ).string() );
return isValidKeyword( keyword );
}
bool RawKeyword::isValidKeyword(const std::string& keywordCandidate) {
return ParserKeyword::validDeckName(keywordCandidate);
}
void RawKeyword::setKeywordName(const std::string& name) {
m_name = boost::algorithm::trim_right_copy(name);
if (!isValidKeyword(m_name)) {
throw std::invalid_argument("Not a valid keyword:" + name);
} else if (m_name.size() > Opm::RawConsts::maxKeywordLength) {
throw std::invalid_argument("Too long keyword:" + name);
} else if (boost::algorithm::trim_left_copy(m_name) != m_name) {
throw std::invalid_argument("Illegal whitespace start of keyword:" + name);
}
}
bool RawKeyword::isPartialRecordStringEmpty() const {
return m_partialRecordString.size() == 0;
}
void RawKeyword::finalizeUnknownSize() {
if (m_sizeType == Raw::UNKNOWN)
m_isFinished = true;
else
throw std::invalid_argument("Fatal error finalizing keyword:" + m_name + " Only RawKeywords with UNKNOWN size can be explicitly finalized.");
}
bool RawKeyword::isFinished() const {
return m_isFinished;
}
const std::string& RawKeyword::getFilename() const {
return m_filename;
}
size_t RawKeyword::getLineNR() const {
return m_lineNR;
}
RawKeyword::const_iterator RawKeyword::begin() const {
return this->m_records.begin();
}
RawKeyword::const_iterator RawKeyword::end() const {
return this->m_records.end();
}
RawKeyword::iterator RawKeyword::begin() {
return this->m_records.begin();
}
RawKeyword::iterator RawKeyword::end() {
return this->m_records.end();
}
bool RawKeyword::is_title() const {
return this->m_is_title;
}
Raw::KeywordSizeEnum RawKeyword::getSizeType() const {
return m_sizeType;
}
bool RawKeyword::slashTerminatedRecords() const {
return this->slash_terminated_records;
}
}

View File

@ -32,7 +32,8 @@
#include <opm/parser/eclipse/Parser/ParseContext.hpp> #include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Parser/ParserItem.hpp> #include <opm/parser/eclipse/Parser/ParserItem.hpp>
#include <opm/parser/eclipse/Parser/ParserRecord.hpp> #include <opm/parser/eclipse/Parser/ParserRecord.hpp>
#include <opm/parser/eclipse/RawDeck/RawRecord.hpp>
#include "src/opm/parser/eclipse/Parser/raw/RawRecord.hpp"
using namespace Opm; using namespace Opm;

View File

@ -29,8 +29,9 @@
#include <opm/parser/eclipse/Parser/ParserKeyword.hpp> #include <opm/parser/eclipse/Parser/ParserKeyword.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/A.hpp> #include <opm/parser/eclipse/Parser/ParserKeywords/A.hpp>
#include <opm/parser/eclipse/Parser/ParserRecord.hpp> #include <opm/parser/eclipse/Parser/ParserRecord.hpp>
#include <opm/parser/eclipse/RawDeck/RawKeyword.hpp>
#include <opm/parser/eclipse/RawDeck/RawRecord.hpp> #include "src/opm/parser/eclipse/Parser/raw/RawKeyword.hpp"
#include "src/opm/parser/eclipse/Parser/raw/RawRecord.hpp"
using namespace Opm; using namespace Opm;
@ -337,7 +338,8 @@ BOOST_AUTO_TEST_CASE( handle_empty_title ) {
Parser parser; Parser parser;
const auto deck = parser.parseString( input_deck); const auto deck = parser.parseString( input_deck);
BOOST_CHECK_EQUAL( "untitled", deck.getKeyword( "TITLE" ).getStringData().front() ); BOOST_CHECK_EQUAL( "opm/flow", deck.getKeyword( "TITLE" ).getStringData().front() );
BOOST_CHECK_EQUAL( "simulation", deck.getKeyword( "TITLE" ).getStringData().back() );
} }
BOOST_AUTO_TEST_CASE( deck_comma_separated_fields ) { BOOST_AUTO_TEST_CASE( deck_comma_separated_fields ) {
@ -1612,12 +1614,12 @@ BOOST_AUTO_TEST_CASE(ParseEmptyRecord) {
const auto& tabdimsKeyword = createFixedSized("TEST" , 1); const auto& tabdimsKeyword = createFixedSized("TEST" , 1);
ParserRecord record; ParserRecord record;
ParserItem item("ITEM", INT); ParserItem item("ITEM", INT);
RawKeyword rawkeyword( tabdimsKeyword->getName() , "FILE" , 10U , 1 , true, false); RawKeyword rawkeyword( tabdimsKeyword->getName() , "FILE" , 10U , false, Raw::FIXED, 1);
ParseContext parseContext; ParseContext parseContext;
ErrorGuard errors; ErrorGuard errors;
BOOST_CHECK_EQUAL( Raw::FIXED , rawkeyword.getSizeType()); BOOST_CHECK_EQUAL( Raw::FIXED , rawkeyword.getSizeType());
rawkeyword.addRawRecordString("/"); rawkeyword.addRecord( RawRecord("") );
record.addItem(item); record.addItem(item);
tabdimsKeyword->addRecord( record ); tabdimsKeyword->addRecord( record );

View File

@ -22,232 +22,80 @@
#include <stdexcept> #include <stdexcept>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <opm/parser/eclipse/RawDeck/RawEnums.hpp> #include "src/opm/parser/eclipse/Parser/raw/RawEnums.hpp"
#include <opm/parser/eclipse/RawDeck/RawKeyword.hpp> #include "src/opm/parser/eclipse/Parser/raw/RawKeyword.hpp"
#include <opm/parser/eclipse/RawDeck/RawRecord.hpp> #include "src/opm/parser/eclipse/Parser/raw/RawRecord.hpp"
using namespace Opm; using namespace Opm;
BOOST_AUTO_TEST_CASE(RawKeywordGiveKeywordToConstructorKeywordSet) {
RawKeyword keyword("KEYYWORD", Raw::SLASH_TERMINATED , "FILE" , 10U, true); BOOST_AUTO_TEST_CASE(RawKeywordConstructor) {
BOOST_CHECK(keyword.getKeywordName() == "KEYYWORD"); BOOST_CHECK_THROW( RawKeyword("NAME", "file", 10, false, Raw::FIXED), std::logic_error);
BOOST_CHECK_EQUAL(Raw::SLASH_TERMINATED , keyword.getSizeType()); BOOST_CHECK_THROW( RawKeyword("NAME", "file", 10, false, Raw::TABLE_COLLECTION), std::logic_error);
BOOST_CHECK_THROW( RawKeyword("NAME", "file", 10, false, Raw::TABLE_COLLECTION, 0), std::logic_error);
BOOST_CHECK_THROW( RawKeyword("NAME", "file", 10, false, Raw::SLASH_TERMINATED, 5), std::logic_error);
BOOST_CHECK_THROW( RawKeyword("NAME", "file", 10, false, Raw::UNKNOWN, 5), std::logic_error);
BOOST_CHECK_THROW( RawKeyword("NAME", "file", 10, false, Raw::CODE, 2), std::logic_error);
RawKeyword kw1("NAME", "file", 10, false, Raw::SLASH_TERMINATED);
RawKeyword kw2("NAME", "file", 10, false, Raw::FIXED, 10);
RawKeyword kw3("NAME", "file", 10, false, Raw::TABLE_COLLECTION, 7);
RawKeyword kw4("NAME", "file", 10, false, Raw::CODE);
} }
BOOST_AUTO_TEST_CASE(RawKeywordSizeTypeInvalidThrows) { BOOST_AUTO_TEST_CASE(IsFinished) {
BOOST_CHECK_THROW( RawKeyword("KEYYWORD", Raw::FIXED , "FILE" , 0U, true) , std::invalid_argument); std::string storage = "RecordString";
BOOST_CHECK_THROW( RawKeyword("KEYYWORD", Raw::TABLE_COLLECTION , "FILE" , 10U, true) , std::invalid_argument); string_view line(storage);
} RawRecord rec(line);
BOOST_AUTO_TEST_CASE(RawKeywordFinalizeWrongSizeTYpeThrows) { RawKeyword kw1("NAME", "file", 10, false, Raw::FIXED, 0);
RawKeyword kw("KEYYWORD", Raw::SLASH_TERMINATED , "FILE" , 0U, true); BOOST_CHECK(kw1.isFinished());
BOOST_CHECK_THROW( kw.finalizeUnknownSize() , std::invalid_argument );
} {
RawKeyword kw2("NAME", "file", 10, false, Raw::FIXED, 2);
BOOST_CHECK(!kw2.isFinished());
BOOST_AUTO_TEST_CASE(RawKeywordFinalizeUnknownSize) {
RawKeyword kw("KEYYWORD", Raw::UNKNOWN , "FILE" , 0U, true); BOOST_CHECK(!kw2.addRecord(rec));
BOOST_CHECK( !kw.isFinished() ); BOOST_CHECK(!kw2.isFinished());
kw.finalizeUnknownSize();
BOOST_CHECK( kw.isFinished() ); BOOST_CHECK(kw2.addRecord(rec));
} BOOST_CHECK(kw2.isFinished());
}
{
RawKeyword kw("NAME", "file", 10, false, Raw::CODE);
BOOST_AUTO_TEST_CASE(RawKeywordGiveKeywordToConstructorTooLongThrows) { BOOST_CHECK(!kw.isFinished());
BOOST_CHECK_THROW(RawKeyword keyword("KEYYYWORD", Raw::SLASH_TERMINATED , "FILE" , 10U, true), std::invalid_argument);
} BOOST_CHECK(kw.addRecord(rec));
BOOST_CHECK(kw.isFinished());
BOOST_AUTO_TEST_CASE(RawKeywordSetKeywordInitialWhitespaceInKeywordThrows) { }
BOOST_CHECK_THROW(RawKeyword(" TELONG", Raw::SLASH_TERMINATED, "FILE" , 10U, true), std::invalid_argument);
} {
RawKeyword kw3("NAME", "file", 10, false, Raw::TABLE_COLLECTION, 2);
BOOST_AUTO_TEST_CASE(constructor_mixedCaseName_throws) { BOOST_CHECK(!kw3.isFinished());
BOOST_CHECK_NO_THROW(RawKeyword("Test", Raw::SLASH_TERMINATED , "FILE" , 10U, true));
} BOOST_CHECK(!kw3.terminateKeyword());
BOOST_CHECK(!kw3.isFinished());
BOOST_AUTO_TEST_CASE(RawKeywordSetKeywordInitialTabInKeywordThrows) {
BOOST_CHECK_THROW( RawKeyword("\tTELONG", Raw::SLASH_TERMINATED , "FILE" , 10U, true), std::invalid_argument); BOOST_CHECK(kw3.terminateKeyword());
} BOOST_CHECK(kw3.isFinished());
}
BOOST_AUTO_TEST_CASE(RawKeywordSetCorrectLenghtKeywordNoError) {
RawKeyword keyword("GOODONE", Raw::SLASH_TERMINATED , "FILE" , 10U, true); {
BOOST_CHECK(keyword.getKeywordName() == "GOODONE"); RawKeyword kw4("NAME", "file", 10, false, Raw::SLASH_TERMINATED);
} BOOST_CHECK(!kw4.isFinished());
BOOST_AUTO_TEST_CASE(RawKeywordSet8CharKeywordWithTrailingWhitespaceKeywordTrimmed) { BOOST_CHECK(kw4.terminateKeyword());
RawKeyword keyword("GOODONEE ", Raw::SLASH_TERMINATED , "FILE" , 10U, true); BOOST_CHECK(kw4.isFinished());
BOOST_CHECK(keyword.getKeywordName() == "GOODONEE"); }
}
{
RawKeyword kw5("NAME", "file", 10, false, Raw::UNKNOWN);
BOOST_AUTO_TEST_CASE(addRecord_singleRecord_recordAdded) { BOOST_CHECK(!kw5.isFinished());
RawKeyword keyword("TEST", Raw::SLASH_TERMINATED , "FILE" , 10U, true);
keyword.addRawRecordString("test 1 3 4 /"); BOOST_CHECK(kw5.terminateKeyword());
BOOST_CHECK_EQUAL(1U, keyword.size()); BOOST_CHECK(kw5.isFinished());
} }
BOOST_AUTO_TEST_CASE(isFinished_undef_size) {
/* addRawRecord assumes newlines etc. are stripped */
/* also assumes all records are *immediately* following the previous one */
const char* inputstr = "test 1 2 3 4 /test 1 2 3 4 test 1 2 3 4 //";
const size_t ln1 = std::strlen( "test 1 2 3 4 /" );
const size_t ln2 = ln1 + std::strlen( "test 1 2 3 4 test 1 2 3 4 " );
const size_t ln3 = ln2 + std::strlen( "/" );
const size_t ln4 = ln3 + std::strlen( "/" );
string_view incomplete1( inputstr, inputstr + ln1 );
string_view incomplete2( inputstr + ln1, inputstr + ln2 );
string_view finalizer1( inputstr + ln2, inputstr + ln3 );
string_view finalizer2( inputstr + ln3 , inputstr + ln4 );
RawKeyword keyword("TEST", Raw::SLASH_TERMINATED , "FILE" , 10U, true);
BOOST_CHECK( !keyword.isFinished() );
keyword.addRawRecordString( incomplete1 );
keyword.addRawRecordString( incomplete2 );
BOOST_CHECK( !keyword.isFinished() );
keyword.addRawRecordString( finalizer1 );
BOOST_CHECK( !keyword.isFinished() );
keyword.addRawRecordString( finalizer2 );
BOOST_CHECK( keyword.isFinished() );
}
BOOST_AUTO_TEST_CASE(isFinished_Fixedsize0) {
RawKeyword keyword("TEST" , "FILE" , 10U , 0U, true, false);
BOOST_CHECK( keyword.isFinished() );
}
BOOST_AUTO_TEST_CASE(isFinished_Fixedsize1) {
RawKeyword keyword("TEST" , "FILE" , 10U, 1U, true, false);
BOOST_CHECK( !keyword.isFinished() );
keyword.addRawRecordString("test 1 3 4 /");
BOOST_CHECK( keyword.isFinished() );
}
BOOST_AUTO_TEST_CASE(isFinished_FixedsizeMulti) {
RawKeyword keyword("TEST", "FILE" , 10U , 4U, true, false);
const char* inputstr = "test 1 2 3 4 //1 2 3 3 4 1 2 3 3 4 /1 2 3 3 /";
const size_t ln1 = std::strlen( "test 1 2 3 4 /" );
const size_t ln2 = ln1 + std::strlen( "/" );
const size_t ln3 = ln2 + std::strlen( "1 2 3 3 4 " );
const size_t ln4 = ln3 + std::strlen( "1 2 3 3 4 /" );
const size_t ln5 = ln4 + std::strlen( "1 2 3 3 /" );
string_view incomplete1( inputstr, inputstr + ln1 );
string_view finalizer1( inputstr + ln1, inputstr + ln2 );
string_view incomplete2( inputstr + ln2 , inputstr + ln3 );
string_view incomplete3( inputstr + ln3 , inputstr + ln4 );
string_view finalizer2( inputstr + ln4 , inputstr + ln5 );
BOOST_CHECK( !keyword.isFinished() );
keyword.addRawRecordString( incomplete1 );
BOOST_CHECK( !keyword.isFinished() );
keyword.addRawRecordString( finalizer1 );
BOOST_CHECK( !keyword.isFinished() );
keyword.addRawRecordString( incomplete2 );
BOOST_CHECK( !keyword.isFinished() );
keyword.addRawRecordString( incomplete3 );
BOOST_CHECK( !keyword.isFinished() );
keyword.addRawRecordString( finalizer2 );
BOOST_CHECK( keyword.isFinished() );
}
BOOST_AUTO_TEST_CASE(isTableCollection) {
RawKeyword keyword1("TEST" , "FILE" , 10U, 4U ,true, false);
RawKeyword keyword2("TEST2", Raw::SLASH_TERMINATED , "FILE" , 10U, true);
BOOST_CHECK_EQUAL( Raw::FIXED , keyword1.getSizeType());
BOOST_CHECK_EQUAL( Raw::SLASH_TERMINATED , keyword2.getSizeType());
}
BOOST_AUTO_TEST_CASE(CreateTableCollection) {
RawKeyword keyword1("TEST" , "FILE" , 10U, 2, true, true);
BOOST_CHECK_EQUAL( Raw::TABLE_COLLECTION , keyword1.getSizeType());
}
BOOST_AUTO_TEST_CASE(CreateWithFileAndLine) {
RawKeyword keyword1("TEST" , Raw::SLASH_TERMINATED , "XXX", 100, true);
BOOST_CHECK_EQUAL( "XXX" , keyword1.getFilename());
BOOST_CHECK_EQUAL( 100U , keyword1.getLineNR() );
}
BOOST_AUTO_TEST_CASE(isUnknownSize) {
RawKeyword keyword("TEST2", Raw::UNKNOWN , "FILE" , 10U, true);
BOOST_CHECK_EQUAL( Raw::UNKNOWN , keyword.getSizeType( ));
}
BOOST_AUTO_TEST_CASE(RawRecordGetRecordsCorrectElementsReturned) {
Opm::RawRecord record(" 'NODIR ' 'REVERS' 1 20 ");
BOOST_CHECK_EQUAL((unsigned) 4, record.size());
BOOST_CHECK_EQUAL("'NODIR '", record.getItem(0));
BOOST_CHECK_EQUAL("'REVERS'", record.getItem(1));
BOOST_CHECK_EQUAL("1", record.getItem(2));
BOOST_CHECK_EQUAL("20", record.getItem(3));
}
BOOST_AUTO_TEST_CASE(RawRecordIsCompleteRecordCompleteRecordReturnsTrue) {
bool isComplete = Opm::RawRecord::isTerminatedRecordString("'NODIR ' 'REVERS' 1 20 /");
BOOST_CHECK_EQUAL(true, isComplete);
}
BOOST_AUTO_TEST_CASE(RawRecordIsCompleteRecordInCompleteRecordReturnsFalse) {
bool isComplete = Opm::RawRecord::isTerminatedRecordString("'NODIR ' 'REVERS' 1 20 ");
BOOST_CHECK_EQUAL(false, isComplete);
}
BOOST_AUTO_TEST_CASE(Rawrecord_OperatorThis_OK) {
Opm::RawRecord record(" 'NODIR ' 'REVERS' 1 20 ");
BOOST_CHECK_EQUAL("'NODIR '", record.getItem(0));
BOOST_CHECK_EQUAL("'REVERS'", record.getItem(1));
BOOST_CHECK_EQUAL("1", record.getItem(2));
BOOST_CHECK_EQUAL("20", record.getItem(3));
BOOST_CHECK_THROW(record.getItem(4), std::out_of_range);
}
BOOST_AUTO_TEST_CASE(Rawrecord_PushFront_OK) {
Opm::RawRecord record(" 'NODIR ' 'REVERS' 1 20 ");
record.prepend( 1, "String2" );
record.prepend( 1, "String1" );
BOOST_CHECK_EQUAL("String1", record.getItem(0));
BOOST_CHECK_EQUAL("String2", record.getItem(1));
}
BOOST_AUTO_TEST_CASE(Rawrecord_size_OK) {
Opm::RawRecord record(" 'NODIR ' 'REVERS' 1 20 ");
BOOST_CHECK_EQUAL(4U, record.size());
record.prepend( 1, "String2");
record.prepend( 1, "String1");
BOOST_CHECK_EQUAL(6U, record.size());
}
BOOST_AUTO_TEST_CASE(Rawrecord_sizeEmpty_OK) {
Opm::RawRecord record("");
BOOST_CHECK_EQUAL(0U, record.size());
}
BOOST_AUTO_TEST_CASE(Rawrecord_spaceOnlyEmpty_OK) {
Opm::RawRecord record(" ");
BOOST_CHECK_EQUAL(0U, record.size());
} }

View File

@ -20,7 +20,8 @@
#define BOOST_TEST_MODULE ParserTests #define BOOST_TEST_MODULE ParserTests
#include <stdexcept> #include <stdexcept>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <opm/parser/eclipse/RawDeck/StarToken.hpp>
#include "src/opm/parser/eclipse/Parser/raw/StarToken.hpp"
BOOST_AUTO_TEST_CASE(NoStarThrows) { BOOST_AUTO_TEST_CASE(NoStarThrows) {