mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-07-02 05:35:11 +00:00
323
sdv_services/core/toml_parser/character_reader_utf_8.cpp
Normal file
323
sdv_services/core/toml_parser/character_reader_utf_8.cpp
Normal file
@@ -0,0 +1,323 @@
|
||||
#include "character_reader_utf_8.h"
|
||||
#include "exception.h"
|
||||
|
||||
CCharacterReaderUTF8::CCharacterReaderUTF8() : m_nDataLength{0}, m_nCursor{0}
|
||||
{}
|
||||
|
||||
CCharacterReaderUTF8::CCharacterReaderUTF8(const std::string& rssString) :
|
||||
m_ssString{rssString}, m_nDataLength{rssString.size()}, m_nCursor{0}
|
||||
{
|
||||
CheckForInvalidUTF8Bytes();
|
||||
CheckForInvalidUTF8Sequences();
|
||||
}
|
||||
|
||||
void CCharacterReaderUTF8::Feed(const std::string& rssString)
|
||||
{
|
||||
m_ssString = rssString;
|
||||
m_nDataLength = rssString.size();
|
||||
m_nCursor = 0;
|
||||
|
||||
CheckForInvalidUTF8Bytes();
|
||||
CheckForInvalidUTF8Sequences();
|
||||
}
|
||||
|
||||
void CCharacterReaderUTF8::Reset()
|
||||
{
|
||||
m_ssString.clear();
|
||||
m_nDataLength = 0;
|
||||
m_nCursor = 0;
|
||||
}
|
||||
|
||||
std::string CCharacterReaderUTF8::Peek()
|
||||
{
|
||||
return GetNextCharacter();
|
||||
}
|
||||
|
||||
std::string CCharacterReaderUTF8::Peek(std::size_t n)
|
||||
{
|
||||
if (n < 1)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
size_t offset{0};
|
||||
for (std::size_t i = 0; i < n - 1; ++i)
|
||||
{
|
||||
offset += GetLengthOfNextCharacter(offset);
|
||||
if (m_nDataLength <= m_nCursor + offset)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return GetNextCharacter(offset);
|
||||
}
|
||||
|
||||
std::string CCharacterReaderUTF8::PeekUntil(const std::vector<std::string>& lstCollection)
|
||||
{
|
||||
size_t offset{0};
|
||||
bool found{false};
|
||||
std::string accumulation;
|
||||
while (!found && m_nDataLength > m_nCursor + offset)
|
||||
{
|
||||
std::string character = GetNextCharacter(offset);
|
||||
offset += GetLengthOfNextCharacter(offset);
|
||||
for (const auto& delimiter : lstCollection)
|
||||
{
|
||||
if (delimiter == character)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
accumulation += character;
|
||||
}
|
||||
}
|
||||
return accumulation;
|
||||
}
|
||||
|
||||
std::string CCharacterReaderUTF8::Consume()
|
||||
{
|
||||
if (IsEOF())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
std::string character{GetNextCharacter()};
|
||||
m_nCursor += GetLengthOfNextCharacter();
|
||||
return character;
|
||||
}
|
||||
|
||||
std::string CCharacterReaderUTF8::Consume(std::size_t n)
|
||||
{
|
||||
if (n < 1)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
size_t offset{0};
|
||||
for (uint32_t i = 0; i < n - 1; ++i)
|
||||
{
|
||||
offset += GetLengthOfNextCharacter(offset);
|
||||
if (m_nDataLength < m_nCursor + offset)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
std::string character{GetNextCharacter(offset)};
|
||||
m_nCursor += offset + GetLengthOfNextCharacter(offset);
|
||||
return character;
|
||||
}
|
||||
|
||||
std::string CCharacterReaderUTF8::ConsumeUntil(const std::vector<std::string>& lstCollection)
|
||||
{
|
||||
std::size_t offset{0};
|
||||
bool found{false};
|
||||
std::string accumulation;
|
||||
while (!found && m_nDataLength > m_nCursor + offset)
|
||||
{
|
||||
std::string character = GetNextCharacter(offset);
|
||||
offset += GetLengthOfNextCharacter(offset);
|
||||
for (const auto& delimiter : lstCollection)
|
||||
{
|
||||
if (delimiter == character)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
accumulation += character;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset -= character.size();
|
||||
}
|
||||
}
|
||||
m_nCursor += offset;
|
||||
return accumulation;
|
||||
}
|
||||
|
||||
bool CCharacterReaderUTF8::IsEOF() const
|
||||
{
|
||||
return m_nDataLength < m_nCursor + 1;
|
||||
}
|
||||
|
||||
void CCharacterReaderUTF8::CheckForInvalidUTF8Bytes() const
|
||||
{
|
||||
const unsigned char invalidByteC0{0xC0};
|
||||
const unsigned char invalidByteC1{0xC1};
|
||||
const unsigned char lowerBoundInvalidRegion{0xF5};
|
||||
for (std::size_t i = 0; i < m_ssString.size(); ++i)
|
||||
{
|
||||
unsigned char uc = m_ssString[i];
|
||||
if (uc == invalidByteC0 || uc == invalidByteC1 || uc >= lowerBoundInvalidRegion)
|
||||
{
|
||||
std::stringstream message;
|
||||
message << "Invalid byte " << std::hex << uc << std::dec << " at position " << i << "\n";
|
||||
throw XTOMLParseException(message.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCharacterReaderUTF8::CheckForInvalidUTF8Sequences() const
|
||||
{
|
||||
enum class EState
|
||||
{
|
||||
state_neutral,
|
||||
state_two_byte,
|
||||
state_three_byte,
|
||||
state_four_byte,
|
||||
state_error
|
||||
};
|
||||
EState eCurrentState{EState::state_neutral};
|
||||
uint8_t uiIndex{0};
|
||||
auto fnCheckByteInNeutralState = [&uiIndex, &eCurrentState](unsigned char uc)
|
||||
{
|
||||
if ((uc & m_uiOneByteCheckMask) == m_OneByteCheckValue)
|
||||
{
|
||||
eCurrentState = EState::state_neutral;
|
||||
uiIndex = 0;
|
||||
}
|
||||
else if ((uc & m_uiFourByteCheckMask) == m_uiFourByteCheckValue)
|
||||
{
|
||||
eCurrentState = EState::state_four_byte;
|
||||
uiIndex = 1;
|
||||
}
|
||||
else if ((uc & m_uiThreeByteCheckMask) == m_uiThreeByteCheckValue)
|
||||
{
|
||||
eCurrentState = EState::state_three_byte;
|
||||
uiIndex = 1;
|
||||
}
|
||||
else if ((uc & m_uiTwoByteCheckMask) == m_uiTwoByteCheckValue)
|
||||
{
|
||||
eCurrentState = EState::state_two_byte;
|
||||
uiIndex = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
eCurrentState = EState::state_error;
|
||||
}
|
||||
};
|
||||
auto fnCheckByteInTwoByteState = [&uiIndex, &eCurrentState](unsigned char uc)
|
||||
{
|
||||
if ((uc & m_uiFollowByteCheckMask) == m_uiFollowByteValue)
|
||||
{
|
||||
uiIndex = 0;
|
||||
eCurrentState = EState::state_neutral;
|
||||
}
|
||||
else
|
||||
{
|
||||
eCurrentState = EState::state_error;
|
||||
}
|
||||
};
|
||||
auto fnCheckByteInThreeByteState = [&uiIndex, &eCurrentState](unsigned char uc)
|
||||
{
|
||||
if (uiIndex == 1 && (uc & m_uiFollowByteCheckMask) == m_uiFollowByteValue)
|
||||
{
|
||||
uiIndex = 2;
|
||||
}
|
||||
else if (uiIndex == 2 && (uc & m_uiFollowByteCheckMask) == m_uiFollowByteValue)
|
||||
{
|
||||
uiIndex = 0;
|
||||
eCurrentState = EState::state_neutral;
|
||||
}
|
||||
else
|
||||
{
|
||||
eCurrentState = EState::state_error;
|
||||
}
|
||||
};
|
||||
auto fnCheckByteInFourByteState = [&uiIndex, &eCurrentState](unsigned char uc)
|
||||
{
|
||||
if (uiIndex <= 2 && (uc & m_uiFollowByteCheckMask) == m_uiFollowByteValue)
|
||||
{
|
||||
++uiIndex;
|
||||
}
|
||||
else if (uiIndex == 3 && (uc & m_uiFollowByteCheckMask) == m_uiFollowByteValue)
|
||||
{
|
||||
uiIndex = 0;
|
||||
eCurrentState = EState::state_neutral;
|
||||
}
|
||||
else
|
||||
{
|
||||
eCurrentState = EState::state_error;
|
||||
}
|
||||
};
|
||||
for (std::size_t i = 0; i < m_ssString.size(); ++i)
|
||||
{
|
||||
uint8_t uiCurrentByte = m_ssString[i];
|
||||
switch (eCurrentState)
|
||||
{
|
||||
case EState::state_neutral:
|
||||
fnCheckByteInNeutralState(uiCurrentByte);
|
||||
break;
|
||||
case EState::state_two_byte:
|
||||
fnCheckByteInTwoByteState(uiCurrentByte);
|
||||
break;
|
||||
case EState::state_three_byte:
|
||||
fnCheckByteInThreeByteState(uiCurrentByte);
|
||||
break;
|
||||
case EState::state_four_byte:
|
||||
fnCheckByteInFourByteState(uiCurrentByte);
|
||||
break;
|
||||
default:
|
||||
std::stringstream sstreamMessage;
|
||||
sstreamMessage << "Invalid character with byte " << std::hex << m_ssString[i - 1] << std::dec << "("
|
||||
<< static_cast<int32_t>(m_ssString[i - 1]) << ") at index " << i - 1 << "\n";
|
||||
throw XTOMLParseException(sstreamMessage.str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (eCurrentState != EState::state_neutral)
|
||||
{
|
||||
std::stringstream sstreamMessage;
|
||||
sstreamMessage << "Unfinished character at the end of file\n";
|
||||
throw XTOMLParseException(sstreamMessage.str());
|
||||
}
|
||||
}
|
||||
|
||||
std::string CCharacterReaderUTF8::GetNextCharacter()
|
||||
{
|
||||
if (IsEOF())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return {m_ssString, m_nCursor, GetLengthOfNextCharacter()};
|
||||
}
|
||||
|
||||
std::string CCharacterReaderUTF8::GetNextCharacter(std::size_t offset)
|
||||
{
|
||||
return {m_ssString, m_nCursor + offset, GetLengthOfNextCharacter(offset)};
|
||||
}
|
||||
|
||||
size_t CCharacterReaderUTF8::GetLengthOfNextCharacter() const
|
||||
{
|
||||
return GetLengthOfNextCharacter(0);
|
||||
}
|
||||
|
||||
size_t CCharacterReaderUTF8::GetLengthOfNextCharacter(std::size_t offset) const
|
||||
{
|
||||
uint8_t ui = m_ssString[m_nCursor + offset];
|
||||
int32_t ret;
|
||||
if ((ui & m_uiOneByteCheckMask) == m_OneByteCheckValue)
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
else if ((ui & m_uiFourByteCheckMask) == m_uiFourByteCheckValue)
|
||||
{
|
||||
ret = 4;
|
||||
}
|
||||
else if ((ui & m_uiThreeByteCheckMask) == m_uiThreeByteCheckValue)
|
||||
{
|
||||
ret = 3;
|
||||
}
|
||||
else if ((ui & m_uiTwoByteCheckMask) == m_uiTwoByteCheckValue)
|
||||
{
|
||||
ret = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream sstreamMessage;
|
||||
sstreamMessage << "Invalid character sequence with byte " << std::hex << ui << std::dec
|
||||
<< " as start byte\n";
|
||||
throw XTOMLParseException(sstreamMessage.str());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
127
sdv_services/core/toml_parser/character_reader_utf_8.h
Normal file
127
sdv_services/core/toml_parser/character_reader_utf_8.h
Normal file
@@ -0,0 +1,127 @@
|
||||
#ifndef CHARACTER_READER_UTF_8_H
|
||||
#define CHARACTER_READER_UTF_8_H
|
||||
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* @brief Reads a given input string, interprets bytes as UTF-8 and returns UTF-8 characters or strings in order on
|
||||
* demand
|
||||
*/
|
||||
class CCharacterReaderUTF8
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Standard constructor for empty character reader
|
||||
*/
|
||||
CCharacterReaderUTF8();
|
||||
|
||||
/**
|
||||
* @brief Constructs a character reader from a given string
|
||||
* @param[in] rssString UTF-8 input string.
|
||||
* @throw InvalidCharacterException Throws an InvalidCharacterException if the input contains invalid UTF-8 characters
|
||||
* @throw InvalidByteException Throws an InvalidByteException if the input contains for UTF-8 invalid bytes
|
||||
*/
|
||||
CCharacterReaderUTF8(const std::string& rssString);
|
||||
|
||||
/**
|
||||
* @brief Feed the character reader from the given string.
|
||||
* @param[in] rssString UTF-8 input string.
|
||||
*/
|
||||
void Feed(const std::string& rssString);
|
||||
|
||||
/**
|
||||
* @brief Reset the character reader content.
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* @brief Gets the next UTF-8 character without advancing the cursor
|
||||
* @return Returns the next UTF-8 character after the current cursor or an empty string if the cursor is at the
|
||||
* end
|
||||
*/
|
||||
std::string Peek();
|
||||
|
||||
/**
|
||||
* @brief Gets the next n-th UTF-8 character without advancing the cursor
|
||||
* @param[in] n Step size
|
||||
* @return Returns the n-th UTF-8 character after the current cursor or an empty string if n<1 or it would read
|
||||
* after the last character
|
||||
*/
|
||||
std::string Peek(std::size_t n);
|
||||
|
||||
/**
|
||||
* @brief Gets all upcoming UTF-8 characters until a terminating character without advancing the cursor
|
||||
* @param[in] lstCollection A collection of terminating characters
|
||||
* @return Returns a string of UTF-8 characters until (excluding) the first occurrence of one of the given
|
||||
* characters
|
||||
*/
|
||||
std::string PeekUntil(const std::vector<std::string>& lstCollection);
|
||||
|
||||
/**
|
||||
* @brief Gets the next UTF-8 character and advancing the cursor by one
|
||||
* @return Returns the next UTF-8 character after the current cursor or an empty string if the cursor is at the
|
||||
* end
|
||||
*/
|
||||
std::string Consume();
|
||||
|
||||
/**
|
||||
* @brief Gets the next n-th UTF-8 character and advancing the cursor by n
|
||||
* @param[in] n Step size
|
||||
* @return Returns the n-th UTF-8 character after the current cursor or an empty string if n<1 or it would read
|
||||
* after the last character
|
||||
*/
|
||||
std::string Consume(std::size_t n);
|
||||
|
||||
/**
|
||||
* @brief Gets all upcoming UTF-8 characters until a terminating character and advancing the cursor by the number
|
||||
* of characters in the returned string
|
||||
* @param[in] lstCollection A collection of terminating characters
|
||||
* @return Returns a string of UTF-8 characters until excludingg) the first occurrence of one of the given
|
||||
* characters
|
||||
*/
|
||||
std::string ConsumeUntil(const std::vector<std::string>& lstCollection);
|
||||
|
||||
/**
|
||||
* @brief Checks if the cursor is at the end of the data to read
|
||||
* @return Returns true if the cursor is at the end of the readable data, false otherwise
|
||||
*/
|
||||
bool IsEOF() const;
|
||||
|
||||
private:
|
||||
void CheckForInvalidUTF8Bytes() const;
|
||||
|
||||
void CheckForInvalidUTF8Sequences() const;
|
||||
|
||||
std::string GetNextCharacter();
|
||||
|
||||
std::string GetNextCharacter(std::size_t offset);
|
||||
|
||||
size_t GetLengthOfNextCharacter() const;
|
||||
|
||||
size_t GetLengthOfNextCharacter(std::size_t offset) const;
|
||||
|
||||
static const uint8_t m_uiOneByteCheckMask{0b10000000}; //!< Checkmask for 1-Byte UTF-8 characters
|
||||
static const uint8_t m_OneByteCheckValue{0b00000000}; //!< Value of a 1-Byte UTF-8 character
|
||||
//!< after being or-ed with the checkmask
|
||||
static const uint8_t m_uiFollowByteCheckMask{0b11000000}; //!< Checkmask for followbyte of a multi-Byte UTF-8 character
|
||||
static const uint8_t m_uiFollowByteValue{0b10000000}; //!< Value of a followbyte of a multi-Byte UTF-8 character
|
||||
//!< after being or-ed with the checkmask
|
||||
static const uint8_t m_uiTwoByteCheckMask{0b11100000}; //!< Checkmask for startbyte of 2-Byte UTF-8 characters
|
||||
static const uint8_t m_uiTwoByteCheckValue{0b11000000}; //!< Value of a startbyte of a 2-Byte UTF-8 character
|
||||
//!< after being or-ed with the checkmask
|
||||
static const uint8_t m_uiThreeByteCheckMask{0b11110000}; //!< Checkmask for startbyte of 3-Byte UTF-8 characters
|
||||
static const uint8_t m_uiThreeByteCheckValue{0b11100000}; //!< Value of a startbyte of a 3-Byte UTF-8 character
|
||||
//!< after being or-ed with the checkmask
|
||||
static const uint8_t m_uiFourByteCheckMask{0b11111000}; //!< Checkmask for startbyte of 4-Byte UTF-8 characters
|
||||
static const uint8_t m_uiFourByteCheckValue{0b11110000}; //!< Value of a startbyte of a 4-Byte UTF-8 character
|
||||
//!< after being or-ed with the checkmask
|
||||
|
||||
std::string m_ssString;
|
||||
std::size_t m_nDataLength;
|
||||
std::size_t m_nCursor;
|
||||
};
|
||||
|
||||
#endif // CHARACTER_READER_UTF_8_H
|
||||
20
sdv_services/core/toml_parser/exception.h
Normal file
20
sdv_services/core/toml_parser/exception.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef CONFIG_EXCEPTION_H
|
||||
#define CONFIG_EXCEPTION_H
|
||||
|
||||
#include <interfaces/toml.h>
|
||||
|
||||
except XTOMLParseException : public sdv::toml::XTOMLParseException
|
||||
{
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
XTOMLParseException(const std::string& rss) { ssMessage = rss; };
|
||||
|
||||
/**
|
||||
* @brief Return the explanatory string.
|
||||
* @return The descriptive string.
|
||||
*/
|
||||
virtual const char* what() const noexcept override { return ssMessage.c_str(); }
|
||||
};
|
||||
|
||||
#endif // !defined CONFIG_EXCEPTION_H
|
||||
1022
sdv_services/core/toml_parser/lexer_toml.cpp
Normal file
1022
sdv_services/core/toml_parser/lexer_toml.cpp
Normal file
File diff suppressed because it is too large
Load Diff
226
sdv_services/core/toml_parser/lexer_toml.h
Normal file
226
sdv_services/core/toml_parser/lexer_toml.h
Normal file
@@ -0,0 +1,226 @@
|
||||
#ifndef LEXER_TOML_H
|
||||
#define LEXER_TOML_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <stack>
|
||||
#include "character_reader_utf_8.h"
|
||||
|
||||
/**
|
||||
* @brief Tokenizes the output of a character reader in regard of the TOML format and returns tokens in order on demand
|
||||
*/
|
||||
class CLexerTOML
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Enum for all possible token categories
|
||||
*/
|
||||
enum class ETokenCategory : uint8_t
|
||||
{
|
||||
token_none, ///< Default
|
||||
token_syntax_assignment, ///< '='
|
||||
token_syntax_array_open, ///< '[' after '='
|
||||
token_syntax_array_close, ///< ']' after an array open
|
||||
token_syntax_table_open, ///< '['
|
||||
token_syntax_table_close, ///< ']'
|
||||
token_syntax_table_array_open, ///< '[['
|
||||
token_syntax_table_array_close, ///< ']]'
|
||||
token_syntax_inline_table_open, ///< '{'
|
||||
token_syntax_inline_table_close, ///< '}'
|
||||
token_syntax_comma, ///< ','
|
||||
token_syntax_dot, ///< '.'
|
||||
token_syntax_new_line, ///< Line break
|
||||
token_key, ///< Key of a Key-Value-Pair
|
||||
token_string, ///< A string for a Value of a Key-Value-Pair or Array
|
||||
token_integer, ///< An integer for a Value of a Key-Value-Pair or Array
|
||||
token_float, ///< A floating point number for a Value of a Key-Value-Pair or Array
|
||||
token_boolean, ///< A bool for a Value of a Key-Value-Pair or Array
|
||||
token_time_local, ///< Unused for now
|
||||
token_date_time_offset, ///< Unused for now
|
||||
token_date_time_local, ///< Unused for now
|
||||
token_date_local, ///< Unused for now
|
||||
token_eof, ///< End of File Token; may only be at the end of the token array
|
||||
token_error, ///< Error token containing an error message; further lexing is not affected
|
||||
token_empty, ///< Empty token for trying to read out of bounds
|
||||
token_terminated, ///< Terminated token containing an error message; further lexing is terminated
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Contains lexed information for the parser
|
||||
*/
|
||||
struct SToken
|
||||
{
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
SToken() = default;
|
||||
|
||||
/**
|
||||
* @brief Constructs a new Token object with a given category
|
||||
* @param[in] category The initial token category value for the token to be constructed
|
||||
*/
|
||||
explicit SToken(ETokenCategory category) : eCategory(category)
|
||||
{}
|
||||
|
||||
std::string ssContentString; ///< Token string content
|
||||
int64_t iContentInteger{}; ///< Token integer content
|
||||
double dContentFloatingpoint{}; ///< Token floatingpoint content
|
||||
bool bContentBoolean{}; ///< Token boolean content
|
||||
ETokenCategory eCategory{ETokenCategory::token_none}; ///< Token category
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
CLexerTOML() = default;
|
||||
|
||||
/**
|
||||
* @brief Constructs a new LexerTOML object with given input data that will be lexed
|
||||
* @param[in] rssString The UTF-8 encoded content of a TOML source
|
||||
*/
|
||||
CLexerTOML(const std::string& rssString);
|
||||
|
||||
/**
|
||||
* @brief Feed the lexer with the given string.
|
||||
* @param[in] rssString UTF-8 input string.
|
||||
*/
|
||||
void Feed(const std::string& rssString);
|
||||
|
||||
/**
|
||||
* @brief Reset the lexer content.
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* @brief Gets the next token after the current cursor position without advancing the cursor
|
||||
* @return Returns the next token after the current cursor position or a End-of-File-Token if there are no
|
||||
* tokens
|
||||
*/
|
||||
SToken Peek() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the next token after the current cursor position and advancing the cursor by one
|
||||
* @return Returns the next token after the current cursor position or a End-of-File-Token if there are no
|
||||
* tokens
|
||||
*/
|
||||
SToken Consume();
|
||||
|
||||
/**
|
||||
* @brief Gets the n-th token after the current cursor without advancing the cursor
|
||||
* @param[in] n Step size
|
||||
* @return Returns the n-th token after the current cursor position or and empty token if n<1 or the end-token
|
||||
* if a step of n would read a position after the end-token
|
||||
*/
|
||||
SToken Peek(int32_t n);
|
||||
|
||||
/**
|
||||
* @brief Gets the n-th token after the current cursor and advancing the cursor by n
|
||||
* @param[in] n Step size
|
||||
* @return Returns the n-th token after the current cursor position or and empty token if n<1 or the end-token
|
||||
* if a step of n would read a position after the end-token
|
||||
*/
|
||||
SToken Consume(int32_t n);
|
||||
|
||||
/**
|
||||
* @brief Checks if the end-token was consumed
|
||||
* @return Returns true if the end-token was consumed by Consume() or Consume(n) or if there are no tokens;
|
||||
* false otherwise
|
||||
*/
|
||||
bool IsEnd() const;
|
||||
|
||||
private:
|
||||
void GenerateTokens();
|
||||
|
||||
bool IsBasicQuotedKey();
|
||||
|
||||
void ReadBasicQuotedKey();
|
||||
|
||||
bool IsLiteralQuotedKey();
|
||||
|
||||
void ReadLiteralQuotedKey();
|
||||
|
||||
bool IsBareKey();
|
||||
|
||||
void ReadBareKey();
|
||||
|
||||
bool IsBasicString();
|
||||
|
||||
void ReadBasicString();
|
||||
|
||||
bool IsBasicMultilineString();
|
||||
|
||||
void ReadBasicMultilineString();
|
||||
|
||||
bool IsLiteralString();
|
||||
|
||||
void ReadLiteralString();
|
||||
|
||||
bool IsLiteralMultilineString();
|
||||
|
||||
void ReadLiteralMultilineString();
|
||||
|
||||
bool IsInteger();
|
||||
|
||||
void ReadInteger();
|
||||
|
||||
bool IsFloat();
|
||||
|
||||
void ReadFloat();
|
||||
|
||||
bool IsBool();
|
||||
|
||||
void ReadBool();
|
||||
|
||||
bool IsWhitespace();
|
||||
|
||||
void ReadWhitespace();
|
||||
|
||||
bool IsSyntaxElement();
|
||||
|
||||
void ReadSyntaxElement();
|
||||
|
||||
bool IsComment();
|
||||
|
||||
void ReadComment();
|
||||
|
||||
void ReadUnknownSequence();
|
||||
|
||||
std::string Unescape();
|
||||
|
||||
std::string Unicode4DigitToUTF8();
|
||||
|
||||
std::string Unicode8DigitToUTF8();
|
||||
|
||||
std::string UnicodeToUTF8(uint8_t numCharacters);
|
||||
|
||||
static uint32_t HexToDecimal(const char character);
|
||||
|
||||
static uint32_t DecimalToDecimal(const char character);
|
||||
|
||||
static uint32_t OctalToDecimal(const char character);
|
||||
|
||||
static uint32_t BinaryToDecimal(const char character);
|
||||
|
||||
CCharacterReaderUTF8 m_reader;
|
||||
std::vector<SToken> m_vecTokens;
|
||||
std::size_t m_nCursor{0};
|
||||
|
||||
/**
|
||||
* @brief Enum for differentiating between keys and values that are potentially indifferent like '"value" =
|
||||
* "value"'
|
||||
*/
|
||||
enum class EExpectation
|
||||
{
|
||||
expect_key, ///< A key is expected over a value
|
||||
expect_value, ///< A value is expected over a key
|
||||
expect_value_once, ///< A value is expected over a key once
|
||||
};
|
||||
std::stack<EExpectation> m_stackExpectations; ///< Tracking of key or value expectations in nested structures
|
||||
// int32_t m_LineCount{0};
|
||||
|
||||
const std::vector<std::string> m_vecKeyDelimiters{
|
||||
"\n", "\t", "\r", " ", "", ".", "=", "]"}; ///< Characters that delimit a key
|
||||
const std::vector<std::string> m_vecValueDelimiters{
|
||||
"\n", "\t", "\r", " ", ",", "", "]", "}"}; ///< Characters that delimit a value
|
||||
};
|
||||
|
||||
#endif // LEXER_TOML_H
|
||||
760
sdv_services/core/toml_parser/parser_node_toml.cpp
Normal file
760
sdv_services/core/toml_parser/parser_node_toml.cpp
Normal file
@@ -0,0 +1,760 @@
|
||||
#include <algorithm>
|
||||
#include "parser_node_toml.h"
|
||||
#include "exception.h"
|
||||
#include <sstream>
|
||||
|
||||
size_t FindFirst(const std::string& rss, const std::string& rssSeparator /*= "."*/)
|
||||
{
|
||||
enum class EType {normal, single_quoted_string, double_quoted_string} eType = EType::normal;
|
||||
size_t nPos = 0;
|
||||
while (nPos < rss.size())
|
||||
{
|
||||
switch (rss[nPos])
|
||||
{
|
||||
case '\'':
|
||||
if (eType == EType::normal)
|
||||
eType = EType::single_quoted_string;
|
||||
else if (eType == EType::single_quoted_string)
|
||||
eType = EType::normal;
|
||||
break;
|
||||
case '\"':
|
||||
if (eType == EType::normal)
|
||||
eType = EType::double_quoted_string;
|
||||
else if (eType == EType::double_quoted_string)
|
||||
eType = EType::normal;
|
||||
break;
|
||||
case '\\':
|
||||
nPos++;
|
||||
break;
|
||||
default:
|
||||
if (eType == EType::normal && rssSeparator.find(rss[nPos]) != std::string::npos)
|
||||
return nPos;
|
||||
break;
|
||||
}
|
||||
nPos++;
|
||||
}
|
||||
return nPos >= rss.size() ? std::string::npos : nPos;
|
||||
}
|
||||
|
||||
size_t FindLast(const std::string& rss, const std::string& rssSeparator /*= "."*/)
|
||||
{
|
||||
enum class EType {normal, single_quoted_string, double_quoted_string} eType = EType::normal;
|
||||
size_t nPos = rss.size();
|
||||
while (nPos)
|
||||
{
|
||||
nPos--;
|
||||
bool bEscaped = nPos && rss[nPos - 1] == '\\';
|
||||
switch (rss[nPos])
|
||||
{
|
||||
case '\'':
|
||||
if (bEscaped)
|
||||
nPos--;
|
||||
else if (eType == EType::normal)
|
||||
eType = EType::single_quoted_string;
|
||||
else if (eType == EType::single_quoted_string)
|
||||
eType = EType::normal;
|
||||
break;
|
||||
case '\"':
|
||||
if (bEscaped)
|
||||
nPos--;
|
||||
else if (eType == EType::normal)
|
||||
eType = EType::double_quoted_string;
|
||||
else if (eType == EType::double_quoted_string)
|
||||
eType = EType::normal;
|
||||
break;
|
||||
default:
|
||||
if (eType == EType::normal && rssSeparator.find(rss[nPos]) != std::string::npos)
|
||||
return nPos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return std::string::npos;
|
||||
}
|
||||
|
||||
bool CompareEqual(const std::string& rss1, const std::string& rss2)
|
||||
{
|
||||
size_t nStart1 = 0, nStop1 = rss1.size();
|
||||
if (rss1.size() && rss1.find_first_of("\"\'") == 0 && rss1.find_last_of("\"\'") == (rss1.size() - 1))
|
||||
{
|
||||
nStart1++;
|
||||
nStop1--;
|
||||
}
|
||||
size_t nStart2 = 0, nStop2 = rss2.size();
|
||||
if (rss2.size() && rss2.find_first_of("\"\'") == 0 && rss2.find_last_of("\"\'") == (rss2.size() - 1))
|
||||
{
|
||||
nStart2++;
|
||||
nStop2--;
|
||||
}
|
||||
|
||||
if (nStop1 - nStart1 != nStop2 - nStart2) return false;
|
||||
for (size_t n = 0; n < (nStop1 - nStart1); n++)
|
||||
{
|
||||
if (rss1[nStart1 + n] != rss2[nStart2 + n])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string EscapeString(const std::string& rssString, const char cQuoteType /*= '\"'*/)
|
||||
{
|
||||
// Iterate through the string
|
||||
std::stringstream sstream;
|
||||
size_t nPos = 0;
|
||||
uint32_t uiUTFChar = 0;
|
||||
while (nPos < rssString.size())
|
||||
{
|
||||
uint8_t uiChar = static_cast<uint8_t>(rssString[nPos]);
|
||||
switch (uiChar)
|
||||
{
|
||||
case '\a': sstream << "\\a"; break;
|
||||
case '\b': sstream << "\\b"; break;
|
||||
case '\f': sstream << "\\f"; break;
|
||||
case '\n': sstream << "\\n"; break;
|
||||
case '\r': sstream << "\\r"; break;
|
||||
case '\t': sstream << "\\t"; break;
|
||||
case '\v': sstream << "\\v"; break;
|
||||
case '\\': sstream << "\\\\"; break;
|
||||
case '\'': if (static_cast<uint8_t>(cQuoteType) == uiChar) sstream << "\\"; sstream << "\'"; break;
|
||||
case '\"': if (static_cast<uint8_t>(cQuoteType) == uiChar) sstream << "\\"; sstream << "\""; break;
|
||||
default:
|
||||
if (uiChar >= 0x20 && uiChar < 0x7f)
|
||||
{
|
||||
// Standard ASCII
|
||||
sstream << static_cast<char>(uiChar);
|
||||
break;
|
||||
}
|
||||
else if (uiChar <= 0x80) // One byte UTF-8
|
||||
uiUTFChar = static_cast<uint32_t>(uiChar);
|
||||
else if (uiChar <= 0xDF) // Two bytes UTF-8
|
||||
{
|
||||
uiUTFChar = static_cast<size_t>(uiChar & 0b00011111) << 6;
|
||||
|
||||
// Expecting the next character to be between 0x80 and 0xBF
|
||||
nPos++;
|
||||
if (nPos >= rssString.size()) break;
|
||||
uiUTFChar |= static_cast<size_t>(rssString[nPos] & 0b00111111);
|
||||
}
|
||||
else if (uiChar <= 0xEF) // Three bytes UTF-8
|
||||
{
|
||||
uiUTFChar = static_cast<size_t>(uiChar & 0b00001111) << 6;
|
||||
|
||||
// Expecting the next character to be between 0x80 and 0xBF
|
||||
nPos++;
|
||||
if (nPos >= rssString.size()) break;
|
||||
uiUTFChar |= static_cast<size_t>(rssString[nPos] & 0b00111111);
|
||||
uiUTFChar <<= 6;
|
||||
|
||||
// Expecting the next character to be between 0x80 and 0xBF
|
||||
nPos++;
|
||||
if (nPos >= rssString.size()) break;
|
||||
uiUTFChar |= static_cast<size_t>(rssString[nPos] & 0b00111111);
|
||||
}
|
||||
else if (uiChar <= 0xF7) // Four bytes UTF-8
|
||||
{
|
||||
uiUTFChar = static_cast<size_t>(uiChar & 0b00000111) << 6;
|
||||
|
||||
// Expecting the next character to be between 0x80 and 0xBF
|
||||
nPos++;
|
||||
if (nPos >= rssString.size()) break;
|
||||
uiUTFChar |= static_cast<size_t>(rssString[nPos] & 0b00111111);
|
||||
uiUTFChar <<= 6;
|
||||
|
||||
// Expecting the next character to be between 0x80 and 0xBF
|
||||
nPos++;
|
||||
if (nPos >= rssString.size()) break;
|
||||
uiUTFChar |= static_cast<size_t>(rssString[nPos] & 0b00111111);
|
||||
uiUTFChar <<= 6;
|
||||
|
||||
// Expecting the next character to be between 0x80 and 0xBF
|
||||
nPos++;
|
||||
if (nPos >= rssString.size()) break;
|
||||
uiUTFChar |= static_cast<size_t>(rssString[nPos] & 0b00111111);
|
||||
}
|
||||
|
||||
// Stream the UTF character
|
||||
if (uiUTFChar <= 0xFFFF)
|
||||
sstream << "\\u" << std::uppercase << std::hex << std::setfill('0') << std::setw(4) << uiUTFChar;
|
||||
else
|
||||
sstream << "\\U" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << uiUTFChar;
|
||||
break;
|
||||
}
|
||||
nPos++;
|
||||
}
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
|
||||
CNode::CNode(const std::string& rssName) : m_ssName(rssName)
|
||||
{}
|
||||
|
||||
CNode::~CNode()
|
||||
{}
|
||||
|
||||
sdv::u8string CNode::GetName() const
|
||||
{
|
||||
return m_ssName;
|
||||
}
|
||||
|
||||
sdv::any_t CNode::GetValue() const
|
||||
{
|
||||
return sdv::any_t();
|
||||
}
|
||||
|
||||
sdv::u8string CNode::GetTOML() const
|
||||
{
|
||||
std::string ssLastTable;
|
||||
std::string ssParent;
|
||||
return CreateTOMLText(ssParent, ssLastTable, true, false, true, true);
|
||||
}
|
||||
|
||||
std::shared_ptr<const CArray> CNode::GetArray() const
|
||||
{
|
||||
if (!dynamic_cast<const CArray*>(this)) return {};
|
||||
return std::static_pointer_cast<const CArray>(shared_from_this());
|
||||
}
|
||||
|
||||
std::shared_ptr<CArray> CNode::GetArray()
|
||||
{
|
||||
if (!dynamic_cast<CArray*>(this)) return {};
|
||||
return std::static_pointer_cast<CArray>(shared_from_this());
|
||||
}
|
||||
|
||||
std::shared_ptr<const CTable> CNode::GetTable() const
|
||||
{
|
||||
if (!dynamic_cast<const CTable*>(this)) return {};
|
||||
return std::static_pointer_cast<const CTable>(shared_from_this());
|
||||
}
|
||||
|
||||
std::shared_ptr<CTable> CNode::GetTable()
|
||||
{
|
||||
if (!dynamic_cast<const CTable*>(this)) return {};
|
||||
return std::static_pointer_cast<CTable>(shared_from_this());
|
||||
}
|
||||
|
||||
std::weak_ptr<const CNode> CNode::GetParent() const
|
||||
{
|
||||
return m_ptrParent;
|
||||
}
|
||||
|
||||
void CNode::SetParent(const std::shared_ptr<CNode>& rptrParent)
|
||||
{
|
||||
m_ptrParent = rptrParent;
|
||||
}
|
||||
|
||||
std::shared_ptr<CNode> CNode::Find(const std::string& /*rssPath*/) const
|
||||
{
|
||||
return std::shared_ptr<CNode>();
|
||||
}
|
||||
|
||||
std::shared_ptr<CNode> CNode::GetDirect(const std::string& /*rssPath*/) const
|
||||
{
|
||||
// The CNode implementation doesn't have any children. Therefore there is nothing to get.
|
||||
return std::shared_ptr<CNode>();
|
||||
}
|
||||
|
||||
std::string CNode::CreateTOMLText(const std::string& rssParent /*= std::string()*/) const
|
||||
{
|
||||
std::string ssLastTable;
|
||||
return CreateTOMLText(rssParent, ssLastTable);
|
||||
}
|
||||
|
||||
void CNode::Add(const std::string& rssPath, const std::shared_ptr<CNode>& /*rptrNode*/, bool /*bDefinedExplicitly = true*/)
|
||||
{
|
||||
throw XTOMLParseException(("Not allowed to add '" + rssPath + "'; parent node is final").c_str());
|
||||
}
|
||||
|
||||
CBooleanNode::CBooleanNode(const std::string& rssName, bool bVal) : CNode(rssName), m_bVal(bVal)
|
||||
{}
|
||||
|
||||
sdv::toml::ENodeType CBooleanNode::GetType() const
|
||||
{
|
||||
return sdv::toml::ENodeType::node_boolean;
|
||||
}
|
||||
|
||||
sdv::any_t CBooleanNode::GetValue() const
|
||||
{
|
||||
return sdv::any_t(m_bVal);
|
||||
}
|
||||
|
||||
std::string CBooleanNode::CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst, bool bEmbedded,
|
||||
bool bAssignment, bool /*bRoot*/) const
|
||||
{
|
||||
std::stringstream sstreamEntry;
|
||||
|
||||
// Do we need to start a table?
|
||||
if (!bEmbedded && bFirst && bAssignment && rssParent != rssLastPrintedTable)
|
||||
{
|
||||
sstreamEntry << std::endl << "[" << rssParent << "]" << std::endl;
|
||||
rssLastPrintedTable = rssParent;
|
||||
}
|
||||
|
||||
if (bEmbedded && !bFirst) // 2nd or higher array entry
|
||||
sstreamEntry << ", ";
|
||||
if (!bEmbedded || bAssignment) // Not an array entry
|
||||
sstreamEntry << GetName() << " = ";
|
||||
sstreamEntry << (m_bVal ? "true" : "false");
|
||||
if (!bEmbedded) // Not an array entry
|
||||
sstreamEntry << std::endl;
|
||||
|
||||
return sstreamEntry.str();
|
||||
}
|
||||
|
||||
CIntegerNode::CIntegerNode(const std::string& rssName, int64_t iVal) : CNode(rssName), m_iVal(iVal)
|
||||
{}
|
||||
|
||||
sdv::toml::ENodeType CIntegerNode::GetType() const
|
||||
{
|
||||
return sdv::toml::ENodeType::node_integer;
|
||||
}
|
||||
|
||||
sdv::any_t CIntegerNode::GetValue() const
|
||||
{
|
||||
return sdv::any_t(m_iVal);
|
||||
}
|
||||
|
||||
std::string CIntegerNode::CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst, bool bEmbedded,
|
||||
bool bAssignment, bool /*bRoot*/) const
|
||||
{
|
||||
std::stringstream sstreamEntry;
|
||||
|
||||
// Do we need to start a table?
|
||||
if (!bEmbedded && bFirst && bAssignment && rssParent != rssLastPrintedTable)
|
||||
{
|
||||
sstreamEntry << std::endl << "[" << rssParent << "]" << std::endl;
|
||||
rssLastPrintedTable = rssParent;
|
||||
}
|
||||
|
||||
if (bEmbedded && !bFirst) // 2nd or higher array entry
|
||||
sstreamEntry << ", ";
|
||||
if (!bEmbedded || bAssignment) // Not an array entry
|
||||
sstreamEntry << GetName() << " = ";
|
||||
sstreamEntry << m_iVal;
|
||||
if (!bEmbedded) // Not an array entry
|
||||
sstreamEntry << std::endl;
|
||||
|
||||
return sstreamEntry.str();
|
||||
}
|
||||
|
||||
CFloatingPointNode::CFloatingPointNode(const std::string& rssName, double dVal) : CNode(rssName), m_dVal(dVal)
|
||||
{}
|
||||
|
||||
sdv::toml::ENodeType CFloatingPointNode::GetType() const
|
||||
{
|
||||
return sdv::toml::ENodeType::node_floating_point;
|
||||
}
|
||||
|
||||
sdv::any_t CFloatingPointNode::GetValue() const
|
||||
{
|
||||
return sdv::any_t(m_dVal);
|
||||
}
|
||||
|
||||
std::string CFloatingPointNode::CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst,
|
||||
bool bEmbedded, bool bAssignment, bool /*bRoot*/) const
|
||||
{
|
||||
std::stringstream sstreamEntry;
|
||||
|
||||
// Do we need to start a table?
|
||||
if (!bEmbedded && bFirst && bAssignment && rssParent != rssLastPrintedTable)
|
||||
{
|
||||
sstreamEntry << std::endl << "[" << rssParent << "]" << std::endl;
|
||||
rssLastPrintedTable = rssParent;
|
||||
}
|
||||
|
||||
if (bEmbedded && !bFirst) // 2nd or higher array entry
|
||||
sstreamEntry << ", ";
|
||||
if (!bEmbedded || bAssignment) // Not an array entry
|
||||
sstreamEntry << GetName() << " = ";
|
||||
sstreamEntry << std::setprecision(15) << std::defaultfloat << m_dVal;
|
||||
if (!bEmbedded) // Not an array entry
|
||||
sstreamEntry << std::endl;
|
||||
|
||||
return sstreamEntry.str();
|
||||
}
|
||||
|
||||
CStringNode::CStringNode(const std::string& rssName, const std::string& rssVal) : CNode(rssName), m_ssVal(rssVal)
|
||||
{}
|
||||
|
||||
sdv::toml::ENodeType CStringNode::GetType() const
|
||||
{
|
||||
return sdv::toml::ENodeType::node_string;
|
||||
}
|
||||
|
||||
sdv::any_t CStringNode::GetValue() const
|
||||
{
|
||||
return sdv::any_t(m_ssVal);
|
||||
}
|
||||
|
||||
std::string CStringNode::CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst, bool bEmbedded,
|
||||
bool bAssignment, bool /*bRoot*/) const
|
||||
{
|
||||
std::stringstream sstreamEntry;
|
||||
|
||||
// Do we need to start a table?
|
||||
if (!bEmbedded && bFirst && bAssignment && rssParent != rssLastPrintedTable)
|
||||
{
|
||||
sstreamEntry << std::endl << "[" << rssParent << "]" << std::endl;
|
||||
rssLastPrintedTable = rssParent;
|
||||
}
|
||||
|
||||
if (bEmbedded && !bFirst) // 2nd or higher array entry
|
||||
sstreamEntry << ", ";
|
||||
if (!bEmbedded || bAssignment) // Not an array entry
|
||||
sstreamEntry << GetName() << " = ";
|
||||
sstreamEntry << "\"" << EscapeString(m_ssVal) << "\"";
|
||||
if (!bEmbedded) // Not an array entry
|
||||
sstreamEntry << std::endl;
|
||||
|
||||
return sstreamEntry.str();
|
||||
}
|
||||
|
||||
CNodeCollection::CNodeCollection(const std::string& rssName) : CNode(rssName)
|
||||
{}
|
||||
|
||||
uint32_t CNodeCollection::GetCount() const
|
||||
{
|
||||
return static_cast<uint32_t>(m_vecContent.size());
|
||||
}
|
||||
|
||||
sdv::IInterfaceAccess* CNodeCollection::GetNode(/*in*/ uint32_t uiIndex) const
|
||||
{
|
||||
auto ptrNode = Get(uiIndex);
|
||||
return static_cast<sdv::IInterfaceAccess*>(ptrNode.get());
|
||||
}
|
||||
|
||||
std::shared_ptr<CNode> CNodeCollection::Get(uint32_t uiIndex) const
|
||||
{
|
||||
if (static_cast<size_t>(uiIndex) >= m_vecContent.size()) return nullptr;
|
||||
|
||||
return m_vecContent[uiIndex];
|
||||
}
|
||||
|
||||
sdv::IInterfaceAccess* CNodeCollection::GetNodeDirect(/*in*/ const sdv::u8string& ssPath) const
|
||||
{
|
||||
auto ptrNode = GetDirect(ssPath);
|
||||
return static_cast<sdv::IInterfaceAccess*>(ptrNode.get());
|
||||
}
|
||||
|
||||
bool CNodeCollection::AddElement(const std::shared_ptr<CNode>& rptrNode, bool bUnique /*= false*/)
|
||||
{
|
||||
if (!rptrNode) return false;
|
||||
if (bUnique && std::find_if(m_vecContent.begin(), m_vecContent.end(), [&](const std::shared_ptr<CNode>& rptrNodeEntry)
|
||||
{
|
||||
return CompareEqual(rptrNodeEntry->GetName(), rptrNode->GetName());
|
||||
}) != m_vecContent.end()) return false;
|
||||
m_vecContent.push_back(rptrNode);
|
||||
return true;
|
||||
}
|
||||
|
||||
CTable::CTable(const std::string& rssName) : CNodeCollection(rssName)
|
||||
{}
|
||||
|
||||
sdv::toml::ENodeType CTable::GetType() const
|
||||
{
|
||||
return sdv::toml::ENodeType::node_table;
|
||||
}
|
||||
|
||||
std::shared_ptr<CNode> CTable::GetDirect(const std::string& rssPath) const
|
||||
{
|
||||
size_t nSeparator = FindFirst(rssPath, ".[");
|
||||
std::string ssKey = rssPath.substr(0, nSeparator);
|
||||
std::shared_ptr<CNode> ptrNode;
|
||||
for (uint32_t uiIndex = 0; !ptrNode && uiIndex < GetCount(); uiIndex++)
|
||||
{
|
||||
std::shared_ptr<CNode> ptrNodeEntry = Get(uiIndex);
|
||||
if (!ptrNodeEntry) continue;
|
||||
if (CompareEqual(ptrNodeEntry->GetName(), ssKey)) ptrNode = ptrNodeEntry;
|
||||
}
|
||||
if (!ptrNode) return ptrNode; // Not found
|
||||
|
||||
// Done?
|
||||
if (nSeparator == std::string::npos) return ptrNode;
|
||||
|
||||
// There is more...
|
||||
if (rssPath[nSeparator] == '.') nSeparator++; // Skip dot
|
||||
return ptrNode->GetDirect(rssPath.substr(nSeparator));
|
||||
}
|
||||
|
||||
std::string CTable::CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst, bool bEmbedded,
|
||||
bool bAssignment, bool bRoot) const
|
||||
{
|
||||
// Create the full name
|
||||
std::string ssFullName = rssParent;
|
||||
if (!GetName().empty() && !bRoot)
|
||||
{
|
||||
if (!ssFullName.empty()) ssFullName += ".";
|
||||
ssFullName += GetName();
|
||||
}
|
||||
|
||||
// Stream the table
|
||||
std::stringstream sstreamEntry;
|
||||
if (bEmbedded && !bFirst) // 2nd or higher array entry
|
||||
sstreamEntry << ", ";
|
||||
if (bEmbedded) // Embedded table in an array
|
||||
sstreamEntry << "{";
|
||||
for (uint32_t uiIndex = 0; uiIndex < GetCount(); uiIndex++)
|
||||
{
|
||||
std::shared_ptr<CNode> ptrNode = Get(uiIndex);
|
||||
if (!ptrNode) continue;
|
||||
sstreamEntry << ptrNode->CreateTOMLText(ssFullName, rssLastPrintedTable, uiIndex == 0, bEmbedded);
|
||||
}
|
||||
if (bEmbedded) // Embedded table in an array
|
||||
sstreamEntry << "}";
|
||||
if (!bEmbedded && !bAssignment && !GetName().empty())
|
||||
sstreamEntry << std::endl;
|
||||
|
||||
return sstreamEntry.str();
|
||||
}
|
||||
|
||||
void CTable::Add(const std::string& rssPath, const std::shared_ptr<CNode>& rptrNode, bool bDefinedExplicitly)
|
||||
{
|
||||
if (!m_bOpenToAddChildren)
|
||||
throw XTOMLParseException(("Not allowed to add '" + rssPath + "'; parent node is final").c_str());
|
||||
|
||||
size_t nDotPos = FindFirst(rssPath);
|
||||
std::string ssFirst = rssPath.substr(0, nDotPos);
|
||||
std::string ssSecond = nDotPos == std::string::npos ? "" : rssPath.substr(nDotPos + 1);
|
||||
auto ptrParent = Find(ssFirst);
|
||||
|
||||
// Element does not already exist at given path
|
||||
if (!ptrParent)
|
||||
{
|
||||
// Add the new element as a direct child
|
||||
if (nDotPos == std::string::npos)
|
||||
{
|
||||
rptrNode->SetParent(shared_from_this());
|
||||
GetTable()->AddElement(rptrNode);
|
||||
return;
|
||||
}
|
||||
// Add the new element as a descendant further down
|
||||
auto ptrIntermediateTable = std::make_shared<CNormalTable>(ssFirst);
|
||||
ptrIntermediateTable->SetParent(shared_from_this());
|
||||
ptrIntermediateTable->m_bDefinedExplicitly = bDefinedExplicitly;
|
||||
GetTable()->AddElement(ptrIntermediateTable);
|
||||
static_cast<CNode*>(ptrIntermediateTable.get())->Add(ssSecond, rptrNode, bDefinedExplicitly);
|
||||
return;
|
||||
}
|
||||
if (dynamic_cast<CTableArray*>(ptrParent.get()) && nDotPos == std::string::npos)
|
||||
{
|
||||
ptrParent->Add(ssFirst, rptrNode, bDefinedExplicitly);
|
||||
return;
|
||||
}
|
||||
// Element already exists but would be inserted as a direct child
|
||||
if (nDotPos == std::string::npos)
|
||||
{
|
||||
// Make an already implicitly defined table explicitly defined
|
||||
if (ptrParent->GetType() == rptrNode->GetType() && dynamic_cast<CNodeCollection*>(ptrParent.get()) &&
|
||||
!static_cast<CNodeCollection*>(ptrParent.get())->m_bDefinedExplicitly)
|
||||
{
|
||||
static_cast<CNodeCollection*>(ptrParent.get())->m_bDefinedExplicitly = true;
|
||||
return;
|
||||
}
|
||||
throw XTOMLParseException(("Name '" + ssFirst + "' already exists").c_str());
|
||||
}
|
||||
// Element already exists and new element would be added as descendant
|
||||
ptrParent->Add(ssSecond, rptrNode, bDefinedExplicitly);
|
||||
}
|
||||
|
||||
std::shared_ptr<CNode> CTable::Find(const std::string& rssPath) const
|
||||
{
|
||||
size_t nDotPos = FindFirst(rssPath);
|
||||
std::string ssFirst = rssPath.substr(0, nDotPos);
|
||||
std::string ssSecond = nDotPos == std::string::npos ? "" : rssPath.substr(nDotPos + 1);
|
||||
|
||||
for (uint32_t uiIndex = 0; uiIndex < GetCount(); uiIndex++)
|
||||
{
|
||||
std::shared_ptr<CNode> ptrNode;
|
||||
ptrNode = Get(uiIndex);
|
||||
if (!ptrNode) continue;
|
||||
if (CompareEqual(ptrNode->GetName(), ssFirst))
|
||||
{
|
||||
if (nDotPos == std::string::npos)
|
||||
return ptrNode;
|
||||
return ptrNode->Find(ssSecond);
|
||||
}
|
||||
}
|
||||
|
||||
// No node found...
|
||||
return std::shared_ptr<CNode>();
|
||||
}
|
||||
|
||||
CArray::CArray(const std::string& rssName) : CNodeCollection(rssName)
|
||||
{}
|
||||
|
||||
sdv::toml::ENodeType CArray::GetType() const
|
||||
{
|
||||
return sdv::toml::ENodeType::node_array;
|
||||
}
|
||||
|
||||
std::shared_ptr<CNode> CArray::GetDirect(const std::string& rssPath) const
|
||||
{
|
||||
size_t nIndexBegin = FindFirst(rssPath, "[");
|
||||
if (nIndexBegin == std::string::npos) return std::shared_ptr<CNode>(); // Unexpected
|
||||
|
||||
size_t nIndexEnd = rssPath.find_first_not_of("0123456789", nIndexBegin + 1);
|
||||
if (nIndexEnd == std::string::npos) return std::shared_ptr<CNode>(); // Unexpected
|
||||
if (rssPath[nIndexEnd] != ']') return std::shared_ptr<CNode>(); // Unexpected
|
||||
std::string ssIndex = rssPath.substr(nIndexBegin + 1, nIndexEnd - nIndexBegin - 1);
|
||||
if (ssIndex.empty()) return std::shared_ptr<CNode>(); // Unexpected
|
||||
uint32_t uiIndex = std::atol(ssIndex.c_str());
|
||||
nIndexEnd++;
|
||||
|
||||
// Get the node
|
||||
if (uiIndex >= GetCount()) return std::shared_ptr<CNode>(); // Not found
|
||||
std::shared_ptr<CNode> ptrNode = Get(uiIndex);
|
||||
|
||||
// Done?
|
||||
if (nIndexEnd == rssPath.size()) return ptrNode;
|
||||
|
||||
// Expecting a dot?
|
||||
size_t nSeparator = nIndexEnd;
|
||||
if (rssPath[nSeparator] == '.') nSeparator++; // Skip dot
|
||||
return ptrNode->GetDirect(rssPath.substr(nSeparator));
|
||||
}
|
||||
|
||||
std::string CArray::CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst, bool bEmbedded,
|
||||
bool bAssignment, bool /*bRoot*/) const
|
||||
{
|
||||
std::stringstream sstreamEntry;
|
||||
|
||||
// Do we need to start a table?
|
||||
if (!bEmbedded && bFirst && bAssignment && rssParent != rssLastPrintedTable)
|
||||
{
|
||||
sstreamEntry << std::endl << "[" << rssParent << "]" << std::endl;
|
||||
rssLastPrintedTable = rssParent;
|
||||
}
|
||||
|
||||
// Stream the array
|
||||
if (bEmbedded && !bFirst) // 2nd or higher array entry
|
||||
sstreamEntry << ", ";
|
||||
if (!bEmbedded || bAssignment) // Not an array entry
|
||||
sstreamEntry << GetName() << " = ";
|
||||
sstreamEntry << "[";
|
||||
for (uint32_t ui = 0; ui < GetCount(); ui++)
|
||||
sstreamEntry << Get(ui)->CreateTOMLText(rssParent, rssLastPrintedTable, ui == 0, true, false);
|
||||
sstreamEntry << "]";
|
||||
if (!bEmbedded) // Not an array entry
|
||||
sstreamEntry << std::endl;
|
||||
|
||||
return sstreamEntry.str();
|
||||
}
|
||||
|
||||
void CArray::Add(const std::string& rssPath, const std::shared_ptr<CNode>& rptrNode, bool bDefinedExplicitly)
|
||||
{
|
||||
size_t nDotPos = FindFirst(rssPath);
|
||||
std::string ssFirst = rssPath.substr(0, nDotPos);
|
||||
std::string ssSecond = nDotPos == std::string::npos ? "" : rssPath.substr(nDotPos + 1);
|
||||
|
||||
// Add new element to array
|
||||
if (nDotPos == std::string::npos)
|
||||
{
|
||||
GetArray()->AddElement(rptrNode);
|
||||
return;
|
||||
}
|
||||
// Add new element to subelement of array
|
||||
if (std::any_of(ssFirst.begin(), ssFirst.end(), [](char digit) { return (digit < '0') || (digit > '9'); }))
|
||||
{
|
||||
throw XTOMLParseException(("Invalid array access subscript '" + ssFirst + "'").c_str());
|
||||
}
|
||||
uint32_t uiIndex = std::stoi(ssFirst);
|
||||
if (uiIndex >= GetArray()->GetCount())
|
||||
{
|
||||
// This indicates an array within an arrays. Add the intermediate array
|
||||
auto ptrIntermediateArray = std::make_shared<CNormalArray>(ssFirst);
|
||||
ptrIntermediateArray->SetParent(shared_from_this());
|
||||
ptrIntermediateArray->m_bDefinedExplicitly = bDefinedExplicitly;
|
||||
GetArray()->AddElement(ptrIntermediateArray);
|
||||
static_cast<CNode*>(ptrIntermediateArray.get())->Add(ssSecond, rptrNode, bDefinedExplicitly);
|
||||
//throw XTOMLParseException(("Invalid array access index '" + ssFirst + "'; out of bounds").c_str());
|
||||
}
|
||||
GetArray()->Get(uiIndex)->Add(ssSecond, rptrNode, bDefinedExplicitly);
|
||||
}
|
||||
|
||||
std::shared_ptr<CNode> CArray::Find(const std::string& rssPath) const
|
||||
{
|
||||
size_t nDotPos = FindFirst(rssPath);
|
||||
std::string ssFirst = rssPath.substr(0, nDotPos);
|
||||
std::string ssSecond = nDotPos == std::string::npos ? "" : rssPath.substr(nDotPos + 1);
|
||||
|
||||
if (ssFirst.empty())
|
||||
throw XTOMLParseException("Missing array subscript");
|
||||
|
||||
if (std::any_of(ssFirst.begin(), ssFirst.end(), [](char digit) { return (digit < '0') || (digit > '9'); }))
|
||||
throw XTOMLParseException(("Invalid array access subscript '" + ssFirst + "'").c_str());
|
||||
uint32_t uiIndex = std::stoi(ssFirst);
|
||||
if (GetArray()->GetCount() <= uiIndex)
|
||||
throw XTOMLParseException(
|
||||
("Invalid array access index '" + ssFirst + "'; out of bounds").c_str());
|
||||
if (nDotPos == std::string::npos)
|
||||
return GetArray()->Get(uiIndex);
|
||||
return GetArray()->Get(uiIndex)->Find(ssSecond);
|
||||
}
|
||||
|
||||
std::string CTableArray::CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool /*bFirst*/, bool /*bEmbedded*/,
|
||||
bool /*bAssignment*/, bool bRoot) const
|
||||
{
|
||||
// Create the full name
|
||||
std::string ssFullName = rssParent;
|
||||
if (!ssFullName.empty() && !bRoot) ssFullName += ".";
|
||||
ssFullName += GetName();
|
||||
|
||||
// Stream the array
|
||||
std::stringstream sstreamEntry;
|
||||
for (uint32_t ui = 0; ui < GetCount(); ui++)
|
||||
{
|
||||
sstreamEntry << std::endl << "[[" << ssFullName << "]]" << std::endl;
|
||||
rssLastPrintedTable = ssFullName;
|
||||
sstreamEntry << Get(ui)->CreateTOMLText(ssFullName, rssLastPrintedTable, ui == 0, false, false);
|
||||
}
|
||||
//sstreamEntry << std::endl;
|
||||
|
||||
return sstreamEntry.str();
|
||||
}
|
||||
|
||||
void CTableArray::Add(const std::string& rssPath, const std::shared_ptr<CNode>& rptrNode, bool bDefinedExplicitly)
|
||||
{
|
||||
//size_t nDotPos = FindFirst(rssPath);
|
||||
//std::string ssFirst = rssPath.substr(0, nDotPos);
|
||||
//std::string ssSecond = nDotPos == std::string::npos ? "" : rssPath.substr(nDotPos + 1);
|
||||
|
||||
uint32_t uiSize = GetArray()->GetCount();
|
||||
if (uiSize == 0)
|
||||
{
|
||||
throw XTOMLParseException("Trying to access table in an empty array of tables");
|
||||
}
|
||||
GetArray()->Get(uiSize - 1)->Add(rssPath, rptrNode, bDefinedExplicitly);
|
||||
}
|
||||
|
||||
std::shared_ptr<CNode> CTableArray::Find(const std::string& rssPath) const
|
||||
{
|
||||
//size_t nDotPos = FindFirst(rssPath);
|
||||
//std::string ssFirst = rssPath.substr(0, nDotPos);
|
||||
//std::string ssSecond = nDotPos == std::string::npos ? "" : rssPath.substr(nDotPos + 1);
|
||||
|
||||
if (!GetArray()->GetCount())
|
||||
throw XTOMLParseException(("Trying to access empty table array; " + rssPath).c_str());
|
||||
return GetArray()->Get(GetArray()->GetCount() - 1)->Find(rssPath);
|
||||
}
|
||||
|
||||
std::string CRootTable::CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool /*bFirst*/,
|
||||
bool /*bEmbedded*/, bool /*bAssignment*/, bool /*bRoot*/) const
|
||||
{
|
||||
// Create the full name
|
||||
std::string ssFullName = rssParent;
|
||||
|
||||
// Stream the table
|
||||
std::stringstream sstreamEntry;
|
||||
for (uint32_t uiIndex = 0; uiIndex < GetCount(); uiIndex++)
|
||||
{
|
||||
std::shared_ptr<CNode> ptrNode = Get(uiIndex);
|
||||
if (!ptrNode) continue;
|
||||
sstreamEntry << ptrNode->CreateTOMLText(ssFullName, rssLastPrintedTable);
|
||||
}
|
||||
|
||||
sstreamEntry << std::endl;
|
||||
|
||||
// Skip whitespace at the beginning
|
||||
std::string ssRet = sstreamEntry.str();
|
||||
size_t nStart = ssRet.find_first_not_of(" \t\f\r\n\v");
|
||||
if (nStart == std::string::npos) return std::string();
|
||||
return ssRet.substr(nStart);
|
||||
}
|
||||
718
sdv_services/core/toml_parser/parser_node_toml.h
Normal file
718
sdv_services/core/toml_parser/parser_node_toml.h
Normal file
@@ -0,0 +1,718 @@
|
||||
#ifndef PARSER_NODE_TOML_H
|
||||
#define PARSER_NODE_TOML_H
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <interfaces/toml.h>
|
||||
#include <support/interface_ptr.h>
|
||||
|
||||
// Forward declaration
|
||||
class CArray;
|
||||
class CTable;
|
||||
|
||||
/**
|
||||
* @brief Find the first separator character. Do not include string content (single/or double quoted) and escape characters.
|
||||
* @param[in] rss Reference to the string.
|
||||
* @param[in] rssSeparator One of the characters to find in the string. Must not be an empty string!
|
||||
* @return The position of the first separator character or std::string::npos when none has found.
|
||||
*/
|
||||
size_t FindFirst(const std::string& rss, const std::string& rssSeparator = ".");
|
||||
|
||||
/**
|
||||
* @brief Find the last separator character. Do not include string content (single/or double quoted) and escape characters.
|
||||
* @param[in] rss Reference to the string.
|
||||
* @param[in] rssSeparator One of the characters to find in the string. Must not be an empty string!
|
||||
* @return The position of the last separator character or std::string::npos when none has found.
|
||||
*/
|
||||
size_t FindLast(const std::string& rss, const std::string& rssSeparator = ".");
|
||||
|
||||
/**
|
||||
* @brief Compare both string ignoring the quotes at the first position and last position.
|
||||
* @param[in] rss1 Reference to the first string.
|
||||
* @param[in] rss2 Reference to the second string.
|
||||
* @return The comparison result.
|
||||
*/
|
||||
bool CompareEqual(const std::string& rss1, const std::string& rss2);
|
||||
|
||||
/**
|
||||
* @brief Escape a string using escape characters and UTF values.
|
||||
*/
|
||||
std::string EscapeString(const std::string& rssString, const char cQuoteType = '\"');
|
||||
|
||||
/**
|
||||
* @brief Node to build up the parse tree
|
||||
*/
|
||||
class CNode : public std::enable_shared_from_this<CNode>, public sdv::IInterfaceAccess, public sdv::toml::INodeInfo
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* @brief Constructs a new node object representing a table or an array.
|
||||
* @param[in] rssName Reference to the name of the node.
|
||||
*/
|
||||
CNode(const std::string& rssName);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Deleted since Nodes should only be handled via smart-pointer
|
||||
* @{
|
||||
*/
|
||||
CNode(const CNode&) = delete;
|
||||
CNode& operator=(const CNode&) = delete;
|
||||
CNode(const CNode&&) = delete;
|
||||
CNode& operator=(const CNode&&) = delete;
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Destroy the node object
|
||||
*/
|
||||
~CNode();
|
||||
|
||||
// Interface map
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(sdv::toml::INodeInfo)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
* @brief Get the node name. Overload of sdv::toml::INodeInfo::GetName.
|
||||
* @return String containing the name of the node.
|
||||
*/
|
||||
virtual sdv::u8string GetName() const override;
|
||||
|
||||
/**
|
||||
* @brief The node value. Overload of sdv::toml::INodeInfo::GetValue.
|
||||
* @return For boolean, integer, floating point and strings, the function returns a value. Otherwise the function
|
||||
* returns empty.
|
||||
*/
|
||||
virtual sdv::any_t GetValue() const override;
|
||||
|
||||
/**
|
||||
* @brief The node value. Overload of sdv::toml::INodeInfo::GetTOML.
|
||||
* @return For boolean, integer, floating point and strings, the function returns a value. Otherwise the function
|
||||
* returns empty.
|
||||
*/
|
||||
virtual sdv::u8string GetTOML() const override;
|
||||
|
||||
/**
|
||||
* @brief Gets the array value of a node
|
||||
* @return Returns a shared pointer of the array value stored in the node if the stored type is array
|
||||
*/
|
||||
std::shared_ptr<const CArray> GetArray() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the array value of a node
|
||||
* @return Returns a shared pointer of the array value stored in the node if the stored type is array
|
||||
*/
|
||||
std::shared_ptr<CArray> GetArray();
|
||||
|
||||
/**
|
||||
* @brief Gets the table value of a node
|
||||
* @return Returns a shared pointer of the table value stored in the node if the stored type is table
|
||||
*/
|
||||
std::shared_ptr<const CTable> GetTable() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the table value of a node
|
||||
* @return Returns a shared pointer of the table value stored in the node if the stored type is table
|
||||
*/
|
||||
std::shared_ptr<CTable> GetTable();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Gets the Parent Node
|
||||
* @return Returns the parent Node
|
||||
* @attention Beware of expiring pointers
|
||||
*/
|
||||
std::weak_ptr<const CNode> GetParent() const;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Set the parent node.
|
||||
* @param[in] rptrParent Reference to the node to assign to this node as a parent.
|
||||
*/
|
||||
void SetParent(const std::shared_ptr<CNode>& rptrParent);
|
||||
|
||||
/**
|
||||
* @brief Accesses a node by its key in the parse tree.
|
||||
* @details Elements of tables can be accessed and traversed by using '.' to separated the parent name from child name.
|
||||
* E.g. 'parent.child' would access the 'child' element of the 'parent' table. Elements of arrays can be accessed and traversed
|
||||
* by using the index number in brackets. E.g. 'array[3]' would access the fourth element of the array 'array'. These access
|
||||
* conventions can also be chained like 'table.array[2][1].subtable.integerElement'.
|
||||
* @attention Array indexing starts with 0!
|
||||
* @param[in] rssPath The path of the node to searched for.
|
||||
* @return Returns a shared pointer to the wanted Node if it was found or a node with invalid content if it was not found.
|
||||
*/
|
||||
virtual std::shared_ptr<CNode> GetDirect(const std::string& rssPath) const;
|
||||
|
||||
/**
|
||||
* @brief Create the TOML text based on the content using an optional parent node.
|
||||
* @param[in] rssParent When present, uses the parent node into the TOML text generation.
|
||||
* @return The string containing the TOML text.
|
||||
*/
|
||||
std::string CreateTOMLText(const std::string& rssParent = std::string()) const;
|
||||
|
||||
/**
|
||||
* @brief Get the TOML text based on the content.
|
||||
* @param[in] rssParent When present, uses the parent node into the TOML text generation.
|
||||
* @param[in] rssLastPrintedTable Reference to the string containing the last printed table. This might be necessary in case a
|
||||
* different table was printed in between.
|
||||
* @param[in] bFirst When set, this is the first entry in an array or table.
|
||||
* @param[in] bEmbedded When set, this is an embedded definition in an array or table.
|
||||
* @param[in] bAssignment When set, this is a table assignment.
|
||||
* @param[in] bRoot Only for table entries, when set this is the root entry (suppress the table name).
|
||||
* @return The string containing the TOML text.
|
||||
*/
|
||||
virtual std::string CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst = true,
|
||||
bool bEmbedded = false, bool bAssignment = true, bool bRoot = false) const = 0;
|
||||
|
||||
private:
|
||||
std::weak_ptr<CNode> m_ptrParent; ///< Weak pointer to the parent node (if existing).
|
||||
std::string m_ssName; ///< Name of the node.
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Searches the subtree of the node for a node at the given location using the provided path.
|
||||
* @remarks The path elements of arrays and tables are separated by a dot.
|
||||
* @param[in] rssPath Reference to the string containing the path of the node to find.
|
||||
* @return Returns a shared pointer to the wanted Node if it is found or an error-Node if it is not
|
||||
*/
|
||||
virtual std::shared_ptr<CNode> Find(const std::string& rssPath) const;
|
||||
|
||||
/**
|
||||
* @brief Adds a given node to a given path in the tree
|
||||
* @remarks The path elements of arrays and tables are separated by a dot.
|
||||
* @param[in] rssPath Reference to the string containing the path in the tree of the location to the new node to be inserted.
|
||||
* @param[in] rptrNode Reference to the smart pointer containing the new node to be added.
|
||||
* @param[in] bDefinedExplicitly If a table that is created to create the path of the node to be added is defined explicitly.
|
||||
* @throw XInvalidAccessException Throws an XInvalidAccessException if a ancestor node is not open to add children.
|
||||
* @throw XDuplicateNameException Throws a XDuplicateNameException if a node with the same path as the node to
|
||||
* be added is already defined explicitly
|
||||
*/
|
||||
virtual void Add(const std::string& rssPath, const std::shared_ptr<CNode>& rptrNode, bool bDefinedExplicitly = true);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Boolean value node.
|
||||
*/
|
||||
class CBooleanNode : public CNode
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rssName Reference to the string containing the name of the node.
|
||||
* @param[in] bVal The value to assign.
|
||||
*/
|
||||
CBooleanNode(const std::string& rssName, bool bVal);
|
||||
|
||||
/**
|
||||
* @brief Get the node type. Overload of sdv::toml::INodeInfo::GetType.
|
||||
* @return Type of the node.
|
||||
*/
|
||||
virtual sdv::toml::ENodeType GetType() const override;
|
||||
|
||||
/**
|
||||
* @brief The node value. Overload of sdv::toml::INodeInfo::GetValue.
|
||||
* @return For boolean, integer, floating point and strings, the function returns a value. Otherwise the function
|
||||
* returns empty.
|
||||
*/
|
||||
virtual sdv::any_t GetValue() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the TOML text based on the content. Overload of CNode::CreateTOMLText.
|
||||
* @param[in] rssParent When present, uses the parent node into the TOML text generation.
|
||||
* @param[in] rssLastPrintedTable Reference to the string containing the last printed table. This might be necessary in case a
|
||||
* different table was printed in between.
|
||||
* @param[in] bFirst When set, this is the first entry in an array or table.
|
||||
* @param[in] bEmbedded When set, this is an embedded definition in an array or table.
|
||||
* @param[in] bAssignment When set, this is a table assignment.
|
||||
* @param[in] bRoot Only for table entries, when set this is the root entry (suppress the table name).
|
||||
* @return The string containing the TOML text.
|
||||
*/
|
||||
virtual std::string CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst, bool bEmbedded,
|
||||
bool bAssignment, bool bRoot) const override;
|
||||
|
||||
private:
|
||||
bool m_bVal; ///< Value in case of boolean node.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Integer value node.
|
||||
*/
|
||||
class CIntegerNode : public CNode
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rssName Reference to the string containing the name of the node.
|
||||
* @param[in] iVal The value to assign.
|
||||
*/
|
||||
CIntegerNode(const std::string& rssName, int64_t iVal);
|
||||
|
||||
/**
|
||||
* @brief Get the node type. Overload of sdv::toml::INodeInfo::GetType.
|
||||
* @return Type of the node.
|
||||
*/
|
||||
virtual sdv::toml::ENodeType GetType() const override;
|
||||
|
||||
/**
|
||||
* @brief The node value. Overload of sdv::toml::INodeInfo::GetValue.
|
||||
* @return For boolean, integer, floating point and strings, the function returns a value. Otherwise the function
|
||||
* returns empty.
|
||||
*/
|
||||
virtual sdv::any_t GetValue() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the TOML text based on the content. Overload of CNode::CreateTOMLText.
|
||||
* @param[in] rssParent When present, uses the parent node into the TOML text generation.
|
||||
* @param[in] rssLastPrintedTable Reference to the string containing the last printed table. This might be necessary in case a
|
||||
* different table was printed in between.
|
||||
* @param[in] bFirst When set, this is the first entry in an array or table.
|
||||
* @param[in] bEmbedded When set, this is an embedded definition in an array or table.
|
||||
* @param[in] bAssignment When set, this is a table assignment.
|
||||
* @param[in] bRoot Only for table entries, when set this is the root entry (suppress the table name).
|
||||
* @return The string containing the TOML text.
|
||||
*/
|
||||
virtual std::string CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst, bool bEmbedded,
|
||||
bool bAssignment, bool bRoot) const override;
|
||||
|
||||
private:
|
||||
int64_t m_iVal; ///< Value in case of integer node.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Floating point value node.
|
||||
*/
|
||||
class CFloatingPointNode : public CNode
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rssName Reference to the string containing the name of the node.
|
||||
* @param[in] dVal The value to assign.
|
||||
*/
|
||||
CFloatingPointNode(const std::string& rssName, double dVal);
|
||||
|
||||
/**
|
||||
* @brief Get the node type. Overload of sdv::toml::INodeInfo::GetType.
|
||||
* @return Type of the node.
|
||||
*/
|
||||
virtual sdv::toml::ENodeType GetType() const override;
|
||||
|
||||
/**
|
||||
* @brief The node value. Overload of sdv::toml::INodeInfo::GetValue.
|
||||
* @return For boolean, integer, floating point and strings, the function returns a value. Otherwise the function
|
||||
* returns empty.
|
||||
*/
|
||||
virtual sdv::any_t GetValue() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the TOML text based on the content. Overload of CNode::CreateTOMLText.
|
||||
* @param[in] rssParent When present, uses the parent node into the TOML text generation.
|
||||
* @param[in] rssLastPrintedTable Reference to the string containing the last printed table. This might be necessary in case a
|
||||
* different table was printed in between.
|
||||
* @param[in] bFirst When set, this is the first entry in an array or table.
|
||||
* @param[in] bEmbedded When set, this is an embedded definition in an array or table.
|
||||
* @param[in] bAssignment When set, this is a table assignment.
|
||||
* @param[in] bRoot Only for table entries, when set this is the root entry (suppress the table name).
|
||||
* @return The string containing the TOML text.
|
||||
*/
|
||||
virtual std::string CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst, bool bEmbedded,
|
||||
bool bAssignment, bool bRoot) const override;
|
||||
|
||||
private:
|
||||
double m_dVal; ///< Value in case of floating point node.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief String value node.
|
||||
*/
|
||||
class CStringNode : public CNode
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rssName Reference to the string containing the name of the node.
|
||||
* @param[in] rssVal The value to assign.
|
||||
*/
|
||||
CStringNode(const std::string& rssName, const std::string& rssVal);
|
||||
|
||||
/**
|
||||
* @brief Get the node type. Overload of sdv::toml::INodeInfo::GetType.
|
||||
* @return Type of the node.
|
||||
*/
|
||||
virtual sdv::toml::ENodeType GetType() const override;
|
||||
|
||||
/**
|
||||
* @brief The node value. Overload of sdv::toml::INodeInfo::GetValue.
|
||||
* @return For boolean, integer, floating point and strings, the function returns a value. Otherwise the function
|
||||
* returns empty.
|
||||
*/
|
||||
virtual sdv::any_t GetValue() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the TOML text based on the content. Overload of CNode::CreateTOMLText.
|
||||
* @param[in] rssParent When present, uses the parent node into the TOML text generation.
|
||||
* @param[in] rssLastPrintedTable Reference to the string containing the last printed table. This might be necessary in case a
|
||||
* different table was printed in between.
|
||||
* @param[in] bFirst When set, this is the first entry in an array or table.
|
||||
* @param[in] bEmbedded When set, this is an embedded definition in an array or table.
|
||||
* @param[in] bAssignment When set, this is a table assignment.
|
||||
* @param[in] bRoot Only for table entries, when set this is the root entry (suppress the table name).
|
||||
* @return The string containing the TOML text.
|
||||
*/
|
||||
virtual std::string CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst, bool bEmbedded,
|
||||
bool bAssignment, bool bRoot) const override;
|
||||
|
||||
private:
|
||||
std::string m_ssVal; ///< Value in case of string or illegal (error) node.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Base structure for arrays and tables.
|
||||
*/
|
||||
class CNodeCollection : public CNode, public sdv::toml::INodeCollection
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rssName Reference to the name of the node.
|
||||
*/
|
||||
CNodeCollection(const std::string& rssName);
|
||||
|
||||
public:
|
||||
// Interface map
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(sdv::toml::INodeCollection)
|
||||
SDV_INTERFACE_CHAIN_BASE(CNode)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
* @brief Returns the amount of nodes. Overload of sdv::toml::INodeCollection::GetCount.
|
||||
* @return The amount of nodes.
|
||||
*/
|
||||
virtual uint32_t GetCount() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the node. Overload of sdv::toml::INodeCollection::GetNode.
|
||||
* @param[in] uiIndex Index of the node to get.
|
||||
* @return Interface to the node object.
|
||||
*/
|
||||
virtual IInterfaceAccess* GetNode(/*in*/ uint32_t uiIndex) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the node.
|
||||
* @param[in] uiIndex Index of the node to get.
|
||||
* @return Smart pointer to the node object.
|
||||
*/
|
||||
std::shared_ptr<CNode> Get(uint32_t uiIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Searches a node by its key in the parse tree
|
||||
* @details Elements of tables can be accessed and traversed by using '.' to separated the parent name from child
|
||||
* name. E.g. 'parent.child' would access the 'child' element of the 'parent' table. Elements of arrays can be
|
||||
* accessed and traversed by using the index number in brackets. E.g. 'array[3]' would access the fourth element of
|
||||
* the array 'array'. These access conventions can also be chained like 'table.array[2][1].subtable.integerElement'.
|
||||
* @attention Array indexing starts with 0!
|
||||
* @param[in] ssPath The path of the node to searched for.
|
||||
* @return Returns an interface the requested node if available.
|
||||
*/
|
||||
virtual sdv::IInterfaceAccess* GetNodeDirect(/*in*/ const sdv::u8string& ssPath) const override;
|
||||
|
||||
/**
|
||||
* @brief Add an element to the collection.
|
||||
* @param[in] rptrNode Reference to the node element smart pointer.
|
||||
* @param[in] bUnique When set, check prevents adding an element with the same name.
|
||||
* @return Returns whether the element addition was successful.
|
||||
*/
|
||||
bool AddElement(const std::shared_ptr<CNode>& rptrNode, bool bUnique = false);
|
||||
|
||||
private:
|
||||
|
||||
std::vector<std::shared_ptr<CNode>> m_vecContent; ///< Vector holding the child elements
|
||||
|
||||
public:
|
||||
bool m_bDefinedExplicitly = true; ///< WHen set, the array/table is defined explicitly
|
||||
///< (not internal).
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A dynamic table structure that allows mixed data in form of key value pairs
|
||||
*/
|
||||
class CTable : public CNodeCollection
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rssName Reference to the name of the node.
|
||||
*/
|
||||
CTable(const std::string& rssName);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Get the node type. Overload of sdv::toml::INodeInfo::GetType.
|
||||
* @return Type of the node.
|
||||
*/
|
||||
virtual sdv::toml::ENodeType GetType() const override;
|
||||
|
||||
/**
|
||||
* @brief Accesses a node by its key in the parse tree. Overload of CNode::GetDirect.
|
||||
* @details Elements of tables can be accessed and traversed by using '.' to separated the parent name from child name.
|
||||
* E.g. 'parent.child' would access the 'child' element of the 'parent' table. Elements of arrays can be accessed and traversed
|
||||
* by using the index number in brackets. E.g. 'array[3]' would access the fourth element of the array 'array'. These access
|
||||
* conventions can also be chained like 'table.array[2][1].subtable.integerElement'.
|
||||
* @attention Array indexing starts with 0!
|
||||
* @param[in] rssPath The path of the node to searched for.
|
||||
* @return Returns a shared pointer to the wanted Node if it was found or a node with invalid content if it was not found.
|
||||
*/
|
||||
virtual std::shared_ptr<CNode> GetDirect(const std::string& rssPath) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the TOML text based on the content. Overload of CNode::CreateTOMLText.
|
||||
* @param[in] rssParent When present, uses the parent node into the TOML text generation.
|
||||
* @param[in] rssLastPrintedTable Reference to the string containing the last printed table. This might be necessary in case a
|
||||
* different table was printed in between.
|
||||
* @param[in] bFirst When set, this is the first entry in an array or table.
|
||||
* @param[in] bEmbedded When set, this is an embedded definition in an array or table.
|
||||
* @param[in] bAssignment When set, this is a table assignment.
|
||||
* @param[in] bRoot Only for table entries, when set this is the root entry (suppress the table name).
|
||||
* @return The string containing the TOML text.
|
||||
*/
|
||||
virtual std::string CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst, bool bEmbedded,
|
||||
bool bAssignment, bool bRoot) const override;
|
||||
|
||||
/**
|
||||
* @brief Adds a given node to a given path in the tree. Overload of CNode::Add.
|
||||
* @param[in] rssPath Reference to the path in the tree where the new node is to be added
|
||||
* @param[in] rptrNode Reference to the smart pointer holding the node.
|
||||
* @param[in] bDefinedExplicitly If a table that is created to create the path of the node to be added is
|
||||
* defined explicitly
|
||||
* @throw XInvalidAccessException Throws an XInvalidAccessException if a ancestor node is not open to add
|
||||
* children
|
||||
* @throw XDuplicateNameException Throws a XDuplicateNameException if a node with the same path as the node to
|
||||
* be added is already defined explicitly
|
||||
*/
|
||||
virtual void Add(const std::string& rssPath, const std::shared_ptr<CNode>& rptrNode, bool bDefinedExplicitly) override;
|
||||
|
||||
/**
|
||||
* @brief Searches the subtree of the node for a node at the given location using the provided path. Overload of CNode::Find.
|
||||
* @remarks The path elements of arrays and tables are separated by a dot.
|
||||
* @param[in] rssPath Reference to the path in the tree where the new node is to be added
|
||||
* @return Returns a shared pointer to the wanted Node if it is found or an error-Node if it is not
|
||||
*/
|
||||
virtual std::shared_ptr<CNode> Find(const std::string& rssPath) const override;
|
||||
|
||||
bool m_bOpenToAddChildren = true; ///< If internal table, the table can be extended until the table
|
||||
///< is closed.
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A dynamic array structure that allows mixed data
|
||||
* @details The definition of an array in TOML differentiate massively from the syntax to access the elements. For example an array
|
||||
* in TOML could be defined by:
|
||||
* @code
|
||||
* integers = [ 1, 2, 3 ]
|
||||
* nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ]
|
||||
* [[products]]
|
||||
* name = "Hammer"
|
||||
* sku = 738594937
|
||||
* @endcode
|
||||
* The first two examples define the complete array at once. The third example defines one element to be added to an array. Random
|
||||
* access to previous definitions is not required.
|
||||
* The access functions need random access to each element. The GetDirect function uses the syntax similar to C++:
|
||||
* @code
|
||||
* integers[1] --> gives: 2
|
||||
* nested_mixed_array[1][2] --> gives: "c"
|
||||
* products[0].sku --> gives: 738594937
|
||||
* @endcode
|
||||
* To find array elements, the path names are composed of elements separated by a dot. The Add and Find functions use the following
|
||||
* syntax:
|
||||
* @code
|
||||
* integers.1 --> stores: 2
|
||||
* nested_mixed_array.1.2 --> stores: "c"
|
||||
* products.0.sku --> stores: 738594937
|
||||
* @endcode
|
||||
*/
|
||||
class CArray : public CNodeCollection
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rssName Reference to the name of the node.
|
||||
*/
|
||||
CArray(const std::string& rssName);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Get the node type. Overload of sdv::toml::INodeInfo::GetType.
|
||||
* @return Type of the node.
|
||||
*/
|
||||
virtual sdv::toml::ENodeType GetType() const override;
|
||||
|
||||
/**
|
||||
* @brief Accesses a node by its key in the parse tree. Overload of CNode::GetDirect.
|
||||
* @details Elements of tables can be accessed and traversed by using '.' to separated the parent name from child name.
|
||||
* E.g. 'parent.child' would access the 'child' element of the 'parent' table. Elements of arrays can be accessed and traversed
|
||||
* by using the index number in brackets. E.g. 'array[3]' would access the fourth element of the array 'array'. These access
|
||||
* conventions can also be chained like 'table.array[2][1].subtable.integerElement'.
|
||||
* @attention Array indexing starts with 0!
|
||||
* @param[in] rssPath Reference to the path of the node to searched for.
|
||||
* @return Returns a shared pointer to the wanted Node if it was found or a node with invalid content if it was not found.
|
||||
*/
|
||||
virtual std::shared_ptr<CNode> GetDirect(const std::string& rssPath) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the TOML text based on the content. Overload of CNode::CreateTOMLText.
|
||||
* @param[in] rssParent When present, uses the parent node into the TOML text generation.
|
||||
* @param[in] rssLastPrintedTable Reference to the string containing the last printed table. This might be necessary in case a
|
||||
* different table was printed in between.
|
||||
* @param[in] bFirst When set, this is the first entry in an array or table.
|
||||
* @param[in] bEmbedded When set, this is an embedded definition in an array or table.
|
||||
* @param[in] bAssignment When set, this is a table assignment.
|
||||
* @param[in] bRoot Only for table entries, when set this is the root entry (suppress the table name).
|
||||
* @return The string containing the TOML text.
|
||||
*/
|
||||
virtual std::string CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst, bool bEmbedded,
|
||||
bool bAssignment, bool bRoot) const override;
|
||||
|
||||
/**
|
||||
* @brief Adds a given node to a given path in the tree. Overload of CNode::Add.
|
||||
* @param[in] rssPath Reference to the path in the tree where the new node is to be added.
|
||||
* @param[in] rptrNode Reference top the smart pointer holding the node.
|
||||
* @param[in] bDefinedExplicitly If a table that is created to create the path of the node to be added is
|
||||
* defined explicitly
|
||||
* @throw XInvalidAccessException Throws an XInvalidAccessException if a ancestor node is not open to add
|
||||
* children
|
||||
* @throw XDuplicateNameException Throws a XDuplicateNameException if a node with the same path as the node to
|
||||
* be added is already defined explicitly
|
||||
*/
|
||||
virtual void Add(const std::string& rssPath, const std::shared_ptr<CNode>& rptrNode, bool bDefinedExplicitly) override;
|
||||
|
||||
/**
|
||||
* @brief Searches the subtree of the node for a node at the given location using the provided path. Overload of CNode::Find.
|
||||
* @remarks The path elements of arrays and tables are separated by a dot.
|
||||
* @param[in] rssPath Reference to the path of the node to find.
|
||||
* @return Returns a shared pointer to the wanted Node if it is found or an error-Node if it is not
|
||||
*/
|
||||
virtual std::shared_ptr<CNode> Find(const std::string& rssPath) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Normal table
|
||||
*/
|
||||
class CNormalTable : public CTable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rssName Reference to the name of the node.
|
||||
*/
|
||||
CNormalTable(const std::string& rssName) : CTable(rssName) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Inline table
|
||||
*/
|
||||
class CInlineTable : public CTable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rssName Reference to the name of the node.
|
||||
*/
|
||||
CInlineTable(const std::string& rssName) : CTable(rssName) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Normal array
|
||||
*/
|
||||
class CNormalArray : public CArray
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rssName Reference to the name of the node.
|
||||
*/
|
||||
CNormalArray(const std::string& rssName) : CArray(rssName) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Array of tables
|
||||
*/
|
||||
class CTableArray : public CArray
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rssName Reference to the name of the node.
|
||||
*/
|
||||
CTableArray(const std::string& rssName) : CArray(rssName) {}
|
||||
|
||||
/**
|
||||
* @brief Get the TOML text based on the content. Overload of CNode::CreateTOMLText.
|
||||
* @param[in] rssParent When present, uses the parent node into the TOML text generation.
|
||||
* @param[in] rssLastPrintedTable Reference to the string containing the last printed table. This might be necessary in case a
|
||||
* different table was printed in between.
|
||||
* @param[in] bFirst When set, this is the first entry in an array or table.
|
||||
* @param[in] bEmbedded When set, this is an embedded definition in an array or table.
|
||||
* @param[in] bAssignment When set, this is a table assignment.
|
||||
* @param[in] bRoot Only for table entries, when set this is the root entry (suppress the table name).
|
||||
* @return The string containing the TOML text.
|
||||
*/
|
||||
virtual std::string CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst, bool bEmbedded,
|
||||
bool bAssignment, bool bRoot) const override;
|
||||
|
||||
/**
|
||||
* @brief Adds a given node to a given path in the tree. Overload of CNode::Add.
|
||||
* @param[in] rssPath Reference to the path in the tree where the new node is to be added.
|
||||
* @param[in] rptrNode Reference top the smart pointer holding the node.
|
||||
* @param[in] bDefinedExplicitly If a table that is created to create the path of the node to be added is
|
||||
* defined explicitly
|
||||
* @throw XInvalidAccessException Throws an XInvalidAccessException if a ancestor node is not open to add
|
||||
* children
|
||||
* @throw XDuplicateNameException Throws a XDuplicateNameException if a node with the same path as the node to
|
||||
* be added is already defined explicitly
|
||||
*/
|
||||
virtual void Add(const std::string& rssPath, const std::shared_ptr<CNode>& rptrNode, bool bDefinedExplicitly) override;
|
||||
|
||||
/**
|
||||
* @brief Searches the subtree of the node for a node at the given location using the provided path. Overload of CNode::Find.
|
||||
* @remarks The path elements of arrays and tables are separated by a dot.
|
||||
* @param[in] rssPath Reference to the string containing the path of the node to find.
|
||||
* @return Returns a shared pointer to the wanted Node if it is found or an error-Node if it is not
|
||||
*/
|
||||
virtual std::shared_ptr<CNode> Find(const std::string& rssPath) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Root table
|
||||
*/
|
||||
class CRootTable : public CNormalTable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
CRootTable() : CNormalTable("root") {}
|
||||
|
||||
/**
|
||||
* @brief Get the TOML text based on the content. Overload of CNode::CreateTOMLText.
|
||||
* @param[in] rssParent When present, uses the parent node into the TOML text generation.
|
||||
* @param[in] rssLastPrintedTable Reference to the string containing the last printed table. This might be necessary in case a
|
||||
* different table was printed in between.
|
||||
* @param[in] bFirst When set, this is the first entry in an array or table.
|
||||
* @param[in] bEmbedded When set, this is an embedded definition in an array or table.
|
||||
* @param[in] bAssignment When set, this is a table assignment.
|
||||
* @param[in] bRoot Only for table entries, when set this is the root entry (suppress the table name).
|
||||
* @return The string containing the TOML text.
|
||||
*/
|
||||
virtual std::string CreateTOMLText(const std::string& rssParent, std::string& rssLastPrintedTable, bool bFirst, bool bEmbedded,
|
||||
bool bAssignment, bool bRoot) const override;
|
||||
};
|
||||
|
||||
#endif // !defined PARSER_NODE_TOML_H
|
||||
380
sdv_services/core/toml_parser/parser_toml.cpp
Normal file
380
sdv_services/core/toml_parser/parser_toml.cpp
Normal file
@@ -0,0 +1,380 @@
|
||||
#include "parser_toml.h"
|
||||
#include <iostream>
|
||||
#include "exception.h"
|
||||
|
||||
CParserTOML::CParserTOML(const std::string& rssString) : m_lexer(rssString)
|
||||
{
|
||||
Process(rssString);
|
||||
}
|
||||
|
||||
void CParserTOML::Clear()
|
||||
{
|
||||
m_ptrRoot = std::make_shared<CRootTable>();
|
||||
m_ssCurrentTable.clear();
|
||||
m_lexer.Reset();
|
||||
while (!m_stackEnvironment.empty()) m_stackEnvironment.pop();
|
||||
}
|
||||
|
||||
bool CParserTOML::Process(/*in*/ const sdv::u8string& ssContent)
|
||||
{
|
||||
Clear();
|
||||
m_lexer.Feed(ssContent);
|
||||
try
|
||||
{
|
||||
// Run through all tokens of the lexer and process the tokens.
|
||||
while (!m_lexer.IsEnd())
|
||||
{
|
||||
CLexerTOML::SToken current = m_lexer.Peek();
|
||||
switch (current.eCategory)
|
||||
{
|
||||
case CLexerTOML::ETokenCategory::token_syntax_table_open:
|
||||
ProcessTable();
|
||||
break;
|
||||
case CLexerTOML::ETokenCategory::token_syntax_table_array_open:
|
||||
ProcessTableArray();
|
||||
break;
|
||||
case CLexerTOML::ETokenCategory::token_key:
|
||||
ProcessValueKey();
|
||||
break;
|
||||
case CLexerTOML::ETokenCategory::token_syntax_new_line:
|
||||
m_lexer.Consume();
|
||||
break;
|
||||
case CLexerTOML::ETokenCategory::token_terminated:
|
||||
case CLexerTOML::ETokenCategory::token_error:
|
||||
throw XTOMLParseException(current.ssContentString);
|
||||
break;
|
||||
default:
|
||||
throw XTOMLParseException("Invalid Syntax; not a Key, Table or Tablearray");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const sdv::toml::XTOMLParseException& e)
|
||||
{
|
||||
std::cout << e.what() << '\n';
|
||||
throw;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const CNodeCollection& CParserTOML::GetRoot() const
|
||||
{
|
||||
auto ptrCollection = m_ptrRoot->GetTable();
|
||||
return *ptrCollection.get();
|
||||
}
|
||||
|
||||
CNodeCollection& CParserTOML::GetRoot()
|
||||
{
|
||||
auto ptrCollection = m_ptrRoot->GetTable();
|
||||
return *ptrCollection.get();
|
||||
}
|
||||
|
||||
std::string CParserTOML::CreateTOMLText(const std::string& rssParent) const
|
||||
{
|
||||
std::string ssLastPrintedTable;
|
||||
return m_ptrRoot->CreateTOMLText(rssParent, ssLastPrintedTable);
|
||||
}
|
||||
|
||||
bool CParserTOML::Add(const std::string& rssPath, bool bVal)
|
||||
{
|
||||
size_t nOffset = FindLast(rssPath);
|
||||
if (nOffset == std::string::npos)
|
||||
nOffset = 0;
|
||||
else
|
||||
nOffset++;
|
||||
std::string ssName = rssPath.substr(nOffset);
|
||||
|
||||
m_ptrRoot->Add(rssPath, std::make_shared<CBooleanNode>(ssName, bVal));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CParserTOML::Add(const std::string& rssPath, int64_t iVal)
|
||||
{
|
||||
size_t nOffset = FindLast(rssPath);
|
||||
if (nOffset == std::string::npos)
|
||||
nOffset = 0;
|
||||
else
|
||||
nOffset++;
|
||||
std::string ssName = rssPath.substr(nOffset);
|
||||
|
||||
m_ptrRoot->Add(rssPath, std::make_shared<CIntegerNode>(ssName, iVal));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CParserTOML::Add(const std::string& rssPath, double dVal)
|
||||
{
|
||||
size_t nOffset = FindLast(rssPath);
|
||||
if (nOffset == std::string::npos)
|
||||
nOffset = 0;
|
||||
else
|
||||
nOffset++;
|
||||
std::string ssName = rssPath.substr(nOffset);
|
||||
|
||||
m_ptrRoot->Add(rssPath, std::make_shared<CFloatingPointNode>(ssName, dVal));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CParserTOML::Add(const std::string& rssPath, const std::string& rssVal)
|
||||
{
|
||||
size_t nOffset = FindLast(rssPath);
|
||||
if (nOffset == std::string::npos)
|
||||
nOffset = 0;
|
||||
else
|
||||
nOffset++;
|
||||
std::string ssName = rssPath.substr(nOffset);
|
||||
|
||||
m_ptrRoot->Add(rssPath, std::make_shared<CStringNode>(ssName, rssVal));
|
||||
return true;
|
||||
}
|
||||
|
||||
void CParserTOML::ProcessTable()
|
||||
{
|
||||
// Get the table path (table name preceded by parent tables separated with dots).
|
||||
m_lexer.Consume();
|
||||
std::string ssPath = ComposePath();
|
||||
CLexerTOML::SToken sToken = m_lexer.Consume();
|
||||
if (sToken.eCategory != CLexerTOML::ETokenCategory::token_syntax_table_close)
|
||||
{
|
||||
throw XTOMLParseException("invalid Table construct");
|
||||
}
|
||||
|
||||
// Find the last dot - the name follows
|
||||
size_t nOffset = FindLast(ssPath);
|
||||
if (nOffset == std::string::npos)
|
||||
nOffset = 0; // No dot found, the whole path is one table name
|
||||
else
|
||||
nOffset++; // Skip the dot
|
||||
std::string ssName = ssPath.substr(nOffset);
|
||||
|
||||
// Add the table to the root
|
||||
m_ptrRoot->Add(ssPath, std::make_shared<CNormalTable>(ssName), false);
|
||||
|
||||
m_ssCurrentTable = ssPath;
|
||||
}
|
||||
|
||||
void CParserTOML::ProcessTableArray()
|
||||
{
|
||||
m_lexer.Consume();
|
||||
std::string rssKeyPath = ComposePath();
|
||||
auto ptrNode = m_ptrRoot->Find(rssKeyPath);
|
||||
if (!ptrNode)
|
||||
{
|
||||
Add<CTableArray>(rssKeyPath);
|
||||
ptrNode = m_ptrRoot->Find(rssKeyPath);
|
||||
}
|
||||
if (!ptrNode) return;
|
||||
if (dynamic_cast<CTableArray*>(ptrNode.get()))
|
||||
ptrNode->GetArray()->AddElement(std::make_shared<CNormalTable>(""));
|
||||
else
|
||||
throw XTOMLParseException(("'" + rssKeyPath + "' already defined as a non-table-array").c_str());
|
||||
m_ssCurrentTable = rssKeyPath;
|
||||
|
||||
CLexerTOML::SToken sToken = m_lexer.Consume();
|
||||
if (sToken.eCategory != CLexerTOML::ETokenCategory::token_syntax_table_array_close)
|
||||
{
|
||||
throw XTOMLParseException("invalid Table Array construct");
|
||||
}
|
||||
}
|
||||
|
||||
void CParserTOML::ProcessValueKey()
|
||||
{
|
||||
std::string rssKeyPath = (m_ssCurrentTable.empty() ? "" : (m_ssCurrentTable + ".")) + ComposePath();
|
||||
|
||||
CLexerTOML::SToken sToken = m_lexer.Consume();
|
||||
if (sToken.eCategory != CLexerTOML::ETokenCategory::token_syntax_assignment)
|
||||
{
|
||||
throw XTOMLParseException("Assignment expected");
|
||||
}
|
||||
|
||||
ProcessValue(rssKeyPath);
|
||||
}
|
||||
|
||||
void CParserTOML::ProcessValue(const std::string& rssKeyPath)
|
||||
{
|
||||
CLexerTOML::SToken assignmentValue = m_lexer.Consume();
|
||||
switch (assignmentValue.eCategory)
|
||||
{
|
||||
case CLexerTOML::ETokenCategory::token_boolean:
|
||||
Add(rssKeyPath, assignmentValue.bContentBoolean);
|
||||
break;
|
||||
case CLexerTOML::ETokenCategory::token_integer:
|
||||
Add(rssKeyPath, assignmentValue.iContentInteger);
|
||||
break;
|
||||
case CLexerTOML::ETokenCategory::token_float:
|
||||
Add(rssKeyPath, assignmentValue.dContentFloatingpoint);
|
||||
break;
|
||||
case CLexerTOML::ETokenCategory::token_string:
|
||||
Add(rssKeyPath, assignmentValue.ssContentString);
|
||||
break;
|
||||
case CLexerTOML::ETokenCategory::token_syntax_array_open:
|
||||
Add<CNormalArray>(rssKeyPath);
|
||||
m_stackEnvironment.push(EEnvironment::env_array);
|
||||
ProcessArray(rssKeyPath);
|
||||
m_stackEnvironment.pop();
|
||||
break;
|
||||
case CLexerTOML::ETokenCategory::token_syntax_inline_table_open:
|
||||
Add<CInlineTable>(rssKeyPath);
|
||||
m_stackEnvironment.push(EEnvironment::env_inline_table);
|
||||
ProcessInlineTable(rssKeyPath);
|
||||
m_stackEnvironment.pop();
|
||||
break;
|
||||
default:
|
||||
throw XTOMLParseException("Missing value");
|
||||
break;
|
||||
}
|
||||
|
||||
CLexerTOML::SToken sToken = m_lexer.Peek();
|
||||
if (!m_stackEnvironment.empty())
|
||||
{
|
||||
switch (m_stackEnvironment.top())
|
||||
{
|
||||
case EEnvironment::env_array:
|
||||
{
|
||||
int32_t index = 2;
|
||||
while (sToken.eCategory == CLexerTOML::ETokenCategory::token_syntax_new_line)
|
||||
{
|
||||
sToken = m_lexer.Peek(index++);
|
||||
}
|
||||
if (sToken.eCategory != CLexerTOML::ETokenCategory::token_syntax_comma
|
||||
&& sToken.eCategory != CLexerTOML::ETokenCategory::token_syntax_array_close)
|
||||
{
|
||||
throw XTOMLParseException(
|
||||
"Invalid Token after value assignment in array; ',' or ']' needed");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EEnvironment::env_inline_table:
|
||||
if (sToken.eCategory != CLexerTOML::ETokenCategory::token_syntax_comma
|
||||
&& sToken.eCategory != CLexerTOML::ETokenCategory::token_syntax_inline_table_close)
|
||||
{
|
||||
throw XTOMLParseException(
|
||||
"Invalid Token after value assignment in inline table; ',' or '}' needed ");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sToken.eCategory != CLexerTOML::ETokenCategory::token_syntax_new_line && sToken.eCategory != CLexerTOML::ETokenCategory::token_eof)
|
||||
{
|
||||
throw XTOMLParseException("Invalid Token after value assignment; newline needed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CParserTOML::ProcessArray(const std::string& rssKeyPath)
|
||||
{
|
||||
/*
|
||||
Arrays are defined as follow: array_name = [value, value, ...]
|
||||
Arrays can have new-lines between their values.
|
||||
And can end with a comma.
|
||||
For example:
|
||||
integers = [ 1, 2, 3 ]
|
||||
colors = [ "red", "yellow", "green", ]
|
||||
nested_arrays_of_ints = [ [ 1, 2 ],
|
||||
[3, 4, 5] ]
|
||||
nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ]
|
||||
string_array = [ "all", 'strings', """are the same""", '''type''' ]
|
||||
*/
|
||||
|
||||
CLexerTOML::SToken sToken = m_lexer.Peek();
|
||||
|
||||
size_t nIndex = 0;
|
||||
enum class EExpect {value_comma_end, comma_end} eExpect = EExpect::value_comma_end;
|
||||
while (sToken.eCategory != CLexerTOML::ETokenCategory::token_syntax_array_close)
|
||||
{
|
||||
switch (sToken.eCategory)
|
||||
{
|
||||
//case CLexerTOML::ETokenCategory::token_syntax_array_open: // Embedded array
|
||||
// if (eExpect == comma_end) throw XTOMLParseException("Expecting comma or table end.");
|
||||
// m_lexer.Consume();
|
||||
// ProcessArray(rssKeyPath + "." + std::to_string(nIndex++));
|
||||
// eExpect = comma_end;
|
||||
// break;
|
||||
case CLexerTOML::ETokenCategory::token_syntax_new_line:
|
||||
m_lexer.Consume();
|
||||
break;
|
||||
case CLexerTOML::ETokenCategory::token_syntax_comma:
|
||||
m_lexer.Consume();
|
||||
eExpect = EExpect::value_comma_end;
|
||||
break;
|
||||
default:
|
||||
if (eExpect == EExpect::comma_end)
|
||||
throw XTOMLParseException("Expecting comma or table end.");
|
||||
ProcessValue(rssKeyPath + "." + std::to_string(nIndex++));
|
||||
eExpect = EExpect::comma_end;
|
||||
break;
|
||||
}
|
||||
sToken = m_lexer.Peek();
|
||||
}
|
||||
m_lexer.Consume();
|
||||
}
|
||||
|
||||
void CParserTOML::ProcessInlineTable(const std::string& rssKeyPath)
|
||||
{
|
||||
/*
|
||||
Inline tables are defined as follow: table_name = {value, value, ...}
|
||||
For example:
|
||||
name = { first = "Tom", last = "Preston-Werner" }
|
||||
point = { x = 1, y = 2 }
|
||||
animal = { type.name = "pug" }
|
||||
*/
|
||||
|
||||
CLexerTOML::SToken sToken = m_lexer.Peek();
|
||||
|
||||
std::string ssCurrentTableTemp = m_ssCurrentTable;
|
||||
m_ssCurrentTable = rssKeyPath;
|
||||
enum class EExpect { value_comma_end, value, comma_end } eExpect = EExpect::value_comma_end;
|
||||
while (sToken.eCategory != CLexerTOML::ETokenCategory::token_syntax_inline_table_close)
|
||||
{
|
||||
switch (sToken.eCategory)
|
||||
{
|
||||
case CLexerTOML::ETokenCategory::token_syntax_new_line:
|
||||
throw XTOMLParseException("No newlines allowed in inline table");
|
||||
break;
|
||||
case CLexerTOML::ETokenCategory::token_syntax_comma:
|
||||
if (eExpect == EExpect::value)
|
||||
throw XTOMLParseException("Unexpected comma.");
|
||||
m_lexer.Consume();
|
||||
eExpect = EExpect::value;
|
||||
break;
|
||||
default:
|
||||
if (eExpect == EExpect::comma_end)
|
||||
throw XTOMLParseException("Expecting comma or table end.");
|
||||
ProcessValueKey();
|
||||
eExpect = EExpect::comma_end;
|
||||
break;
|
||||
}
|
||||
sToken = m_lexer.Peek();
|
||||
}
|
||||
if (eExpect == EExpect::value)
|
||||
throw XTOMLParseException("Expecting a value before inline table end.");
|
||||
|
||||
m_ptrRoot->Find(rssKeyPath)->GetTable()->m_bOpenToAddChildren = false;
|
||||
|
||||
m_lexer.Consume();
|
||||
m_ssCurrentTable = ssCurrentTableTemp;
|
||||
}
|
||||
|
||||
std::string CParserTOML::ComposePath()
|
||||
{
|
||||
std::string ssPath;
|
||||
CLexerTOML::SToken sToken = m_lexer.Peek();
|
||||
if (sToken.eCategory != CLexerTOML::ETokenCategory::token_syntax_dot
|
||||
&& sToken.eCategory != CLexerTOML::ETokenCategory::token_key)
|
||||
throw XTOMLParseException("Invalid Token to assemble path from keys");
|
||||
|
||||
while (sToken.eCategory == CLexerTOML::ETokenCategory::token_syntax_dot
|
||||
|| sToken.eCategory == CLexerTOML::ETokenCategory::token_key)
|
||||
{
|
||||
m_lexer.Consume();
|
||||
if (sToken.eCategory == CLexerTOML::ETokenCategory::token_key)
|
||||
ssPath += sToken.ssContentString;
|
||||
else
|
||||
ssPath += ".";
|
||||
sToken = m_lexer.Peek();
|
||||
}
|
||||
return ssPath;
|
||||
}
|
||||
|
||||
173
sdv_services/core/toml_parser/parser_toml.h
Normal file
173
sdv_services/core/toml_parser/parser_toml.h
Normal file
@@ -0,0 +1,173 @@
|
||||
#ifndef PARSER_TOML_H
|
||||
#define PARSER_TOML_H
|
||||
|
||||
#include "lexer_toml.h"
|
||||
#include "parser_node_toml.h"
|
||||
|
||||
/**
|
||||
* @brief Creates a tree structure from input of UTF-8 encoded TOML source data
|
||||
*/
|
||||
class CParserTOML : public sdv::IInterfaceAccess, public sdv::toml::ITOMLParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
CParserTOML() = default;
|
||||
|
||||
/**
|
||||
* @brief Construct a new Parser object
|
||||
* @param[in] rssString UTF-8 encoded data of a TOML source
|
||||
*/
|
||||
CParserTOML(const std::string& rssString);
|
||||
|
||||
// Interface map
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(sdv::toml::ITOMLParser)
|
||||
SDV_INTERFACE_CHAIN_MEMBER(m_ptrRoot)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
* @brief Clears the current parse result.
|
||||
* @attention This will render any pointer invalid!
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
// Ignore cppcheck warning for not using dynamic binding when being called through the constructor.
|
||||
// cppcheck-suppress virtualCallInConstructor
|
||||
/**
|
||||
* @brief Process the configuration from the supplied content string. Overload of sdv::toml::ITOMLParser.
|
||||
* @param[in] ssContent Configuration string.
|
||||
* @return Returns 'true' when the configuration could be read successfully, false when not.
|
||||
*/
|
||||
virtual bool Process(/*in*/ const sdv::u8string& ssContent) override;
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Return the root node.
|
||||
* @return Reference to the root node collection.
|
||||
*/
|
||||
const CNodeCollection& GetRoot() const;
|
||||
CNodeCollection& GetRoot();
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get the TOML text based on the content.
|
||||
* @param[in] rssParent When present, uses the parent node into the TOML text generation.
|
||||
* @return The string containing the TOML text.
|
||||
*/
|
||||
std::string CreateTOMLText(const std::string& rssParent = std::string()) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Add a collection node (table or array).
|
||||
* @tparam TCollectionNode The collection node class to add (to create).
|
||||
* @param[in] rssPath Reference to the node path.
|
||||
* @return Returns whether the node could be added.
|
||||
*/
|
||||
template <class TCollectionNode>
|
||||
bool Add(const std::string& rssPath);
|
||||
|
||||
/**
|
||||
* @brief Add a boolean value node.
|
||||
* @param[in] rssPath Reference to the node path.
|
||||
* @param[in] bVal The boolean value.
|
||||
* @return Returns whether the node could be added.
|
||||
*/
|
||||
bool Add(const std::string& rssPath, bool bVal);
|
||||
|
||||
/**
|
||||
* @brief Add a integer value node.
|
||||
* @param[in] rssPath Reference to the node path.
|
||||
* @param[in] iVal The integer value.
|
||||
* @return Returns whether the node could be added.
|
||||
*/
|
||||
bool Add(const std::string& rssPath, int64_t iVal);
|
||||
|
||||
/**
|
||||
* @brief Add a floating point value node.
|
||||
* @param[in] rssPath Reference to the node path.
|
||||
* @param[in] dVal The floating point value.
|
||||
* @return Returns whether the node could be added.
|
||||
*/
|
||||
bool Add(const std::string& rssPath, double dVal);
|
||||
|
||||
/**
|
||||
* @brief Add a string value node.
|
||||
* @param[in] rssPath Reference to the node path.
|
||||
* @param[in] rssVal Reference to the string value.
|
||||
* @return Returns whether the node could be added.
|
||||
*/
|
||||
bool Add(const std::string& rssPath, const std::string& rssVal);
|
||||
|
||||
/**
|
||||
* @brief Process a table declaration.
|
||||
*/
|
||||
void ProcessTable();
|
||||
|
||||
/**
|
||||
* @brief Process a table array declaration.
|
||||
*/
|
||||
void ProcessTableArray();
|
||||
|
||||
/**
|
||||
* @brief Process the value key.
|
||||
*/
|
||||
void ProcessValueKey();
|
||||
|
||||
/**
|
||||
* @brief Process the value with the supplied key.
|
||||
* @param[in] rssKeyPath Reference to the key path string.
|
||||
*/
|
||||
void ProcessValue(const std::string& rssKeyPath);
|
||||
|
||||
/**
|
||||
* @brief Process the array value with the supplied key.
|
||||
* @param[in] rssKeyPath Reference to the key path string.
|
||||
*/
|
||||
void ProcessArray(const std::string& rssKeyPath);
|
||||
|
||||
/**
|
||||
* @brief Process the inline table value with the supplied key.
|
||||
* @param[in] rssKeyPath Reference to the key path string.
|
||||
*/
|
||||
void ProcessInlineTable(const std::string& rssKeyPath);
|
||||
|
||||
/**
|
||||
* @brief Compose a path from lexer tokens. A path is composed of table and array elements separated with a dot.
|
||||
* @return The composed path.
|
||||
*/
|
||||
std::string ComposePath();
|
||||
|
||||
/**
|
||||
* @brief Enum for differentiating between an array environment and an inline table environment for syntax checks.
|
||||
*/
|
||||
enum class EEnvironment
|
||||
{
|
||||
env_array, //!< Environment for an array
|
||||
env_inline_table //!< Environment for a table
|
||||
};
|
||||
std::stack<EEnvironment> m_stackEnvironment; ///< Tracking of environments in nested structures.
|
||||
std::shared_ptr<CNode> m_ptrRoot = std::make_shared<CRootTable>(); ///< The one root node.
|
||||
std::string m_ssCurrentTable; ///< Path to the current table.
|
||||
CLexerTOML m_lexer; ///< Lexer.
|
||||
};
|
||||
|
||||
template <class TCollectionNode>
|
||||
inline bool CParserTOML::Add(const std::string& rssPath)
|
||||
{
|
||||
size_t nOffset = rssPath.rfind('.');
|
||||
if (nOffset == std::string::npos)
|
||||
nOffset = 0;
|
||||
else
|
||||
nOffset++;
|
||||
std::string ssName = rssPath.substr(nOffset);
|
||||
|
||||
m_ptrRoot->Add(rssPath, std::make_shared<TCollectionNode>(ssName), true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // PARSER_TOML_H
|
||||
Reference in New Issue
Block a user