From e5013125f1c11f9e888eadb6112dcc63b14e09bb Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Thu, 15 Aug 2019 23:03:23 +0200 Subject: [PATCH] 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. --- CMakeLists_files.cmake | 13 +- GenerateKeywords.cmake | 6 +- opm/parser/eclipse/Deck/DeckKeyword.hpp | 3 +- opm/parser/eclipse/Parser/ParserKeyword.hpp | 5 +- opm/parser/eclipse/Parser/ParserRecord.hpp | 4 +- opm/parser/eclipse/RawDeck/RawKeyword.hpp | 108 ------- src/opm/parser/eclipse/Deck/DeckKeyword.cpp | 6 +- .../EclipseState/Schedule/UDQ/UDQDefine.cpp | 2 +- src/opm/parser/eclipse/Parser/Parser.cpp | 261 ++++++++++------ src/opm/parser/eclipse/Parser/ParserItem.cpp | 5 +- .../parser/eclipse/Parser/ParserKeyword.cpp | 28 +- .../parser/eclipse/Parser/ParserRecord.cpp | 9 +- .../parser/eclipse/Parser/raw}/RawConsts.hpp | 0 .../parser/eclipse/Parser/raw}/RawEnums.hpp | 3 +- .../parser/eclipse/Parser/raw/RawKeyword.cpp | 164 ++++++++++ .../parser/eclipse/Parser/raw/RawKeyword.hpp | 80 +++++ .../{RawDeck => Parser/raw}/RawRecord.cpp | 11 +- .../parser/eclipse/Parser/raw}/RawRecord.hpp | 4 +- .../{RawDeck => Parser/raw}/StarToken.cpp | 3 +- .../parser/eclipse/Parser/raw}/StarToken.hpp | 0 src/opm/parser/eclipse/RawDeck/RawKeyword.cpp | 218 ------------- tests/parser/DeckTests.cpp | 3 +- tests/parser/ParserTests.cpp | 12 +- tests/parser/RawKeywordTests.cpp | 286 ++++-------------- tests/parser/StarTokenTests.cpp | 3 +- 25 files changed, 539 insertions(+), 698 deletions(-) delete mode 100644 opm/parser/eclipse/RawDeck/RawKeyword.hpp rename {opm/parser/eclipse/RawDeck => src/opm/parser/eclipse/Parser/raw}/RawConsts.hpp (100%) rename {opm/parser/eclipse/RawDeck => src/opm/parser/eclipse/Parser/raw}/RawEnums.hpp (94%) create mode 100644 src/opm/parser/eclipse/Parser/raw/RawKeyword.cpp create mode 100644 src/opm/parser/eclipse/Parser/raw/RawKeyword.hpp rename src/opm/parser/eclipse/{RawDeck => Parser/raw}/RawRecord.cpp (93%) rename {opm/parser/eclipse/RawDeck => src/opm/parser/eclipse/Parser/raw}/RawRecord.hpp (95%) rename src/opm/parser/eclipse/{RawDeck => Parser/raw}/StarToken.cpp (99%) rename {opm/parser/eclipse/RawDeck => src/opm/parser/eclipse/Parser/raw}/StarToken.hpp (100%) delete mode 100644 src/opm/parser/eclipse/RawDeck/RawKeyword.cpp diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 3ec285cf2..badace945 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -154,9 +154,9 @@ if(ENABLE_ECL_INPUT) src/opm/parser/eclipse/Parser/ParserItem.cpp src/opm/parser/eclipse/Parser/ParserKeyword.cpp src/opm/parser/eclipse/Parser/ParserRecord.cpp - src/opm/parser/eclipse/RawDeck/RawKeyword.cpp - src/opm/parser/eclipse/RawDeck/RawRecord.cpp - src/opm/parser/eclipse/RawDeck/StarToken.cpp + src/opm/parser/eclipse/Parser/raw/RawKeyword.cpp + src/opm/parser/eclipse/Parser/raw/RawRecord.cpp + src/opm/parser/eclipse/Parser/raw/StarToken.cpp src/opm/parser/eclipse/Units/Dimension.cpp src/opm/parser/eclipse/Units/UnitSystem.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/DeckKeyword.hpp opm/parser/eclipse/Deck/DeckRecord.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) + opm/parser/eclipse/Deck/UDAValue.hpp) endif() if(ENABLE_ECL_OUTPUT) list(APPEND PUBLIC_HEADER_FILES diff --git a/GenerateKeywords.cmake b/GenerateKeywords.cmake index 1d3262bad..0b03bff48 100644 --- a/GenerateKeywords.cmake +++ b/GenerateKeywords.cmake @@ -14,9 +14,9 @@ set(genkw_SOURCES src/opm/json/JsonObject.cpp src/opm/parser/eclipse/Parser/ParserItem.cpp src/opm/parser/eclipse/Parser/ParserKeyword.cpp src/opm/parser/eclipse/Parser/ParserRecord.cpp - src/opm/parser/eclipse/RawDeck/RawKeyword.cpp - src/opm/parser/eclipse/RawDeck/RawRecord.cpp - src/opm/parser/eclipse/RawDeck/StarToken.cpp + src/opm/parser/eclipse/Parser/raw/RawKeyword.cpp + src/opm/parser/eclipse/Parser/raw/RawRecord.cpp + src/opm/parser/eclipse/Parser/raw/StarToken.cpp src/opm/parser/eclipse/Units/Dimension.cpp src/opm/parser/eclipse/Units/UnitSystem.cpp src/opm/parser/eclipse/Utility/Stringview.cpp diff --git a/opm/parser/eclipse/Deck/DeckKeyword.hpp b/opm/parser/eclipse/Deck/DeckKeyword.hpp index 6fc76c71a..362159bd7 100644 --- a/opm/parser/eclipse/Deck/DeckKeyword.hpp +++ b/opm/parser/eclipse/Deck/DeckKeyword.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -39,7 +40,7 @@ namespace Opm { const std::string& name() const; void setFixedSize(); - void setLocation(const std::string& fileName, int lineNumber); + void setLocation(const std::pair& location); const std::string& getFileName() const; int getLineNumber() const; diff --git a/opm/parser/eclipse/Parser/ParserKeyword.hpp b/opm/parser/eclipse/Parser/ParserKeyword.hpp index f910f3cfa..834111b96 100644 --- a/opm/parser/eclipse/Parser/ParserKeyword.hpp +++ b/opm/parser/eclipse/Parser/ParserKeyword.hpp @@ -90,7 +90,6 @@ namespace Opm { typedef std::set SectionNameSet; - static string_view getDeckName(const string_view& rawString); static bool validInternalName(const std::string& name); static bool validDeckName(const string_view& name); bool hasMatchRegex() const; @@ -127,7 +126,7 @@ namespace Opm { enum ParserKeywordSizeEnum getSizeType() const; const KeywordSize& getKeywordSize() const; bool isDataKeyword() const; - bool slashTerminatedRecords() const; + bool rawStringKeyword() const; std::string createDeclaration(const std::string& indent) const; std::string createDecl() const; @@ -149,7 +148,7 @@ namespace Opm { size_t m_fixedSize; bool m_isTableCollection; std::string m_Description; - bool slash_terminated_records = true; + bool raw_string_keyword = false; static bool validNameStart(const string_view& name); void initDeckNames( const Json::JsonObject& jsonConfig ); diff --git a/opm/parser/eclipse/Parser/ParserRecord.hpp b/opm/parser/eclipse/Parser/ParserRecord.hpp index e3e2dd1f2..883ef96d5 100644 --- a/opm/parser/eclipse/Parser/ParserRecord.hpp +++ b/opm/parser/eclipse/Parser/ParserRecord.hpp @@ -54,12 +54,12 @@ namespace Opm { bool operator==( const ParserRecord& ) const; bool operator!=( const ParserRecord& ) const; - bool slashTerminatedRecords() const; + bool rawStringRecord() const; private: bool m_dataRecord; std::vector< ParserItem > m_items; - bool slash_terminated_records = true; + bool raw_string_record = false; }; std::ostream& operator<<( std::ostream&, const ParserRecord& ); diff --git a/opm/parser/eclipse/RawDeck/RawKeyword.hpp b/opm/parser/eclipse/RawDeck/RawKeyword.hpp deleted file mode 100644 index 053aea690..000000000 --- a/opm/parser/eclipse/RawDeck/RawKeyword.hpp +++ /dev/null @@ -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 . - */ - -#ifndef RAWKEYWORD_HPP -#define RAWKEYWORD_HPP - -#include -#include -#include -#include - -#include -#include - -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 */ - diff --git a/src/opm/parser/eclipse/Deck/DeckKeyword.cpp b/src/opm/parser/eclipse/Deck/DeckKeyword.cpp index 52eaeda12..084bb4de9 100644 --- a/src/opm/parser/eclipse/Deck/DeckKeyword.cpp +++ b/src/opm/parser/eclipse/Deck/DeckKeyword.cpp @@ -47,9 +47,9 @@ namespace Opm { m_slashTerminated = false; } - void DeckKeyword::setLocation(const std::string& fileName, int lineNumber) { - m_fileName = fileName; - m_lineNumber = lineNumber; + void DeckKeyword::setLocation(const std::pair& location) { + m_fileName = location.first; + m_lineNumber = location.second; } const std::string& DeckKeyword::getFileName() const { diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.cpp index d9cf7ba47..46e05effc 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQDefine.cpp @@ -23,10 +23,10 @@ #include #include -#include #include #include +#include "../../../Parser/raw/RawConsts.hpp" #include "UDQParser.hpp" #include "UDQASTNode.hpp" diff --git a/src/opm/parser/eclipse/Parser/Parser.cpp b/src/opm/parser/eclipse/Parser/Parser.cpp index ee6826ae5..d053c2478 100644 --- a/src/opm/parser/eclipse/Parser/Parser.cpp +++ b/src/opm/parser/eclipse/Parser/Parser.cpp @@ -42,16 +42,20 @@ #include #include #include -#include -#include -#include -#include -#include #include +#include + +#include "raw/RawConsts.hpp" +#include "raw/RawEnums.hpp" +#include "raw/RawRecord.hpp" +#include "raw/RawKeyword.hpp" +#include "raw/StarToken.hpp" namespace Opm { namespace { +namespace str { +const std::string emptystr = ""; struct find_comment { /* @@ -124,7 +128,7 @@ inline string_view trim( string_view str ) { 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; const auto term = []( itr begin, itr end ) { return std::find( begin, end, '/' ); @@ -140,7 +144,7 @@ inline string_view strip_slash( string_view view ) { 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 end = view.end(); auto slash = end; @@ -163,6 +167,13 @@ inline string_view strip_last_slash( string_view view ) { 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 ) { if( input.empty() ) return false; @@ -203,7 +214,30 @@ inline std::string clean( const std::string& str ) { 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 { file( boost::filesystem::path p, const std::string& in ) : @@ -215,6 +249,7 @@ struct file { boost::filesystem::path path; }; + class InputStack : public std::stack< file, std::vector< file > > { public: void push( std::string&& input, boost::filesystem::path p = "" ); @@ -247,6 +282,7 @@ class ParserState { bool done() const; string_view getline(); + void ungetline(const string_view& ln); void closeFile(); private: @@ -259,7 +295,6 @@ class ParserState { ParserKeywordSizeEnum lastSizeType = SLASH_TERMINATED; std::string lastKeyWord; - string_view nextKeyword = emptystr; Deck deck; const ParseContext& parseContext; ErrorGuard& errors; @@ -287,12 +322,25 @@ bool ParserState::done() const { string_view ParserState::getline() { string_view ln; - Opm::getline( this->input_stack.top().input, ln ); + str::getline( this->input_stack.top().input, ln ); this->input_stack.top().lineNR++; 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() { this->input_stack.pop(); } @@ -313,7 +361,7 @@ ParserState::ParserState( const ParseContext& context, } 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) { @@ -358,7 +406,7 @@ void ParserState::loadFile(const boost::filesystem::path& inputFile) { throw std::runtime_error( "Error when reading input file '" + 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) { errorKey = ParseContext::PARSE_EXTRA_RECORDS; - msg << "String: \'" + msg << "String: \'" << keywordString << "\' invalid." - << "Too many records in keyword: " + << "Too many records in keyword: " << lastKeyWord << " at: " << 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) { - bool slash_terminated_records = parserKeyword.slashTerminatedRecords(); + bool raw_string_keyword = parserKeyword.rawStringKeyword(); if( parserKeyword.getSizeType() == SLASH_TERMINATED || parserKeyword.getSizeType() == UNKNOWN) { @@ -450,22 +498,25 @@ RawKeyword * newRawKeyword(const ParserKeyword& parserKeyword, const std::string ? Raw::SLASH_TERMINATED : Raw::UNKNOWN; - return new RawKeyword( keywordString, rawSizeType, + return new RawKeyword( keywordString, parserState.current_path().string(), parserState.line(), - slash_terminated_records); + raw_string_keyword, + rawSizeType); } if( parserKeyword.hasFixedSize() ) return new RawKeyword( keywordString, parserState.current_path().string(), parserState.line(), - parserKeyword.getFixedSize(), - slash_terminated_records, - parserKeyword.isTableCollection() ); + raw_string_keyword, + Raw::FIXED, + parserKeyword.getFixedSize()); + const auto& keyword_size = parserKeyword.getKeywordSize(); const auto& deck = parserState.deck; + auto size_type = parserKeyword.isTableCollection() ? Raw::TABLE_COLLECTION : Raw::FIXED; if( deck.hasKeyword(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, parserState.current_path().string(), parserState.line(), - targetSize, - slash_terminated_records, - parserKeyword.isTableCollection() ); + raw_string_keyword, + size_type, + targetSize); } 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, parserState.current_path().string(), parserState.line(), - targetSize, - slash_terminated_records, - parserKeyword.isTableCollection() ); + raw_string_keyword, + size_type, + targetSize); } -RawKeyword * newRawKeyword( const string_view& kw, ParserState& parserState, const Parser& parser ) { - auto keywordString = ParserKeyword::getDeckName( kw ); - - if (parser.isRecognizedKeyword(keywordString)) { +RawKeyword * newRawKeyword( const std::string& deck_name, ParserState& parserState, const Parser& parser, const string_view& line ) { + if (parser.isRecognizedKeyword(deck_name)) { parserState.unknown_keyword = false; - const auto& parserKeyword = parser.getParserKeywordFromDeckName( keywordString.string() ); - return newRawKeyword(parserKeyword, keywordString.string(), parserState, parser); + const auto& parserKeyword = parser.getParserKeywordFromDeckName(deck_name); + return newRawKeyword(parserKeyword, deck_name, parserState, parser); } - if (keywordString.size() > RawConsts::maxKeywordLength) { - const std::string keyword8 = {keywordString.begin() , keywordString.begin() + RawConsts::maxKeywordLength}; + if (deck_name.size() > RawConsts::maxKeywordLength) { + const std::string keyword8 = deck_name.substr(0, RawConsts::maxKeywordLength); 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.unknown_keyword = false; @@ -518,44 +567,61 @@ RawKeyword * newRawKeyword( const string_view& kw, ParserState& parserState, con } } - if( ParserKeyword::validDeckName( keywordString ) ) { - parserState.parseContext.handleUnknownKeyword( keywordString.string(), parserState.errors ); + if( ParserKeyword::validDeckName(deck_name) ) { + parserState.parseContext.handleUnknownKeyword( deck_name, parserState.errors ); parserState.unknown_keyword = true; - return {}; + return nullptr; } if (!parserState.unknown_keyword) - parserState.handleRandomText( keywordString ); + parserState.handleRandomText(line); - return {}; + return nullptr; } -bool tryParseKeyword( ParserState& parserState, const Parser& parser, std::unique_ptr& 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 tryParseKeyword( ParserState& parserState, const Parser& parser) { + bool is_title = false; + std::unique_ptr rawKeyword; + string_view record_buffer(str::emptystr); while( !parserState.done() ) { auto line = parserState.getline(); if( line.empty() && !rawKeyword ) continue; - if( line.empty() && !rawKeyword->is_title() ) continue; + if( line.empty() && !is_title ) continue; std::string keywordString; if( !rawKeyword ) { - if( RawKeyword::isKeywordPrefix( line, keywordString ) ) { - rawKeyword.reset( newRawKeyword( keywordString, parserState, parser )); - parserState.lastSizeType = SLASH_TERMINATED; - if ( parser.isRecognizedKeyword(line) ) { - const auto& parserKeyword = parser.getParserKeywordFromDeckName( line ); - parserState.lastSizeType = parserKeyword.getSizeType(); - parserState.lastKeyWord = rawKeyword->getKeywordName(); + /* + Extracting a possible keywordname from a line of deck input + involves several steps. + + 1. The make_deck_name() function will strip off everyhing + following the first white-space separator and uppercase the + 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 { /* 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 is essential to recognize a string as the next keyword. The 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 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 keyword. */ - auto space_pos = line.find(' '); - const std::string candidate_name = line.substr(0, space_pos); - if( parser.isRecognizedKeyword( candidate_name ) ) { - rawKeyword->finalizeUnknownSize(); - parserState.nextKeyword = line; - return true; + std::string deck_name = str::make_deck_name( line ); + if( parser.isRecognizedKeyword( deck_name ) ) { + rawKeyword->terminateKeyword(); + parserState.ungetline(line); + return rawKeyword; } } - if (rawKeyword->slashTerminatedRecords()) - line = strip_slash(line); - else - line = strip_last_slash(line); + line = str::del_after_slash(line, rawKeyword->rawStringKeyword()); + record_buffer = str::update_record_buffer(record_buffer, 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 - && rawKeyword->getSizeType() == Raw::UNKNOWN) - { - rawKeyword->finalizeUnknownSize(); - return true; + if (rawKeyword) { + if (rawKeyword->getSizeType() == Raw::UNKNOWN) + rawKeyword->terminateKeyword(); + + 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 ) { std::string filename = parserState.current_path().string(); while( !parserState.done() ) { - std::unique_ptr rawKeyword; - - const bool streamOK = tryParseKeyword( parserState, parser, rawKeyword ); - if( !rawKeyword && !streamOK ) + auto rawKeyword = tryParseKeyword( parserState, parser); + if( !rawKeyword ) continue; if (rawKeyword->getKeywordName() == Opm::RawConsts::end) @@ -657,9 +739,10 @@ bool parseState( ParserState& parserState, const Parser& parser ) { { std::stringstream ss; + const auto& location = rawKeyword->getLocation(); ss << std::setw(5) << parserState.deck.size() << " 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()); } try { @@ -670,8 +753,9 @@ bool parseState( ParserState& parserState, const Parser& parser ) { error message; the parser is quite confused at this state and we should not be tempted to continue the parsing. */ + const auto& location = rawKeyword->getLocation(); 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"; throw std::invalid_argument(msg); @@ -679,8 +763,7 @@ bool parseState( ParserState& parserState, const Parser& parser ) { } else { DeckKeyword deckKeyword( rawKeyword->getKeywordName(), false ); const std::string msg = "The keyword " + rawKeyword->getKeywordName() + " is not recognized"; - deckKeyword.setLocation( filename, - rawKeyword->getLineNR()); + deckKeyword.setLocation( rawKeyword->getLocation() ); parserState.deck.addKeyword( std::move( deckKeyword ) ); 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 ) { 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) { diff --git a/src/opm/parser/eclipse/Parser/ParserItem.cpp b/src/opm/parser/eclipse/Parser/ParserItem.cpp index 04406e01c..e1cad5011 100644 --- a/src/opm/parser/eclipse/Parser/ParserItem.cpp +++ b/src/opm/parser/eclipse/Parser/ParserItem.cpp @@ -28,10 +28,11 @@ #include #include -#include -#include #include +#include "raw/RawRecord.hpp" +#include "raw/StarToken.hpp" + namespace Opm { namespace { diff --git a/src/opm/parser/eclipse/Parser/ParserKeyword.cpp b/src/opm/parser/eclipse/Parser/ParserKeyword.cpp index 9f2ea5d70..431ca0f27 100644 --- a/src/opm/parser/eclipse/Parser/ParserKeyword.cpp +++ b/src/opm/parser/eclipse/Parser/ParserKeyword.cpp @@ -30,9 +30,10 @@ #include #include #include -#include -#include -#include + +#include "raw/RawConsts.hpp" +#include "raw/RawKeyword.hpp" +#include "raw/RawRecord.hpp" namespace Opm { @@ -222,12 +223,6 @@ namespace Opm { 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) { @@ -418,8 +413,8 @@ void set_dimensions( ParserItem& item, void ParserKeyword::addRecord( ParserRecord record ) { m_records.push_back( std::move( record ) ); - if (!record.slashTerminatedRecords()) - this->slash_terminated_records = false; + if (record.rawStringRecord()) + 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()); DeckKeyword keyword( rawKeyword.getKeywordName() ); - keyword.setLocation( rawKeyword.getFilename(), rawKeyword.getLineNR() ); + keyword.setLocation( rawKeyword.getLocation( ) ); keyword.setDataKeyword( isDataKeyword() ); size_t record_nr = 0; @@ -483,7 +478,7 @@ void set_dimensions( ParserItem& item, if( m_records.size() == 0 && rawRecord.size() > 0 ) 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++; } @@ -515,8 +510,8 @@ void set_dimensions( ParserItem& item, return m_keywordSizeType; } - bool ParserKeyword::slashTerminatedRecords() const { - return this->slash_terminated_records; + bool ParserKeyword::rawStringKeyword() const { + return this->raw_string_keyword; } const KeywordSize& ParserKeyword::getKeywordSize() const { @@ -555,9 +550,8 @@ void set_dimensions( ParserItem& item, else if( m_deckNames.count( name.string() ) ) return true; - else if (hasMatchRegex()) { + else if (hasMatchRegex()) return boost::regex_match( name.begin(), name.end(), m_matchRegex); - } return false; } diff --git a/src/opm/parser/eclipse/Parser/ParserRecord.cpp b/src/opm/parser/eclipse/Parser/ParserRecord.cpp index eedf94765..046a11aec 100644 --- a/src/opm/parser/eclipse/Parser/ParserRecord.cpp +++ b/src/opm/parser/eclipse/Parser/ParserRecord.cpp @@ -22,9 +22,10 @@ #include #include #include -#include #include +#include "raw/RawRecord.hpp" + namespace Opm { namespace { @@ -46,8 +47,8 @@ namespace { return m_items.size(); } - bool ParserRecord::slashTerminatedRecords() const { - return this->slash_terminated_records; + bool ParserRecord::rawStringRecord() const { + return this->raw_string_record; } void ParserRecord::addItem( ParserItem item ) { @@ -62,7 +63,7 @@ namespace { throw std::invalid_argument("Itemname: " + item.name() + " already exists."); if (item.parseRaw()) - this->slash_terminated_records = false; + this->raw_string_record = true; this->m_items.push_back( std::move( item ) ); } diff --git a/opm/parser/eclipse/RawDeck/RawConsts.hpp b/src/opm/parser/eclipse/Parser/raw/RawConsts.hpp similarity index 100% rename from opm/parser/eclipse/RawDeck/RawConsts.hpp rename to src/opm/parser/eclipse/Parser/raw/RawConsts.hpp diff --git a/opm/parser/eclipse/RawDeck/RawEnums.hpp b/src/opm/parser/eclipse/Parser/raw/RawEnums.hpp similarity index 94% rename from opm/parser/eclipse/RawDeck/RawEnums.hpp rename to src/opm/parser/eclipse/Parser/raw/RawEnums.hpp index 34f60ba47..2630a4d8a 100644 --- a/opm/parser/eclipse/RawDeck/RawEnums.hpp +++ b/src/opm/parser/eclipse/Parser/raw/RawEnums.hpp @@ -28,7 +28,8 @@ namespace Opm { SLASH_TERMINATED = 0, FIXED = 1, UNKNOWN = 3, - TABLE_COLLECTION = 4 + TABLE_COLLECTION = 4, + CODE = 5, }; } } diff --git a/src/opm/parser/eclipse/Parser/raw/RawKeyword.cpp b/src/opm/parser/eclipse/Parser/raw/RawKeyword.cpp new file mode 100644 index 000000000..3b26d533d --- /dev/null +++ b/src/opm/parser/eclipse/Parser/raw/RawKeyword.cpp @@ -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 . + */ +#include +#include + +#include +#include + +#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 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; + } + +} + diff --git a/src/opm/parser/eclipse/Parser/raw/RawKeyword.hpp b/src/opm/parser/eclipse/Parser/raw/RawKeyword.hpp new file mode 100644 index 000000000..c45d58430 --- /dev/null +++ b/src/opm/parser/eclipse/Parser/raw/RawKeyword.hpp @@ -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 . + */ + +#ifndef RAWKEYWORD_HPP +#define RAWKEYWORD_HPP + +#include +#include +#include +#include + +#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 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 */ + diff --git a/src/opm/parser/eclipse/RawDeck/RawRecord.cpp b/src/opm/parser/eclipse/Parser/raw/RawRecord.cpp similarity index 93% rename from src/opm/parser/eclipse/RawDeck/RawRecord.cpp rename to src/opm/parser/eclipse/Parser/raw/RawRecord.cpp index 8f79b77f0..5b8af1e03 100644 --- a/src/opm/parser/eclipse/RawDeck/RawRecord.cpp +++ b/src/opm/parser/eclipse/Parser/raw/RawRecord.cpp @@ -23,11 +23,12 @@ #include #include -#include -#include - #include +#include "RawRecord.hpp" +#include "RawConsts.hpp" + + using namespace Opm; using namespace std; @@ -106,8 +107,4 @@ inline bool even_quotes( const T& str ) { std::string RawRecord::getRecordString() const { return m_sanitizedRecordString.string(); } - - bool RawRecord::isTerminatedRecordString( const string_view& str ) { - return str.back() == RawConsts::slash; - } } diff --git a/opm/parser/eclipse/RawDeck/RawRecord.hpp b/src/opm/parser/eclipse/Parser/raw/RawRecord.hpp similarity index 95% rename from opm/parser/eclipse/RawDeck/RawRecord.hpp rename to src/opm/parser/eclipse/Parser/raw/RawRecord.hpp index 6da0ee847..a2a6b6fe5 100644 --- a/opm/parser/eclipse/RawDeck/RawRecord.hpp +++ b/src/opm/parser/eclipse/Parser/raw/RawRecord.hpp @@ -45,9 +45,7 @@ namespace Opm { std::string getRecordString() const; inline string_view getItem(size_t index) const; - static bool isTerminatedRecordString( const string_view& ); - - void dump() const; + void dump() const; private: string_view m_sanitizedRecordString; diff --git a/src/opm/parser/eclipse/RawDeck/StarToken.cpp b/src/opm/parser/eclipse/Parser/raw/StarToken.cpp similarity index 99% rename from src/opm/parser/eclipse/RawDeck/StarToken.cpp rename to src/opm/parser/eclipse/Parser/raw/StarToken.cpp index 2d55a9c17..d4ee0e406 100644 --- a/src/opm/parser/eclipse/RawDeck/StarToken.cpp +++ b/src/opm/parser/eclipse/Parser/raw/StarToken.cpp @@ -26,10 +26,11 @@ #include -#include #include #include +#include "StarToken.hpp" + namespace qi = boost::spirit::qi; namespace Opm { diff --git a/opm/parser/eclipse/RawDeck/StarToken.hpp b/src/opm/parser/eclipse/Parser/raw/StarToken.hpp similarity index 100% rename from opm/parser/eclipse/RawDeck/StarToken.hpp rename to src/opm/parser/eclipse/Parser/raw/StarToken.hpp diff --git a/src/opm/parser/eclipse/RawDeck/RawKeyword.cpp b/src/opm/parser/eclipse/RawDeck/RawKeyword.cpp deleted file mode 100644 index 51a71ee32..000000000 --- a/src/opm/parser/eclipse/RawDeck/RawKeyword.cpp +++ /dev/null @@ -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 . - */ -#include -#include - -#include -#include -#include -#include -#include - -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; - } - -} - diff --git a/tests/parser/DeckTests.cpp b/tests/parser/DeckTests.cpp index bb4979731..bd6c00f4c 100644 --- a/tests/parser/DeckTests.cpp +++ b/tests/parser/DeckTests.cpp @@ -32,7 +32,8 @@ #include #include #include -#include + +#include "src/opm/parser/eclipse/Parser/raw/RawRecord.hpp" using namespace Opm; diff --git a/tests/parser/ParserTests.cpp b/tests/parser/ParserTests.cpp index 3ba0f7925..3919958f5 100644 --- a/tests/parser/ParserTests.cpp +++ b/tests/parser/ParserTests.cpp @@ -29,8 +29,9 @@ #include #include #include -#include -#include + +#include "src/opm/parser/eclipse/Parser/raw/RawKeyword.hpp" +#include "src/opm/parser/eclipse/Parser/raw/RawRecord.hpp" using namespace Opm; @@ -337,7 +338,8 @@ BOOST_AUTO_TEST_CASE( handle_empty_title ) { Parser parser; 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 ) { @@ -1612,12 +1614,12 @@ BOOST_AUTO_TEST_CASE(ParseEmptyRecord) { const auto& tabdimsKeyword = createFixedSized("TEST" , 1); ParserRecord record; 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; ErrorGuard errors; BOOST_CHECK_EQUAL( Raw::FIXED , rawkeyword.getSizeType()); - rawkeyword.addRawRecordString("/"); + rawkeyword.addRecord( RawRecord("") ); record.addItem(item); tabdimsKeyword->addRecord( record ); diff --git a/tests/parser/RawKeywordTests.cpp b/tests/parser/RawKeywordTests.cpp index af8090930..35cc95594 100644 --- a/tests/parser/RawKeywordTests.cpp +++ b/tests/parser/RawKeywordTests.cpp @@ -22,232 +22,80 @@ #include #include -#include -#include -#include +#include "src/opm/parser/eclipse/Parser/raw/RawEnums.hpp" +#include "src/opm/parser/eclipse/Parser/raw/RawKeyword.hpp" +#include "src/opm/parser/eclipse/Parser/raw/RawRecord.hpp" using namespace Opm; -BOOST_AUTO_TEST_CASE(RawKeywordGiveKeywordToConstructorKeywordSet) { - RawKeyword keyword("KEYYWORD", Raw::SLASH_TERMINATED , "FILE" , 10U, true); - BOOST_CHECK(keyword.getKeywordName() == "KEYYWORD"); - BOOST_CHECK_EQUAL(Raw::SLASH_TERMINATED , keyword.getSizeType()); + +BOOST_AUTO_TEST_CASE(RawKeywordConstructor) { + BOOST_CHECK_THROW( RawKeyword("NAME", "file", 10, false, Raw::FIXED), std::logic_error); + 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_CHECK_THROW( RawKeyword("KEYYWORD", Raw::FIXED , "FILE" , 0U, true) , std::invalid_argument); - BOOST_CHECK_THROW( RawKeyword("KEYYWORD", Raw::TABLE_COLLECTION , "FILE" , 10U, true) , std::invalid_argument); -} +BOOST_AUTO_TEST_CASE(IsFinished) { + std::string storage = "RecordString"; + string_view line(storage); + RawRecord rec(line); -BOOST_AUTO_TEST_CASE(RawKeywordFinalizeWrongSizeTYpeThrows) { - RawKeyword kw("KEYYWORD", Raw::SLASH_TERMINATED , "FILE" , 0U, true); - BOOST_CHECK_THROW( kw.finalizeUnknownSize() , std::invalid_argument ); -} - - -BOOST_AUTO_TEST_CASE(RawKeywordFinalizeUnknownSize) { - RawKeyword kw("KEYYWORD", Raw::UNKNOWN , "FILE" , 0U, true); - BOOST_CHECK( !kw.isFinished() ); - kw.finalizeUnknownSize(); - BOOST_CHECK( kw.isFinished() ); -} - - - - -BOOST_AUTO_TEST_CASE(RawKeywordGiveKeywordToConstructorTooLongThrows) { - BOOST_CHECK_THROW(RawKeyword keyword("KEYYYWORD", Raw::SLASH_TERMINATED , "FILE" , 10U, true), std::invalid_argument); -} - -BOOST_AUTO_TEST_CASE(RawKeywordSetKeywordInitialWhitespaceInKeywordThrows) { - BOOST_CHECK_THROW(RawKeyword(" TELONG", Raw::SLASH_TERMINATED, "FILE" , 10U, true), std::invalid_argument); -} - -BOOST_AUTO_TEST_CASE(constructor_mixedCaseName_throws) { - BOOST_CHECK_NO_THROW(RawKeyword("Test", Raw::SLASH_TERMINATED , "FILE" , 10U, true)); -} - -BOOST_AUTO_TEST_CASE(RawKeywordSetKeywordInitialTabInKeywordThrows) { - BOOST_CHECK_THROW( RawKeyword("\tTELONG", Raw::SLASH_TERMINATED , "FILE" , 10U, true), std::invalid_argument); -} - -BOOST_AUTO_TEST_CASE(RawKeywordSetCorrectLenghtKeywordNoError) { - RawKeyword keyword("GOODONE", Raw::SLASH_TERMINATED , "FILE" , 10U, true); - BOOST_CHECK(keyword.getKeywordName() == "GOODONE"); -} - -BOOST_AUTO_TEST_CASE(RawKeywordSet8CharKeywordWithTrailingWhitespaceKeywordTrimmed) { - RawKeyword keyword("GOODONEE ", Raw::SLASH_TERMINATED , "FILE" , 10U, true); - BOOST_CHECK(keyword.getKeywordName() == "GOODONEE"); -} - - -BOOST_AUTO_TEST_CASE(addRecord_singleRecord_recordAdded) { - RawKeyword keyword("TEST", Raw::SLASH_TERMINATED , "FILE" , 10U, true); - keyword.addRawRecordString("test 1 3 4 /"); - BOOST_CHECK_EQUAL(1U, keyword.size()); -} - - - - -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()); + RawKeyword kw1("NAME", "file", 10, false, Raw::FIXED, 0); + BOOST_CHECK(kw1.isFinished()); + + { + RawKeyword kw2("NAME", "file", 10, false, Raw::FIXED, 2); + BOOST_CHECK(!kw2.isFinished()); + + BOOST_CHECK(!kw2.addRecord(rec)); + BOOST_CHECK(!kw2.isFinished()); + + BOOST_CHECK(kw2.addRecord(rec)); + BOOST_CHECK(kw2.isFinished()); + } + + { + RawKeyword kw("NAME", "file", 10, false, Raw::CODE); + BOOST_CHECK(!kw.isFinished()); + + BOOST_CHECK(kw.addRecord(rec)); + BOOST_CHECK(kw.isFinished()); + } + + { + RawKeyword kw3("NAME", "file", 10, false, Raw::TABLE_COLLECTION, 2); + BOOST_CHECK(!kw3.isFinished()); + + BOOST_CHECK(!kw3.terminateKeyword()); + BOOST_CHECK(!kw3.isFinished()); + + BOOST_CHECK(kw3.terminateKeyword()); + BOOST_CHECK(kw3.isFinished()); + } + + { + RawKeyword kw4("NAME", "file", 10, false, Raw::SLASH_TERMINATED); + BOOST_CHECK(!kw4.isFinished()); + + BOOST_CHECK(kw4.terminateKeyword()); + BOOST_CHECK(kw4.isFinished()); + } + + { + RawKeyword kw5("NAME", "file", 10, false, Raw::UNKNOWN); + BOOST_CHECK(!kw5.isFinished()); + + BOOST_CHECK(kw5.terminateKeyword()); + BOOST_CHECK(kw5.isFinished()); + } } diff --git a/tests/parser/StarTokenTests.cpp b/tests/parser/StarTokenTests.cpp index 0460686b4..e17fee18d 100644 --- a/tests/parser/StarTokenTests.cpp +++ b/tests/parser/StarTokenTests.cpp @@ -20,7 +20,8 @@ #define BOOST_TEST_MODULE ParserTests #include #include -#include + +#include "src/opm/parser/eclipse/Parser/raw/StarToken.hpp" BOOST_AUTO_TEST_CASE(NoStarThrows) {