mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-07-02 05:35:11 +00:00
Update sdv_packager (#6)
This commit is contained in:
@@ -1,3 +1,17 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Stimpfl - initial API and implementation
|
||||
* Erik Verhoeven - writing TOML and whitespace preservation
|
||||
********************************************************************************/
|
||||
|
||||
#include "character_reader_utf_8.h"
|
||||
#include "exception.h"
|
||||
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Stimpfl - initial API and implementation
|
||||
* Erik Verhoeven - writing TOML and whitespace preservation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef CHARACTER_READER_UTF_8_H
|
||||
#define CHARACTER_READER_UTF_8_H
|
||||
|
||||
|
||||
425
sdv_services/core/toml_parser/code_snippet.cpp
Normal file
425
sdv_services/core/toml_parser/code_snippet.cpp
Normal file
@@ -0,0 +1,425 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Erik Verhoeven - initial API and implementation
|
||||
********************************************************************************/
|
||||
|
||||
#include "code_snippet.h"
|
||||
#include "parser_node_toml.h"
|
||||
|
||||
/// The TOML parser namespace
|
||||
namespace toml_parser
|
||||
{
|
||||
void CCodeSnippet::SetTokenList(const std::list<CToken>& rlstTokens)
|
||||
{
|
||||
m_lstTokens = rlstTokens;
|
||||
m_bUseDefault = false;
|
||||
}
|
||||
|
||||
void CCodeSnippet::SetTokenList(std::list<CToken>&& rlstTokens)
|
||||
{
|
||||
m_lstTokens = std::move(rlstTokens);
|
||||
m_bUseDefault = false;
|
||||
}
|
||||
|
||||
std::string CCodeSnippet::Compose(EComposeMode eMode, const CGenContext& rContext, size_t nAssignmentOffset /*= 0*/,
|
||||
size_t nCommentOffset /*= 0*/) const
|
||||
{
|
||||
// Build the stream until the first comment.
|
||||
std::stringstream sstream;
|
||||
TTokenListIterator it = m_lstTokens.begin();
|
||||
bool bCommaAvailable = false;
|
||||
bool bPrintableCharsAvailable = false;
|
||||
bool bLastTokenIsComment = false;
|
||||
while (it != m_lstTokens.end() && it->Category() != ETokenCategory::token_comment)
|
||||
{
|
||||
// Add comma only when needed.
|
||||
bool bSkip = false;
|
||||
switch (it->Category())
|
||||
{
|
||||
case ETokenCategory::token_syntax_comma:
|
||||
if (eMode != EComposeMode::compose_behind || !rContext.CommaNeeded() || bCommaAvailable)
|
||||
{
|
||||
bSkip = true;
|
||||
break; // Only when placed behind a node
|
||||
}
|
||||
bCommaAvailable = true;
|
||||
break;
|
||||
case ETokenCategory::token_comment:
|
||||
bSkip = !rContext.CommentAndNewlineAllowed();
|
||||
if (!bSkip) bLastTokenIsComment = true;
|
||||
break;
|
||||
case ETokenCategory::token_syntax_new_line:
|
||||
bSkip = !rContext.NewlineAllowed();
|
||||
if (!bSkip) bLastTokenIsComment = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!bSkip)
|
||||
{
|
||||
sstream << it->RawString();
|
||||
bPrintableCharsAvailable = true;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
// Determine the last comment.
|
||||
TTokenListIterator itFirstComment = it;
|
||||
TTokenListIterator itLastComment = it;
|
||||
while (it != m_lstTokens.end())
|
||||
{
|
||||
if (it->Category() == ETokenCategory::token_comment)
|
||||
itLastComment = it;
|
||||
++it;
|
||||
}
|
||||
|
||||
// Determine the code behind the last comment (and the obligatory newline).
|
||||
TTokenListIterator itPostComment = itLastComment;
|
||||
if (itPostComment != m_lstTokens.end())
|
||||
++itPostComment;
|
||||
if (itPostComment != m_lstTokens.end() && itPostComment->Category() == ETokenCategory::token_syntax_new_line)
|
||||
++itPostComment;
|
||||
|
||||
// Stream the comment
|
||||
if (!m_bCommentReplaced)
|
||||
{
|
||||
for (it = itFirstComment; it != itPostComment; ++it)
|
||||
{
|
||||
// Add comma only when needed.
|
||||
bool bSkip = false;
|
||||
switch (it->Category())
|
||||
{
|
||||
case ETokenCategory::token_syntax_comma:
|
||||
if (eMode != EComposeMode::compose_behind || !rContext.CommaNeeded() || bCommaAvailable)
|
||||
{
|
||||
bSkip = true;
|
||||
break; // Only when placed behind a node
|
||||
}
|
||||
bCommaAvailable = true;
|
||||
break;
|
||||
case ETokenCategory::token_comment:
|
||||
bSkip = !rContext.CommentAndNewlineAllowed();
|
||||
if (!bSkip) bLastTokenIsComment = true;
|
||||
break;
|
||||
case ETokenCategory::token_syntax_new_line:
|
||||
bSkip = !rContext.NewlineAllowed();
|
||||
if (!bSkip) bLastTokenIsComment = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!bSkip)
|
||||
{
|
||||
sstream << it->RawString();
|
||||
bPrintableCharsAvailable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (eMode)
|
||||
{
|
||||
case EComposeMode::compose_inline:
|
||||
case EComposeMode::compose_behind:
|
||||
if (itFirstComment == m_lstTokens.end() && !m_ssComment.empty())
|
||||
sstream << " ";
|
||||
break;
|
||||
case EComposeMode::compose_standalone_behind:
|
||||
if (itFirstComment == m_lstTokens.end() && !m_ssComment.empty())
|
||||
sstream << std::endl;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// TODO: Align the comment....
|
||||
size_t nPos = 0;
|
||||
bool bEmptyLine = false;
|
||||
while (nPos != std::string::npos)
|
||||
{
|
||||
// Find the chunk until the next newline or the end of the string
|
||||
size_t nNextPos = m_ssComment.find('\n', nPos);
|
||||
if (nNextPos != std::string::npos) nNextPos++;
|
||||
if (nNextPos >= m_ssComment.size()) nNextPos = std::string::npos;
|
||||
std::string ssChunk = m_ssComment.substr(nPos, nNextPos);
|
||||
nPos = nNextPos;
|
||||
|
||||
// Insert an extra line break, but only when there isn't a line-break already...
|
||||
if (!bEmptyLine && !sstream.str().empty())
|
||||
{
|
||||
switch (eMode)
|
||||
{
|
||||
case EComposeMode::compose_before:
|
||||
case EComposeMode::compose_behind:
|
||||
case EComposeMode::compose_inline:
|
||||
sstream << std::string(nCommentOffset, ' ') << "#";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sstream << std::endl;
|
||||
}
|
||||
|
||||
if (ssChunk.find_first_not_of("\r\n") == std::string::npos)
|
||||
bEmptyLine = true;
|
||||
else
|
||||
{
|
||||
sstream << std::string(nCommentOffset, ' ') << "# " << ssChunk;
|
||||
if (ssChunk.find('\n') == std::string::npos)
|
||||
sstream << std::endl; // Comment is always followed by a newline.
|
||||
bEmptyLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add spaces for next assignment
|
||||
switch (eMode)
|
||||
{
|
||||
case EComposeMode::compose_inline:
|
||||
if (itPostComment == m_lstTokens.end() && nAssignmentOffset)
|
||||
sstream << std::string(nAssignmentOffset, ' ');
|
||||
break;
|
||||
case EComposeMode::compose_standalone_before:
|
||||
if (itFirstComment == m_lstTokens.end() && !m_ssComment.empty())
|
||||
sstream << std::endl;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Stream the rest of the tokens
|
||||
for (it = itPostComment; it != m_lstTokens.end(); ++it)
|
||||
{
|
||||
bool bSkip = false;
|
||||
switch (it->Category())
|
||||
{
|
||||
case ETokenCategory::token_syntax_comma:
|
||||
if (eMode != EComposeMode::compose_behind || !rContext.CommaNeeded() || bCommaAvailable)
|
||||
{
|
||||
bSkip = true;
|
||||
break; // Only when placed behind a node
|
||||
}
|
||||
bCommaAvailable = true;
|
||||
break;
|
||||
case ETokenCategory::token_comment:
|
||||
bSkip = !rContext.CommentAndNewlineAllowed();
|
||||
if (!bSkip) bLastTokenIsComment = true;
|
||||
break;
|
||||
case ETokenCategory::token_syntax_new_line:
|
||||
bSkip = !rContext.NewlineAllowed();
|
||||
if (!bSkip) bLastTokenIsComment = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!bSkip)
|
||||
{
|
||||
sstream << it->RawString();
|
||||
bPrintableCharsAvailable = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Post processing
|
||||
switch (eMode)
|
||||
{
|
||||
case EComposeMode::compose_behind:
|
||||
// Was a comma provided?
|
||||
if (!bCommaAvailable && rContext.CommaNeeded())
|
||||
{
|
||||
std::string ssTemp = sstream.str();
|
||||
ssTemp.insert(0, bPrintableCharsAvailable ? "," : ", ");
|
||||
sstream.str(ssTemp);
|
||||
}
|
||||
|
||||
// Default newline needed
|
||||
if (rContext.FinalNewline() && ((m_lstTokens.empty() && m_ssComment.empty()) || bLastTokenIsComment))
|
||||
sstream << std::endl;
|
||||
break;
|
||||
case EComposeMode::compose_before:
|
||||
//if (!bPrintableCharsAvailable && rContext.Embedded())
|
||||
// sstream << " ";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
std::string CCodeSnippet::GetComment() const
|
||||
{
|
||||
if (m_bCommentReplaced)
|
||||
return m_ssComment;
|
||||
|
||||
std::stringstream sstream;
|
||||
size_t nNewLineCount = 0;
|
||||
for (const CToken& rToken : m_lstTokens)
|
||||
{
|
||||
// Deal with new line.
|
||||
if (rToken.Category() == ETokenCategory::token_syntax_new_line)
|
||||
{
|
||||
if (sstream.str().empty())
|
||||
continue;
|
||||
nNewLineCount++;
|
||||
if (nNewLineCount < 2)
|
||||
continue;
|
||||
sstream << std::endl;
|
||||
continue;
|
||||
}
|
||||
if (rToken.Category() == ETokenCategory::token_whitespace)
|
||||
continue;
|
||||
nNewLineCount = 0;
|
||||
if (rToken.Category() == toml_parser::ETokenCategory::token_comment && !rToken.RawString().empty()
|
||||
&& rToken.RawString()[0] == '#')
|
||||
{
|
||||
// The comment doesn't have a newline inside the comment text. This allows us to glue multiple comments to one
|
||||
// large string.
|
||||
// A new line will be inserted on the following conditions:
|
||||
// - the line starts as comment, but only has whitespace.
|
||||
// - there are at least some characters in the stream already.
|
||||
// - the comment starts with a tab or multiple spaces
|
||||
if (rToken.RawString().size() <= 1 || rToken.RawString().find_first_not_of(" \t", 1) == std::string::npos)
|
||||
{
|
||||
// Line has only whitespace
|
||||
sstream << std::endl;
|
||||
continue;
|
||||
}
|
||||
if (rToken.RawString()[1] == '\t' || rToken.RawString().substr(1, 2) == " "
|
||||
|| rToken.RawString().substr(1, 2) == " \t")
|
||||
{
|
||||
// Line starts with a tab, are there any characters in the stream already.
|
||||
if (!sstream.str().empty())
|
||||
sstream << std::endl;
|
||||
sstream << rToken.RawString().substr(1);
|
||||
continue;
|
||||
}
|
||||
size_t nStartComment = rToken.RawString()[1] == ' ' ? 2 : 1;
|
||||
if (!sstream.str().empty())
|
||||
{
|
||||
// The stream is not empty. Are there extra spaces (indicating a list or so)
|
||||
if (rToken.RawString().substr(1, 2) == " ")
|
||||
sstream << std::endl;
|
||||
else // No newline, but space?
|
||||
if (!std::isspace(sstream.str().back()))
|
||||
sstream << " ";
|
||||
}
|
||||
|
||||
// Add the content to the stream
|
||||
sstream << rToken.RawString().substr(nStartComment);
|
||||
}
|
||||
}
|
||||
|
||||
// Trim space at the end of the string
|
||||
std::string ssResult = sstream.str();
|
||||
while (!ssResult.empty() && std::isspace(ssResult.back()))
|
||||
ssResult.pop_back();
|
||||
return ssResult;
|
||||
}
|
||||
|
||||
void CCodeSnippet::SetComment(const std::string& rssComment)
|
||||
{
|
||||
// Just store the string. Further processing is done in the compose function.
|
||||
m_ssComment = rssComment;
|
||||
m_bCommentReplaced = true;
|
||||
m_bUseDefault = false;
|
||||
}
|
||||
|
||||
void CCodeSnippet::Clear()
|
||||
{
|
||||
m_ssComment.clear();
|
||||
m_lstTokens.clear();
|
||||
m_bCommentReplaced = false;
|
||||
m_bUseDefault = true;
|
||||
}
|
||||
|
||||
bool CCodeSnippet::HasCode() const
|
||||
{
|
||||
return !m_bUseDefault || (m_bCommentReplaced || !m_lstTokens.empty());
|
||||
}
|
||||
|
||||
void CCodeSnippet::RemoveFormat()
|
||||
{
|
||||
// Read the comment from the token list.
|
||||
if (!m_bCommentReplaced && !m_lstTokens.empty())
|
||||
{
|
||||
m_ssComment = GetComment();
|
||||
m_bCommentReplaced = !m_ssComment.empty();
|
||||
}
|
||||
|
||||
// Clear the token list
|
||||
m_lstTokens.clear();
|
||||
|
||||
m_bUseDefault = !m_bCommentReplaced;
|
||||
}
|
||||
|
||||
bool CCodeSnippet::HasComma() const
|
||||
{
|
||||
return !m_bCommentReplaced && (std::find_if(m_lstTokens.begin(), m_lstTokens.end(),
|
||||
[](const CToken& rToken) { return rToken.Category() == ETokenCategory::token_syntax_comma; }) != m_lstTokens.end());
|
||||
}
|
||||
|
||||
void CCodeSnippet::Insert(const CCodeSnippet& rCode)
|
||||
{
|
||||
// Something to do?
|
||||
if (!rCode.HasCode()) return;
|
||||
|
||||
// Simple assignment?
|
||||
if (!HasCode())
|
||||
{
|
||||
m_bCommentReplaced = rCode.m_bCommentReplaced;
|
||||
m_ssComment = rCode.m_ssComment;
|
||||
m_lstTokens = rCode.m_lstTokens;
|
||||
return;
|
||||
}
|
||||
|
||||
// Differentiate between comment text or token lists.
|
||||
if (m_bCommentReplaced)
|
||||
m_ssComment.insert(0, rCode.GetComment());
|
||||
else
|
||||
{
|
||||
if (rCode.m_bCommentReplaced)
|
||||
{
|
||||
m_ssComment = rCode.GetComment() + GetComment();
|
||||
m_bCommentReplaced = true;
|
||||
}
|
||||
else
|
||||
m_lstTokens.insert(m_lstTokens.begin(), rCode.m_lstTokens.begin(), rCode.m_lstTokens.end());
|
||||
}
|
||||
}
|
||||
|
||||
void CCodeSnippet::Append(const CCodeSnippet& rCode)
|
||||
{
|
||||
// Something to do?
|
||||
if (!rCode.HasCode()) return;
|
||||
|
||||
// Simple assignment?
|
||||
if (!HasCode())
|
||||
{
|
||||
m_bCommentReplaced = rCode.m_bCommentReplaced;
|
||||
m_ssComment = rCode.m_ssComment;
|
||||
m_lstTokens = rCode.m_lstTokens;
|
||||
return;
|
||||
}
|
||||
|
||||
// Differentiate between comment text or token lists.
|
||||
if (m_bCommentReplaced)
|
||||
m_ssComment.append(rCode.GetComment());
|
||||
else
|
||||
{
|
||||
if (rCode.m_bCommentReplaced)
|
||||
{
|
||||
m_ssComment = rCode.GetComment() + GetComment();
|
||||
m_bCommentReplaced = true;
|
||||
}
|
||||
else
|
||||
m_lstTokens.insert(m_lstTokens.end(), rCode.m_lstTokens.begin(), rCode.m_lstTokens.end());
|
||||
}
|
||||
}
|
||||
} // namespace toml_parser
|
||||
220
sdv_services/core/toml_parser/code_snippet.h
Normal file
220
sdv_services/core/toml_parser/code_snippet.h
Normal file
@@ -0,0 +1,220 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Erik Verhoeven - initial API and implementation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef CODE_SNIPPET_H
|
||||
#define CODE_SNIPPET_H
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <interfaces/toml.h>
|
||||
#include "lexer_toml.h"
|
||||
|
||||
/// The TOML parser namespace
|
||||
namespace toml_parser
|
||||
{
|
||||
// Forward declaration
|
||||
class CGenContext;
|
||||
|
||||
/**
|
||||
* @brief Comment or code snippet structure.
|
||||
* @details Each node has multiple code snippets used to reproduce the exact code. For example with an assignment:
|
||||
* @code
|
||||
*
|
||||
* # This is out of scope comment before
|
||||
*
|
||||
* # This is comment before
|
||||
* var_a = "abc" # comment behind
|
||||
* # more comment behind
|
||||
*
|
||||
* # This is out of scope comment behind
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* The code snippets are identified as follows:
|
||||
* @code
|
||||
* <out of scope comment before>
|
||||
* <comment before>
|
||||
* <space before><key><space>=<space><value><comment behind>
|
||||
* <out of scope comment behind>
|
||||
* @endcode
|
||||
*
|
||||
* Each code snippet has token a list and comment string.
|
||||
* - If the tokenlist is not empty and comment string is empty, the tokenlist determines the comment.
|
||||
* - If the tokenlist is empty, the comment string determines the comment. The following steps are taken during the
|
||||
* GetComment with the raw flag enabled:
|
||||
* - For the comment behind, the current position for the comment is determined by examining the length of the sibling
|
||||
* nodes. If the position is larger than 80, the start position is either 80 or one space character more than the
|
||||
* node length.
|
||||
* - For all other comment types, the start position is zero.
|
||||
* - Stream spaces until the start position is reached; then stream the comment character '#' followed by a space.
|
||||
* - The comment text is streamed word by word. If between the words a space exists, this can be replaced by a
|
||||
* newline when the current position with the new word would exceed column 132. After the new line spaces fill up
|
||||
* until the start position. Then the comment character and a space is streamed followed by more words from the
|
||||
* comment.
|
||||
* - If within the comment a newline is available, this is followed by an additional newline within the raw comment
|
||||
* stream. Also if multiple empty lines occur (lines with no character sor only whitespace), this is also
|
||||
* streamed with one additional newline at the beginning.
|
||||
* - The last word is followed by a newline.
|
||||
* - If tokenlist is not empty and comment string is not empty, the comments plus the newline following within the
|
||||
* tokenlist are replaced by the new comment text like described above, with the exception that the start position is
|
||||
* determined by the current position within the tokenlist.
|
||||
*/
|
||||
class CCodeSnippet
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Set the token list containing the code for this code snippet.
|
||||
* @param[in] rlstTokens Reference to the token list to be set.
|
||||
*/
|
||||
void SetTokenList(const std::list<CToken>& rlstTokens);
|
||||
|
||||
/**
|
||||
* @brief Set the token list containing the code for this code snippet.
|
||||
* @param[in] rlstTokens Reference to the token list to be set.
|
||||
*/
|
||||
void SetTokenList(std::list<CToken>&& rlstTokens);
|
||||
|
||||
/**
|
||||
* @brief Mode the code snippet composer should run in.
|
||||
*/
|
||||
enum class EComposeMode
|
||||
{
|
||||
compose_inline, ///< Compose as inline whitespace and comment. If there is no token list and no comment
|
||||
///< string, compose as one space. If there is only a comment string, insert a space, add
|
||||
///< the comment followed by an obligatory newline, and insert spaces until the next
|
||||
///< provided position. If there are tokens with a comment token, replace the comment. If
|
||||
///< there are tokens without comment, add the comment, newline and spaces.
|
||||
compose_before, ///< Compose as comment assigned to and located before the node. If there is no token list
|
||||
///< and no comment string, doesn't add anything. If there is only a comment string, adds
|
||||
///< the comment followed by the obligatory newline. If there are tokens with a comment
|
||||
///< token, replace the comment. If there are tokens without the comment, place the comment
|
||||
///< before the last newline or when not available, at the end of the tokens followed by a
|
||||
///< new newline.
|
||||
compose_behind, ///< Compose as comment assigned to and located behind the node. If there is no token list
|
||||
///< and no comment string, add a newline. If there is a comment string and no tokens,
|
||||
///< add a space, the comment string followed by the obligatory newline. If there is a token
|
||||
///< list without comment, add a comment before the newline or at the end with an additional
|
||||
///< newline.
|
||||
compose_standalone_before, ///< Compose as stand-alone comment before the node. Replace any token list if a comment
|
||||
///< string is available.
|
||||
compose_standalone_behind, ///< Compose as stand-alone comment behind the node. Replace any token list if a comment
|
||||
///< string is available.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compose a conde string from the stored tokens and/or string.
|
||||
* @details The comment text to code translation is as follows:
|
||||
* @code
|
||||
* The following text might be split into multiple TOML comment lines.
|
||||
* @endcode
|
||||
* @code
|
||||
* # The following text might be split into
|
||||
* # multiple TOML comment lines.
|
||||
* @endcode
|
||||
* and
|
||||
* @code
|
||||
* This is part 1 of a text which will be as two separated blocks.
|
||||
* This is part 2 of a text which will be as two separated blocks.
|
||||
* @endcode
|
||||
* @code
|
||||
* # This is part 1 of a text which will be as
|
||||
* # two separated blocks.
|
||||
* #
|
||||
* # This is part 2 of a text which will be as
|
||||
* # two separated blocks.
|
||||
* @endcode
|
||||
* and
|
||||
* @code
|
||||
* This is a list or an indented text, which is streated as a list.
|
||||
* First indented text which belongs as a separated line.
|
||||
* Second indented text which belongs as a separate line.
|
||||
* @endcode
|
||||
* @code
|
||||
* # This is a list or an indented text, which is
|
||||
* # streated as a list.
|
||||
* # First indented text which belongs as a
|
||||
* # separated line.
|
||||
* # Second indented text which belongs as a
|
||||
* # separate line.
|
||||
* @endcode
|
||||
* @param[in] eMode The mode the composer should run in.
|
||||
* @param[in] rContext Reference to the node context used for the code generation.
|
||||
* @param[in] nAssignmentOffset The offset for a next assignent; only used for inline composition.
|
||||
* @param[in] nCommentOffset The offset to insert a multi-line comment; only used for inline and behind composition.
|
||||
* @return The composed code string.
|
||||
*/
|
||||
std::string Compose(EComposeMode eMode, const CGenContext& rContext, size_t nAssignmentOffset = 0, size_t nCommentOffset = 0) const;
|
||||
|
||||
/**
|
||||
* @brief Get the stored comment from the code snippet. A stored comment string supersedes a comment string from the
|
||||
* token list. Comment lines that belong together are combined together as a text without line-breaks.
|
||||
* @return Returns the stored comment string.
|
||||
*/
|
||||
std::string GetComment() const;
|
||||
|
||||
/**
|
||||
* @brief Set a comment string. The comment will be formatted in the compose function. Lines that should stay together
|
||||
* should not be separated by a line-break. Comments should be provided without the TOML comment character '#'.
|
||||
* @param[in] rssComment Reference to the string containing the comment text.
|
||||
*/
|
||||
void SetComment(const std::string& rssComment);
|
||||
|
||||
/**
|
||||
* @brief Remove the content of the code snippet.
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
/**
|
||||
* @brief Does the snippet contain code?
|
||||
* @return Returns whether the snippet has code or not.
|
||||
*/
|
||||
bool HasCode() const;
|
||||
|
||||
/**
|
||||
* @brief This function will remove the formatting from the code.
|
||||
*/
|
||||
void RemoveFormat();
|
||||
|
||||
/**
|
||||
* @brief Does the code snippet have a comma in the token list?
|
||||
* @return Returns whether the token list is active and contains a comma token.
|
||||
*/
|
||||
bool HasComma() const;
|
||||
|
||||
/**
|
||||
* @brief Insert a code snippet before the existing comment.
|
||||
* @remarks In case the code has been replaced by a comment text of the current or the to be inserted code snippet, the
|
||||
* result will be a combined comment text, disregarding the format.
|
||||
* @param[in] rCode Reference to the code snippet to insert before the current code.
|
||||
*/
|
||||
void Insert(const CCodeSnippet& rCode);
|
||||
|
||||
/**
|
||||
* @brief Append a code snippet behind the existing comment.
|
||||
* @remarks In case the code has been replaced by a comment text of the current or the to be inserted code snippet, the
|
||||
* result will be a combined comment text, disregarding the format.
|
||||
* @param[in] rCode Reference to the code snippet to appended behind the current code.
|
||||
*/
|
||||
void Append(const CCodeSnippet& rCode);
|
||||
|
||||
private:
|
||||
std::list<CToken> m_lstTokens; ///< Token list for the code snippet in raw format.
|
||||
std::string m_ssComment; ///< The comment text for the code snippet in text format.
|
||||
bool m_bCommentReplaced = false; ///< Comment replaced with SetComment function.
|
||||
bool m_bUseDefault = false; ///< When set, the format was removed from the code.
|
||||
};
|
||||
} // namespace toml_parser
|
||||
|
||||
#endif // !defined CODE_SNIPPET_H
|
||||
@@ -1,3 +1,17 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Stimpfl - initial API and implementation
|
||||
* Erik Verhoeven - writing TOML and whitespace preservation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef CONFIG_EXCEPTION_H
|
||||
#define CONFIG_EXCEPTION_H
|
||||
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Stimpfl - initial API and implementation
|
||||
* Erik Verhoeven - writing TOML and whitespace preservation
|
||||
********************************************************************************/
|
||||
|
||||
#include "lexer_toml.h"
|
||||
#include <interfaces/toml.h>
|
||||
#include "exception.h"
|
||||
@@ -176,7 +190,15 @@ namespace toml_parser
|
||||
}
|
||||
}
|
||||
|
||||
void CLexer::Reset()
|
||||
void CLexer::Clear()
|
||||
{
|
||||
m_lstTokens.clear();
|
||||
m_itCursor = m_lstTokens.end();
|
||||
while (!m_stackExpectations.empty())
|
||||
m_stackExpectations.pop();
|
||||
}
|
||||
|
||||
void CLexer::ResetCursor()
|
||||
{
|
||||
m_itCursor = m_lstTokens.begin();
|
||||
}
|
||||
@@ -275,6 +297,54 @@ namespace toml_parser
|
||||
|
||||
void CLexer::SmartExtendNodeRange(CNodeTokenRange& rTokenRange) const
|
||||
{
|
||||
/*
|
||||
Consider the following TOML code:
|
||||
|
||||
# Out of scope comment
|
||||
|
||||
|
||||
# Pre comment with spaces before
|
||||
# Pre comment
|
||||
[table] # Post comment
|
||||
# Post comment without indentation
|
||||
|
||||
|
||||
# Out of scope comment
|
||||
|
||||
# Pre comment
|
||||
var = "1234" # Post comment
|
||||
# More post comment with indentation
|
||||
# Pre comment of var2 due to indentation identical or smaller then var2 def indentation
|
||||
var2 = "5678"
|
||||
# Pre comment of var3
|
||||
var3 = 9012 # Post comment of var3
|
||||
# More post comment of var3 (due ot space at the beginning)
|
||||
# Pre comment of var4 due to lesser indentation
|
||||
# Pre comment of var4 due to previous pre comment
|
||||
# Pre comment of var4
|
||||
var4 = 3456
|
||||
# Out of scope comment due to missing post comment at same line as defintion
|
||||
|
||||
var5 = [ 8765, # Post comment for var5[0] (event behind the comma)
|
||||
# Pre comment for var[1]
|
||||
4321 ] # Post comment for var5
|
||||
|
||||
var6 = 7890 # Post comment of var6
|
||||
# Out of scope comment due to missing indentation
|
||||
|
||||
--------------------------------------------
|
||||
The function uses as input the token range of the definition and extends the definition with comments and whitespace that
|
||||
belong to the definition. Therefore the following rules count:
|
||||
- Pre comments are defined on the lines before if they are covering the complete line and do not have an indentation larger
|
||||
than the indentation of the definition.
|
||||
- Post comments are defined at the same line following the definition.
|
||||
- If a comment with indentation is supplied before the definition, it is a pre-comment if there is no post-comment defined
|
||||
that connects to this comment. Otherwise the comment belongs to the definition before.
|
||||
- If comments follow on the lines directly behind the definition, they are post-comments when the comment has started at
|
||||
the same line as the definition and each comment has an indentation larger than the indentation of the next definition.
|
||||
- The extended range always includes the complete line including the indentation before and the line-break behind.
|
||||
*/
|
||||
|
||||
// Define an iterator range type.
|
||||
using TRange = std::pair<TTokenListIterator, TTokenListIterator>;
|
||||
|
||||
@@ -285,7 +355,7 @@ namespace toml_parser
|
||||
// return A pair containing the begin and one past the end of the line.
|
||||
auto fnGetLine = [this](const TTokenListIterator& rit) -> TRange
|
||||
{
|
||||
// When the end of the list is reached, there is no more line.
|
||||
// When the end of the list is reached, there are no more tokens in the line.
|
||||
if (rit == m_lstTokens.end())
|
||||
return std::make_pair(m_lstTokens.end(), m_lstTokens.end());
|
||||
|
||||
@@ -392,6 +462,26 @@ namespace toml_parser
|
||||
return bComments;
|
||||
};
|
||||
|
||||
// Check a range for a comment at the end (as last token or just before the line break).
|
||||
// remarks No validity check is done for the supplied token iterator.
|
||||
// param[in] rprRange Pair with the start position and one past the end position of a range.
|
||||
// return Returns whether the line contains a post comment.
|
||||
auto fnPostComment = [this](const TRange& rprRange) -> bool
|
||||
{
|
||||
auto itToken = rprRange.second;
|
||||
if (itToken == rprRange.first)
|
||||
return false;
|
||||
--itToken;
|
||||
if (itToken->Category() == ETokenCategory::token_comment)
|
||||
return true;
|
||||
if (itToken->Category() != ETokenCategory::token_syntax_new_line)
|
||||
return false;
|
||||
if (itToken == rprRange.first)
|
||||
return false;
|
||||
--itToken;
|
||||
return itToken->Category() == ETokenCategory::token_comment;
|
||||
};
|
||||
|
||||
// Check a range for empty line(s) only (ignore whitespace and newlines).
|
||||
// remarks No validity check is done for the supplied token iterator.
|
||||
// param[in] rprRange Pair with the start position and one past the end position of a range.
|
||||
@@ -530,75 +620,127 @@ namespace toml_parser
|
||||
// The beginning and the end cannot be the same, except for an empty range.
|
||||
if (itTokenBegin == itTokenEnd) return;
|
||||
|
||||
// Determine line boundaries of the current range
|
||||
// Determine whether there is a post comment at all
|
||||
auto itTokenBeginLine = itTokenBegin == m_lstTokens.begin() ? itTokenBegin : fnGetLine(itTokenBegin).first;
|
||||
auto itTokenEndLine = itTokenEnd;
|
||||
--itTokenEndLine;
|
||||
itTokenEndLine = fnGetLine(itTokenEndLine).second;
|
||||
|
||||
// Are the comments following the statement?
|
||||
bool bCommentsSameLine = fnCommentsOnly(std::make_pair(itTokenEnd, itTokenEndLine));
|
||||
bool bPostCommentPresent = fnCommentsOnly(std::make_pair(itTokenEnd, itTokenEndLine));
|
||||
|
||||
// Is there only whitespace before or after the statement
|
||||
bool bWhitespaceBefore = fnEmptyLine(std::make_pair(itTokenBeginLine, itTokenBegin)) && !bIsParent;
|
||||
bool bWhitespaceAfter = fnEmptyLine(std::make_pair(itTokenEnd, itTokenEndLine));
|
||||
bool bWhitespaceBefore = fnEmptyLine(TRange{itTokenBeginLine, itTokenBegin}) && !bIsParent;
|
||||
bool bWhitespaceAfter = fnEmptyLine(TRange{itTokenEnd, itTokenEndLine});
|
||||
|
||||
// Get the indentation length of the line (whether there is other comments before or not).
|
||||
size_t nIndentLen = fnGetIndentation(std::make_pair(itTokenBeginLine, itTokenEnd));
|
||||
// Post comments or whitespace until the end of the line definitely belongs to the extended range.
|
||||
if (bPostCommentPresent || bWhitespaceAfter) itTokenEnd = itTokenEndLine;
|
||||
|
||||
// Extend the range to include the beginning of the line and the end of the line.
|
||||
TRange prExtended = std::make_pair(bWhitespaceBefore ? itTokenBeginLine : itTokenBegin,
|
||||
(bCommentsSameLine || bWhitespaceAfter) ? itTokenEndLine : itTokenEnd);
|
||||
// Get the indentation length of the definition.
|
||||
size_t nDefIndent = fnGetIndentation(std::make_pair(itTokenBeginLine, itTokenEnd));
|
||||
|
||||
// Deal with whitespace and optionally comments before
|
||||
TRange prLine = prExtended;
|
||||
bool bEmptyLineBefore = false;
|
||||
if (bWhitespaceBefore)
|
||||
// Classify the lines
|
||||
struct SCommentLine
|
||||
{
|
||||
// Check for comments preceeding the range. If previous lines are having comments only (and optionally whitespace), and
|
||||
// the indentation is identical or less than the indentation of the range, the comment belongs to the range.
|
||||
while (fnGetPrevLine(prLine) && fnCommentsOnly(prLine) && fnGetIndentation(prLine) <= nIndentLen)
|
||||
prExtended.first = prLine.first;
|
||||
TRange tLine;
|
||||
size_t nIndent;
|
||||
};
|
||||
std::list<SCommentLine> lstLinesBefore, lstLinesBehind;
|
||||
|
||||
// Check whether there is an empty line before the range or the range starts at the first token in the list.
|
||||
bEmptyLineBefore = prLine.first != prExtended.first ? fnEmptyLine(prLine) : prLine.first == m_lstTokens.begin();
|
||||
}
|
||||
|
||||
// Deal with whitespace and optionally comments following
|
||||
if (bWhitespaceAfter)
|
||||
// Classify the lines before if the definition doesn't have other definition parts before at the same line.
|
||||
TRange tLine = {itTokenBeginLine, itTokenEndLine};
|
||||
bool bIncludeAllBefore = false;
|
||||
while (bWhitespaceBefore && tLine.first != m_lstTokens.begin())
|
||||
{
|
||||
// Check for comments following the range. But only when there are comments at the same line and the indentation of the
|
||||
// next line is larger than the range indentation or there is an empty line following.
|
||||
TRange prPotential = prExtended;
|
||||
bool bUsePotential = false;
|
||||
prLine = prExtended;
|
||||
while (bCommentsSameLine && fnGetNextLine(prLine) && fnCommentsOnly(prLine))
|
||||
if (!fnGetPrevLine(tLine))
|
||||
{
|
||||
if (bUsePotential || fnGetIndentation(prLine) > nIndentLen)
|
||||
{
|
||||
bUsePotential = true;
|
||||
prPotential.second = prLine.second;
|
||||
}
|
||||
else
|
||||
prExtended.second = prLine.second;
|
||||
bIncludeAllBefore = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check whether there is an empty line following the range or the range ends at the end of the list.
|
||||
bool bEmptyLineBeyond = prLine.second == m_lstTokens.end() ? true : fnEmptyLine(prLine);
|
||||
|
||||
// If an empty line is following and a potential extension was detected, extend the range
|
||||
if (bEmptyLineBeyond && bUsePotential)
|
||||
prExtended.second = prPotential.second;
|
||||
|
||||
// If there is an empty line before, include any empty lines until the next token or the end of the list.
|
||||
while (bEmptyLineBefore && bEmptyLineBeyond && fnGetNextLine(prLine) && fnEmptyLine(prLine))
|
||||
prExtended.second = prLine.second;
|
||||
if (fnEmptyLine(tLine))
|
||||
{
|
||||
bIncludeAllBefore = true;
|
||||
break;
|
||||
}
|
||||
if (!fnCommentsOnly(tLine))
|
||||
{
|
||||
// Check for a post comment
|
||||
bIncludeAllBefore = !fnPostComment(tLine);
|
||||
break;
|
||||
}
|
||||
lstLinesBefore.emplace_front(SCommentLine{tLine, fnGetIndentation(tLine)});
|
||||
}
|
||||
|
||||
rTokenRange.ExtendedNode(CTokenRange(fnToken(prExtended.first), fnToken(prExtended.second)));
|
||||
// Classify the lines behind (when there is a post comment or only whitespace following).
|
||||
size_t nNextStatementIndent = 0;
|
||||
tLine = {itTokenBeginLine, itTokenEndLine};
|
||||
bool bIncludeAllBehind = false;
|
||||
while ((bPostCommentPresent || bWhitespaceAfter) && tLine.second != m_lstTokens.end())
|
||||
{
|
||||
if (!fnGetNextLine(tLine))
|
||||
{
|
||||
bIncludeAllBehind = true;
|
||||
break;
|
||||
}
|
||||
if (fnEmptyLine(tLine))
|
||||
{
|
||||
// Note: one empty line still belongs to the extended range.
|
||||
lstLinesBehind.emplace_back(SCommentLine{tLine, 0});
|
||||
bIncludeAllBehind = true;
|
||||
break;
|
||||
}
|
||||
size_t nIndent = fnGetIndentation(tLine);
|
||||
if (!fnCommentsOnly(tLine))
|
||||
{
|
||||
nNextStatementIndent = nIndent;
|
||||
break;
|
||||
}
|
||||
lstLinesBehind.emplace_back(SCommentLine{tLine, fnGetIndentation(tLine)});
|
||||
}
|
||||
|
||||
TRange tExtended{itTokenBegin, itTokenEnd};
|
||||
if (!lstLinesBefore.empty())
|
||||
{
|
||||
// Include all comments before, or only the comments with an indentation identical or smaller than the def indentation.
|
||||
if (bIncludeAllBefore)
|
||||
tExtended.first = lstLinesBefore.front().tLine.first;
|
||||
else
|
||||
{
|
||||
auto it = lstLinesBefore.crbegin();
|
||||
while (it != lstLinesBefore.crend())
|
||||
{
|
||||
// NOTE: Use of SCommentLine structure here, prevents unusedStruct warning of cppcheck
|
||||
const SCommentLine& rsLine = *it;
|
||||
if (rsLine.nIndent > nDefIndent)
|
||||
break;
|
||||
tExtended.first = rsLine.tLine.first;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!lstLinesBehind.empty())
|
||||
{
|
||||
// Include all comments behind, or only the comments with an indentation larger than the indentation of the next def.
|
||||
// The latter only when there is a post-comment.
|
||||
if (bIncludeAllBehind)
|
||||
tExtended.second = lstLinesBehind.back().tLine.second;
|
||||
else if (bPostCommentPresent)
|
||||
{
|
||||
auto it = lstLinesBehind.cbegin();
|
||||
while (it != lstLinesBehind.cend())
|
||||
{
|
||||
// NOTE: Use of SCommentLine structure here, prevents unusedStruct warning of cppcheck
|
||||
const SCommentLine& rsLine = *it;
|
||||
if (rsLine.nIndent <= nNextStatementIndent)
|
||||
break;
|
||||
tExtended.second = rsLine.tLine.second;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rTokenRange.ExtendedNode(CTokenRange(fnToken(tExtended.first), fnToken(tExtended.second)));
|
||||
|
||||
// Determine if there are any more nodes before the end of the list.
|
||||
auto itFinal = prExtended.second;
|
||||
auto itFinal = tExtended.second;
|
||||
bool bNextNodeFound = false;
|
||||
while (itFinal != m_lstTokens.end() && !bNextNodeFound)
|
||||
{
|
||||
@@ -1161,7 +1303,7 @@ namespace toml_parser
|
||||
{
|
||||
token = CToken(ETokenCategory::token_syntax_array_close);
|
||||
m_stackExpectations.pop();
|
||||
if (m_stackExpectations.top() == EExpectation::expect_value_once)
|
||||
if (!m_stackExpectations.empty() && m_stackExpectations.top() == EExpectation::expect_value_once)
|
||||
m_stackExpectations.pop();
|
||||
}
|
||||
else
|
||||
@@ -1184,7 +1326,7 @@ namespace toml_parser
|
||||
rReader.Consume();
|
||||
token = CToken(ETokenCategory::token_syntax_inline_table_close);
|
||||
m_stackExpectations.pop();
|
||||
if (m_stackExpectations.top() == EExpectation::expect_value_once)
|
||||
if (!m_stackExpectations.empty() && m_stackExpectations.top() == EExpectation::expect_value_once)
|
||||
m_stackExpectations.pop();
|
||||
break;
|
||||
case ',':
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Stimpfl - initial API and implementation
|
||||
* Erik Verhoeven - writing TOML and whitespace preservation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef LEXER_TOML_H
|
||||
#define LEXER_TOML_H
|
||||
|
||||
@@ -11,6 +25,32 @@
|
||||
/// The TOML parser namespace
|
||||
namespace toml_parser
|
||||
{
|
||||
/**
|
||||
* @brief Safe stack implementation for an enum returning a default value when the stack is empty.
|
||||
*/
|
||||
template <typename TEnum, TEnum TDefault>
|
||||
class enum_stack : public std::stack<TEnum>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Pop the top-most entry from the stack if the stack is not empty.
|
||||
*/
|
||||
void pop()
|
||||
{
|
||||
if (!std::stack<TEnum>::empty())
|
||||
std::stack<TEnum>::pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the value of the top-most entry of the stack or if empty a default value.
|
||||
* @return The top-most or default value.
|
||||
*/
|
||||
TEnum top() const
|
||||
{
|
||||
return std::stack<TEnum>::empty() ? TDefault : std::stack<TEnum>::top();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Node token range used to regenerate the source from the node entries.
|
||||
* @details A node can have several token ranges identifying code that belongs to the node or precedes or succeeds the node. The
|
||||
@@ -166,10 +206,15 @@ namespace toml_parser
|
||||
*/
|
||||
void Feed(const std::string& rssString, bool bValueOnly = false);
|
||||
|
||||
/**
|
||||
* @brief Clear the lexer content.
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
/**
|
||||
* @brief Reset the lexer cursor position.
|
||||
*/
|
||||
void Reset();
|
||||
void ResetCursor();
|
||||
|
||||
/**
|
||||
* @brief Navigation modes supported by the lexer.
|
||||
@@ -362,11 +407,13 @@ namespace toml_parser
|
||||
*/
|
||||
enum class EExpectation
|
||||
{
|
||||
undefined, ///< Error case when code is supplied that was not expected.
|
||||
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
|
||||
enum_stack<EExpectation, EExpectation::undefined>
|
||||
m_stackExpectations; ///< Tracking of key or value expectations in nested structures
|
||||
|
||||
const std::vector<std::string>
|
||||
m_vecKeyDelimiters{"\n", "\t", "\r", " ", "", ".", "=", "]"}; ///< Characters that delimit a key
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Stimpfl - initial API and implementation
|
||||
* Erik Verhoeven - writing TOML and whitespace preservation
|
||||
********************************************************************************/
|
||||
|
||||
#include "lexer_toml_token.h"
|
||||
#include <sstream>
|
||||
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Stimpfl - initial API and implementation
|
||||
* Erik Verhoeven - writing TOML and whitespace preservation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef LEXER_TOML_TOKEN_H
|
||||
#define LEXER_TOML_TOKEN_H
|
||||
|
||||
@@ -310,7 +324,7 @@ namespace toml_parser
|
||||
|
||||
union
|
||||
{
|
||||
std::string m_ssContentString; ///< Token string content (used with keys, strings and errors).
|
||||
std::string m_ssContentString; ///< Token string contentv (used with keys, strings and errors).
|
||||
int64_t m_iContentInteger; ///< Token integer content
|
||||
double m_dContentFloatingpoint; ///< Token floatingpoint content
|
||||
bool m_bContentBoolean; ///< Token boolean content
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Stimpfl - initial API and implementation
|
||||
* Erik Verhoeven - writing TOML and whitespace preservation
|
||||
********************************************************************************/
|
||||
|
||||
#include "miscellaneous.h"
|
||||
#include "exception.h"
|
||||
#include <sstream>
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Stimpfl - initial API and implementation
|
||||
* Erik Verhoeven - writing TOML and whitespace preservation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef MISCELLANEOUS_H
|
||||
#define MISCELLANEOUS_H
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,17 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Stimpfl - initial API and implementation
|
||||
* Erik Verhoeven - writing TOML and whitespace preservation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef PARSER_NODE_TOML_H
|
||||
#define PARSER_NODE_TOML_H
|
||||
|
||||
@@ -9,10 +23,9 @@
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include <interfaces/toml.h>
|
||||
#include <support/interface_ptr.h>
|
||||
#include "lexer_toml.h"
|
||||
#include "miscellaneous.h"
|
||||
#include "code_snippet.h"
|
||||
|
||||
/// The TOML parser namespace
|
||||
namespace toml_parser
|
||||
@@ -30,9 +43,11 @@ namespace toml_parser
|
||||
*/
|
||||
enum class EGenerateOptions : uint32_t
|
||||
{
|
||||
inline_when_possible = 0x01, ///< Try to generate as much as possible as inline nodes.
|
||||
explicit_when_possible = 0x02, ///< Try to generate as much as possible as explicit nodes.
|
||||
no_comments = 0x10, ///< Do not include comments
|
||||
inline_when_possible = 0x01, ///< Try to generate as much as possible as inline nodes.
|
||||
explicit_when_possible = 0x02, ///< Try to generate as much as possible as explicit nodes.
|
||||
no_comments = 0x10, ///< Do not include comments.
|
||||
reduce_whitespace = 0x20, ///< Add comments, but reduce extra newlines before and after the node.
|
||||
full_header = 0x40, ///< When generating tables or table arrays, include the header in generated code.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -50,7 +65,8 @@ namespace toml_parser
|
||||
CGenContext(const std::string& rssPrefixKey = std::string(), uint32_t uiOptions = 0);
|
||||
|
||||
/**
|
||||
* @brief Called by the node that is generating the TOML. If not initialized before, initializes with the provided node.
|
||||
* @brief Called by the node that is generating the TOML. If not initialized before, extract the context from the node and
|
||||
* assign this node as top node for the code generation.
|
||||
* @param[in] rptrNode Reference to the node that could be used for initialization as top most node.
|
||||
*/
|
||||
void InitTopMostNode(const std::shared_ptr<const CNode>& rptrNode);
|
||||
@@ -65,9 +81,12 @@ namespace toml_parser
|
||||
/**
|
||||
* @brief Create a copy of the context class with a new key context.
|
||||
* @param[in] rssNewKeyContext Reference to the string containing the new key context.
|
||||
* @param[in] rptrNode Reference to the node pointer to extract the context from.
|
||||
* @param[in] bLastNode When set, this is the last node in the current view.
|
||||
* @return The copy of the contetx class.
|
||||
*/
|
||||
CGenContext CopyWithContext(const std::string& rssNewKeyContext) const;
|
||||
CGenContext CopyWithContext(const std::string& rssNewKeyContext, const std::shared_ptr<CNode>& rptrNode,
|
||||
bool bLastNode) const;
|
||||
|
||||
/**
|
||||
* @brief Get the stored prefix key that should be used for the TOML code generation.
|
||||
@@ -81,6 +100,24 @@ namespace toml_parser
|
||||
*/
|
||||
const std::string& KeyContext() const;
|
||||
|
||||
/**
|
||||
* @brief The key path composed of the prefix and the relative key path.
|
||||
* @return Reference to the key path string.
|
||||
*/
|
||||
const std::string& KeyPath() const;
|
||||
|
||||
/**
|
||||
* @brief The key path composed of the key kontext and the relative key path.
|
||||
* @return Reference to the key path string.
|
||||
*/
|
||||
const std::string& FullKeyPath() const;
|
||||
|
||||
/**
|
||||
* @brief The relative key path, relative to the current context.
|
||||
* @return Reference to the key path string.
|
||||
*/
|
||||
const std::string& RelKeyPath() const;
|
||||
|
||||
/**
|
||||
* @brief Is this the top most node?
|
||||
* @return Returns when the node is the top most node.
|
||||
@@ -100,17 +137,115 @@ namespace toml_parser
|
||||
*/
|
||||
bool CheckOption(EGenerateOptions eOption) const;
|
||||
|
||||
/**
|
||||
* @brief Is the last-node-flag set?
|
||||
* @return Returns whether the last-node-flag has been set indicating the node using this context to be the last node within
|
||||
* the current view.
|
||||
*/
|
||||
bool LastNode() const;
|
||||
|
||||
/**
|
||||
* @brief Node presentation form.
|
||||
*/
|
||||
enum class EPresentation
|
||||
{
|
||||
standard, ///< Standard presentation (root or within table/table-array)
|
||||
standard_inline, ///< Inline presentation (root or within table/table-array)
|
||||
embedded, ///< Embedded presentation (within array or inline-table)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get the presentation form of the node.
|
||||
* @return The node presentation extracted from the node and the generation context.
|
||||
*/
|
||||
EPresentation Presentation() const;
|
||||
|
||||
/**
|
||||
* @brief Is the node a standard node?
|
||||
* @return Returns 'true' when the node is a standard node.
|
||||
*/
|
||||
bool Standard() const;
|
||||
|
||||
/**
|
||||
* @brief Is the node an inline node?
|
||||
* @remarks Embedded nodes are also inline.
|
||||
* @return Returns 'true' when the node is an inline node.
|
||||
*/
|
||||
bool Inline() const;
|
||||
|
||||
/**
|
||||
* @brief Is the node an embedded node (within an inline table or array)?
|
||||
* @return Returns 'true' when the node is an embedded node.
|
||||
*/
|
||||
bool Embedded() const;
|
||||
|
||||
/**
|
||||
* @brief Does the node need an assignment (key and when inline, equal sign)?
|
||||
* @remarks Embedded nodes within an array do not need an assignment.
|
||||
* @return Returns 'true' when the node needs an assignment.
|
||||
*/
|
||||
bool Assignment() const;
|
||||
|
||||
/**
|
||||
* @brief For an embedded node, is a comma indicating the next node needed?
|
||||
* @remarks Some inline arrays can have a final comma behind the last embedded node.
|
||||
* @return Returns 'true' when a comma is needed.
|
||||
*/
|
||||
bool CommaNeeded() const;
|
||||
|
||||
/**
|
||||
* @brief Are comments and newlines allowed? For an embedded node, this might be prohibited. But can also explicitly be
|
||||
* defined in the context.
|
||||
* @remarks Inline tables require a one line definition for the embedded nodes.
|
||||
* @return Returns 'true' if comments and newlines are allowed.
|
||||
*/
|
||||
bool CommentAndNewlineAllowed() const;
|
||||
|
||||
/**
|
||||
* @brief Are newlines allowed? For an embedded node, this might be prohibited. But can also explicitly be defined in the
|
||||
* context.
|
||||
* @remarks Inline tables require a one line definition for the embedded nodes.
|
||||
* @return Returns 'true' if comments and newlines are allowed.
|
||||
*/
|
||||
bool NewlineAllowed() const;
|
||||
|
||||
/**
|
||||
* @brief For a standard (inline) node, is a newline required at the end of the node definition?
|
||||
* @returns Returns'true' if a newline is required behind the node definition.
|
||||
*/
|
||||
bool FinalNewline() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<const CNode> m_ptrTopMostNode; ///< Top most node that is used for the generation. The parent nodes of
|
||||
///< the top most node will not be part of the node generation and if
|
||||
///< they contain child nodes in their view, the nodes are printed by
|
||||
///< their parent and not by their view.
|
||||
std::string m_ssPrefixKey; ///< Prefix key to be used during the generation of the TOML code.
|
||||
std::string m_ssKeyContext; ///< string containing the current context. The string must follow the
|
||||
///< key rules for separation with bare, literal and quoted keys.
|
||||
uint32_t m_uiOptions = 0; ///< Zero or more options to take into account when creating the text to
|
||||
///< the TOML nodes.
|
||||
bool m_bTopMost = true; ///< Set when this context is the top most context.
|
||||
void ExtractContext(const std::shared_ptr<const CNode>& rptrNode);
|
||||
|
||||
std::shared_ptr<const CNode> m_ptrTopMostNode; ///< Top most node that is used for the generation. The
|
||||
///< parent nodes of the top most node will not be part of
|
||||
///< the node generation and if they contain child nodes in
|
||||
///< their view, the nodes are printed by their parent and
|
||||
///< not by their view.
|
||||
std::string m_ssPrefixKey; ///< Prefix key to be used during the generation of the TOML
|
||||
///< not by their view.
|
||||
std::string m_ssKeyContext2;
|
||||
std::string m_ssKeyContext; ///< String containing the current context. The string must
|
||||
///< follow the key rules for separation with bare, literal
|
||||
///< and quoted keys.
|
||||
std::string m_ssKeyPath; ///< The key path composed of the prefix and the relative
|
||||
///< key path.
|
||||
std::string m_ssFullKeyPath; ///< The full key path composed of the key context and the
|
||||
///< relative key path.
|
||||
std::string m_ssRelKeyPath; ///< The relative key path, relative to the current context.
|
||||
uint32_t m_uiOptions = 0; ///< Zero or more options to take into account when creating
|
||||
///< the text to the TOML nodes.
|
||||
bool m_bTopMost = true; ///< Set when this context is the top most context.
|
||||
bool m_bLastNode = false; ///< Is this the last node in the current view?
|
||||
bool m_bFinalLastNode = false; ///< When set, this is the last (top level) node of the node
|
||||
///< hierarchy. Only child nodes can still follow.
|
||||
EPresentation m_ePresentation = EPresentation::standard; ///< Presentation of the node.
|
||||
bool m_bOneLine = false; ///< Set when the node is not allowed to cover more than
|
||||
///< one line (except when using multi-line strings).
|
||||
bool m_bAssignment = false; ///< Does the node need an assignment.
|
||||
bool m_bCommaNeeded = false; ///< Is a comma needed following the node definition?
|
||||
bool m_bFinalNewline = false; ///< Is a final newline behind the definition required?
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -118,7 +253,7 @@ namespace toml_parser
|
||||
*/
|
||||
class CNode :
|
||||
public std::enable_shared_from_this<CNode>, public sdv::IInterfaceAccess, public sdv::toml::INodeInfo,
|
||||
public sdv::toml::INodeDelete, public sdv::toml::INodeUpdate
|
||||
public sdv::toml::INodeUpdate
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
@@ -150,7 +285,6 @@ namespace toml_parser
|
||||
// Interface map
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(sdv::toml::INodeInfo)
|
||||
SDV_INTERFACE_ENTRY(sdv::toml::INodeDelete)
|
||||
SDV_INTERFACE_ENTRY(sdv::toml::INodeUpdate)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
@@ -194,8 +328,9 @@ namespace toml_parser
|
||||
virtual sdv::any_t GetValue() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the index of this node within the parent collection. Overload of sdv::toml::INodeInfo::GetIndex.
|
||||
* @return The index of the node within the parent collection node or npos when no parent is available.
|
||||
* @brief Get the index of this node within the view collection (either the assigned view or the parent). Overload of
|
||||
* sdv::toml::INodeInfo::GetIndex.
|
||||
* @return The index of the node within the view collection node or npos when no parent is available.
|
||||
*/
|
||||
virtual uint32_t GetIndex() const override;
|
||||
|
||||
@@ -214,27 +349,25 @@ namespace toml_parser
|
||||
|
||||
/**
|
||||
* @brief Set or replace a comment for the node. Overload of sdv::toml::INodeInfo::SetComment.
|
||||
* @remarks This function can also be used to insert whitespace (with or without comments) when used in raw mode.
|
||||
* Set the comment text for the node. If a comment is proided as text (normal behavior), the comment text will be
|
||||
* formatted automatically when generating the TOML text. If the comment is provided as raw comment, the text should
|
||||
* contain all whitespace and the comment '#' character before the comment text.
|
||||
* Comments inserted before the enode will be inserted on the line before the node uness the comment is provided in raw
|
||||
* format and is ended with a newline and optionally whitespace. Comment inserted behind the node will be inserted on
|
||||
* @details Set the comment text for the node. If a comment is provided as text (normal behavior), the comment text will
|
||||
* be formatted automatically when generating the TOML text. If the comment text should not contain the comment
|
||||
* character '#' before the comment text.
|
||||
* Comments inserted before the node will be inserted on the line before the node unless the comment is provided in raw
|
||||
* format and is ended with a line-break and optionally whitespace. Comment inserted behind the node will be inserted on
|
||||
* the same line as the node.
|
||||
* Comments provided as text is automatically wrapped to 80 characters if possible. Newlines in the text will cause a
|
||||
* new comment line to start.
|
||||
* @param[in] ssComment String containing the comment text or the raw comment string to set.
|
||||
* @param[in] uiFlags One or more ECommentFlags flags influencing the behavior of the comment.
|
||||
* Comments provided as text is automatically wrapped to 132 characters if possible. Line-breaks in the text will cause
|
||||
* a new comment line to start.
|
||||
* @param[in] eType The comment type to set the comment text for.
|
||||
* @param[in] ssComment String containing the comment text to set.
|
||||
*/
|
||||
virtual void SetComment(const sdv::u8string& ssComment, uint32_t uiFlags) override;
|
||||
virtual void SetComment(sdv::toml::INodeInfo::ECommentType eType, const sdv::u8string& ssComment) override;
|
||||
|
||||
/**
|
||||
* Get the current comment for the node. Overload of sdv::toml::INodeInfo::GetComment.
|
||||
* @remarks To receive the whitespace formatting the node, use this function in raw mode.
|
||||
* @param[in] uiFlags One or more ECommentFlags flags identifying the string format of the comment to return.
|
||||
* @param[in] eType The comment type to get the comment text of.
|
||||
* @return String with the comment text or an empty string if no comment is available.
|
||||
*/
|
||||
virtual sdv::u8string GetComment(uint32_t uiFlags) override;
|
||||
virtual sdv::u8string GetComment(sdv::toml::INodeInfo::ECommentType eType) override;
|
||||
|
||||
/**
|
||||
* @brief Format the node automatically. This will remove the whitespace between the elements within the node. Comments
|
||||
@@ -242,6 +375,18 @@ namespace toml_parser
|
||||
*/
|
||||
virtual void AutomaticFormat() override;
|
||||
|
||||
/**
|
||||
* @brief Is the node inline? Overload of sdv::toml::INodeInfo::IsInline.
|
||||
* @return Returns whether the node is defined as inline node.
|
||||
*/
|
||||
virtual bool IsInline() const override;
|
||||
|
||||
/**
|
||||
* @brief Is the node defined as standard node? Overload of sdv::toml::INodeInfo::IsStandard.
|
||||
* @return Returns whether the node is defined as standard node.
|
||||
*/
|
||||
virtual bool IsStandard() const override;
|
||||
|
||||
/**
|
||||
* @brief Update the node with TOML code information. The default implementation takes the comment and whitespace around the
|
||||
* node and stores this for node reconstruction.
|
||||
@@ -249,19 +394,6 @@ namespace toml_parser
|
||||
*/
|
||||
virtual void UpdateNodeCode(const CNodeTokenRange& rNodeRange);
|
||||
|
||||
/**
|
||||
* @brief Delete the current node. Overload of sdv::toml::INodeDelete::DeleteNode.
|
||||
* @attention A successful deletion will cause all interfaces to the current node to become inoperable.
|
||||
* @return Returns whether the deletion was successful.
|
||||
*/
|
||||
virtual bool DeleteNode() override;
|
||||
|
||||
/**
|
||||
* @brief Is this node marked as deleted?
|
||||
* @return Returns whether this node has been deleted.
|
||||
*/
|
||||
bool IsDeleted() const;
|
||||
|
||||
/**
|
||||
* @brief Change the key name of the node (if the node is not a value node of an array). Overload of
|
||||
* sdv::toml::INodeUpdate::ChangeName.
|
||||
@@ -275,7 +407,7 @@ namespace toml_parser
|
||||
/**
|
||||
* @brief Change the value of the node. Overload of sdv::toml::INodeUpdate::ChangeValue.
|
||||
* @remarks Only valid for value nodes. Changing the value type is not supported.
|
||||
* @param[in] anyNewValue The value of the node, being either an integer, floating point number, boolean value or a
|
||||
* @param[in] anyNewValue The value of the node, being either an integer, floating point number, virtual bool value or a
|
||||
* string. Conversion is automatically done to int64, double float, bool or u8string.
|
||||
* @return Returns whether the value change was successful.
|
||||
*/
|
||||
@@ -297,6 +429,19 @@ namespace toml_parser
|
||||
*/
|
||||
virtual bool MoveDown() override;
|
||||
|
||||
/**
|
||||
* @brief Delete the current node. Overload of sdv::toml::INodeUpdate::DeleteNode.
|
||||
* @attention A successful deletion will cause all interfaces to the current node to become inoperable.
|
||||
* @return Returns whether the deletion was successful.
|
||||
*/
|
||||
virtual bool DeleteNode() override;
|
||||
|
||||
/**
|
||||
* @brief Is this node marked as deleted?
|
||||
* @return Returns whether this node has been deleted.
|
||||
*/
|
||||
bool IsDeleted() const;
|
||||
|
||||
/**
|
||||
* @brief Do a dynamic cast to one of the base types of the node.
|
||||
* @return Casted shared pointer to the base type if the type is valid, or an empty pointer if not.
|
||||
@@ -311,19 +456,19 @@ namespace toml_parser
|
||||
template <typename TNodeType>
|
||||
std::shared_ptr<const TNodeType> Cast() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the parent node pointer
|
||||
* @return Returns the parent node pointer or an empty pointer when no parent was assigned or the stored weak pointer could
|
||||
* not be locked.
|
||||
*/
|
||||
std::shared_ptr<CNodeCollection> GetParentPtr() const;
|
||||
|
||||
/**
|
||||
* @brief Set the parent node.
|
||||
* @param[in] rptrParent Reference to the node to assign to this node as a parent.
|
||||
*/
|
||||
void SetParentPtr(const std::shared_ptr<CNodeCollection>& rptrParent);
|
||||
|
||||
/**
|
||||
* @brief Gets the parent node pointer.
|
||||
* @return Returns the parent node pointer or an empty pointer when no parent was assigned or the stored weak pointer could
|
||||
* not be locked.
|
||||
*/
|
||||
std::shared_ptr<CNodeCollection> GetParentPtr() const;
|
||||
|
||||
/**
|
||||
* @brief Get the parent path of the node.
|
||||
* @return Return the parent path if existining and not a root.
|
||||
@@ -337,6 +482,12 @@ namespace toml_parser
|
||||
*/
|
||||
void SetViewPtr(const std::shared_ptr<CNodeCollection>& rptrView);
|
||||
|
||||
/**
|
||||
* @brief Gets the view definition node pointer.
|
||||
* @return Returns the store view definition node pointer or an empty pointer when no view was assigned.
|
||||
*/
|
||||
std::shared_ptr<CNodeCollection> GetViewPtr() const;
|
||||
|
||||
/**
|
||||
* @brief Checks whether the node is part of the view.
|
||||
* @details The node is part of the view if the supplied pointer is identical to the view definition pointer, when the view
|
||||
@@ -367,95 +518,8 @@ namespace toml_parser
|
||||
*/
|
||||
virtual std::string GenerateTOML(const CGenContext& rContext = CGenContext()) const = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Compose a custom path from the node key path using a key prefix and a context.
|
||||
* @param[in] rssPrefixKey The prefix to insert at as a base to the key tree.
|
||||
* @param[in] rssContext The context that is used to define the relative portion of the key. To determine the relative
|
||||
* portion, the context string contains the same prefix as is supplied in rssPrefixKey.
|
||||
* @return Returns the custom path composed of the prefix and the relative portion of the original path.
|
||||
*/
|
||||
std::string GetCustomPath(const std::string& rssPrefixKey, const std::string& rssContext) const;
|
||||
|
||||
/**
|
||||
* @brief Comment or code snippet structure.
|
||||
* @details Each node has multiple code snippets used to reproduce the exact code. For example with an assignment:
|
||||
* @code
|
||||
*
|
||||
* # This is out of scope comment before
|
||||
*
|
||||
* # This is comment before
|
||||
* var_a = "abc" # comment behind
|
||||
* # more comment behind
|
||||
*
|
||||
* # This is out of scope comment behind
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* The code snippets are identified as follows:
|
||||
* @code
|
||||
* <out of scope comment before>
|
||||
* <comment before>
|
||||
* <space before><key><space>=<space><value><comment behind>
|
||||
* <out of scope comment behind>
|
||||
* @endcode
|
||||
*/
|
||||
class CCodeSnippet
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Access the token list.
|
||||
* @return Reference to the list with tokens.
|
||||
*/
|
||||
std::list<CToken>& List();
|
||||
|
||||
/**
|
||||
* @brief Access the comment text string.
|
||||
* @return Reference to the comment string.
|
||||
*/
|
||||
std::string& Str();
|
||||
|
||||
/**
|
||||
* @brief Mode the code snippet composer should run in.
|
||||
*/
|
||||
enum class EComposeMode
|
||||
{
|
||||
compose_inline, ///< Compose as inline whitespace and comment. If there is no token list and no comment
|
||||
///< string, compose as one space. If there is only a comment string, insert a space, add
|
||||
///< the comment followed by an obligatory newline, and insert spaces until the next
|
||||
///< provided position. If there are tokens with a comment token, replace the comment. If
|
||||
///< there are tokens without comment, add the comment, newline and spaces.
|
||||
compose_before, ///< Compose as comment assigned to and located before the node. If there is no token list
|
||||
///< and no comment string, doesn't add anything. If there is only a comment string, adds
|
||||
///< the comment followed by the obligatory newline. If there are tokens with a comment
|
||||
///< token, replace the comment. If there are tokens without the comment, place the comment
|
||||
///< before the last newline or when not available, at the end of the tokens followed by a
|
||||
///< new newline.
|
||||
compose_behind, ///< Compose as comment assigned to and located behind the node. If there is no token list
|
||||
///< and no comment string, add a newline. If there is a comment string and no tokens,
|
||||
///< add a space, the comment string followed by the obligatory newline. If there is a token
|
||||
///< list without comment, add a comment before the newline or at the end with an additional
|
||||
///< newline.
|
||||
compose_standalone, ///< Compose as stand-alone comment. Replace any token list if a comment string is
|
||||
///< available.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compose a conde string from the stored tokens and/or string.
|
||||
* @param[in] eMode The mode the composer should run in.
|
||||
* @param[in] nAssignmentOffset The offset for a next assignent; only used for inline composition.
|
||||
* @param[in] nCommentOffset The offset to insert a multi-line comment; only used for inline and behind composition.
|
||||
* @return The composed code string.
|
||||
*/
|
||||
std::string Compose(EComposeMode eMode, size_t nAssignmentOffset = 0, size_t nCommentOffset = 0) const;
|
||||
|
||||
private:
|
||||
std::list<CToken> m_lstTokens; ///< Token list for the code snippet in raw format.
|
||||
std::string m_ssComment; ///< The comment text for the code snippet in text format.
|
||||
};
|
||||
|
||||
// White space and comment preservation indices for code generation.
|
||||
const size_t m_nPreNodeCode = 0; ///< Code snippet before the node. Corresponds to
|
||||
const size_t m_nPreNodeCode = 0; ///< Code snippet before the node. Corresponds to
|
||||
///< sdv::toml::INodeInfo::ECommentFlags::comment_before.
|
||||
const size_t m_nPostNodeCode = 1; ///< Comment behind the node. Corresponds to
|
||||
///< sdv::toml::INodeInfo::ECommentFlags::comment_behind.
|
||||
@@ -473,7 +537,7 @@ namespace toml_parser
|
||||
|
||||
/**
|
||||
* @brief Get the code snippet.
|
||||
* @param[in] nIndex The comment type index to get the comment for.
|
||||
* @param[in] nIndex The comment type index to get the code for.
|
||||
* @param[in] rssKey Reference to the key to be used for code snippet identification.
|
||||
* @return Reference to the comment structure of the comment. If the provided index is not available in the vector,
|
||||
* returns an empty code snippet.
|
||||
@@ -481,15 +545,38 @@ namespace toml_parser
|
||||
const CCodeSnippet& CodeSnippet(size_t nIndex, const std::string& rssKey = std::string()) const;
|
||||
|
||||
/**
|
||||
* @brief Get the code snippet (write access). This allows moving the snippet from one node to the another node.
|
||||
* @remarks Since the request to the code snippet could change the location of the vector allocation, access to the code
|
||||
* snippet is valid until the next code snippet is requested.
|
||||
* @param[in] nIndex The comment type index to get the comment for.
|
||||
* @brief Get the code snippet (write access).
|
||||
* @param[in] nIndex The comment type index to get the code for.
|
||||
* @param[in] rssKey Reference to the key to be used for code snippet identification.
|
||||
* @return Reference to the comment structure of the comment.
|
||||
*/
|
||||
CCodeSnippet& CodeSnippet(size_t nIndex, const std::string& rssKey = std::string());
|
||||
|
||||
/**
|
||||
* @brief Get the code snippet using the comment type.
|
||||
* @param[in] eType The comment type to get the code for.
|
||||
* @return Reference to the comment structure of the comment. If the provided index is not available in the vector,
|
||||
* returns an empty code snippet.
|
||||
*/
|
||||
const CCodeSnippet& CodeSnippet(sdv::toml::INodeInfo::ECommentType eType) const;
|
||||
|
||||
/**
|
||||
* @brief Get the code snippet (write access) using the comment type.
|
||||
* @param[in] eType The comment type to get the code for.
|
||||
* @return Reference to the comment structure of the comment. If the provided index is not available in the vector,
|
||||
* returns an empty code snippet.
|
||||
*/
|
||||
CCodeSnippet& CodeSnippet(sdv::toml::INodeInfo::ECommentType eType);
|
||||
|
||||
/**
|
||||
* @brief Compose a custom path from the node key path using a key prefix and a context.
|
||||
* @param[in] rssPrefixKey The prefix to insert at as a base to the key tree.
|
||||
* @param[in] rssContext The context that is used to define the relative portion of the key. To determine the relative
|
||||
* portion, the context string contains the same prefix as is supplied in rssPrefixKey.
|
||||
* @return Returns the custom path composed of the prefix and the relative portion of the original path.
|
||||
*/
|
||||
std::string GetCustomPath(const std::string& rssPrefixKey, const std::string& rssContext) const;
|
||||
|
||||
private:
|
||||
std::weak_ptr<CNodeCollection> m_ptrParent; ///< Weak pointer to the parent node (if existing).
|
||||
std::weak_ptr<CNodeCollection> m_ptrView; ///< Weak pointer to the view node (if existing and explicitly set).
|
||||
@@ -610,6 +697,12 @@ namespace toml_parser
|
||||
*/
|
||||
std::string RawValueText() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief When updating the node, reset the raw value text.
|
||||
*/
|
||||
void ResetRawValueText();
|
||||
|
||||
private:
|
||||
std::string m_ssRawValue; ///< Raw value string.
|
||||
};
|
||||
@@ -647,7 +740,7 @@ namespace toml_parser
|
||||
/**
|
||||
* @brief Change the value of the node. Overload of sdv::toml::INodeUpdate::ChangeValue.
|
||||
* @remarks Only valid for value nodes. Changing the value type is not supported.
|
||||
* @param[in] anyNewValue The value of the node, being either an integer, floating point number, boolean value or a
|
||||
* @param[in] anyNewValue The value of the node, being either an integer, floating point number, virtual bool value or a
|
||||
* string. Conversion is automatically done to int64, double float, bool or u8string.
|
||||
* @return Returns whether the value change was successful.
|
||||
*/
|
||||
@@ -660,7 +753,7 @@ namespace toml_parser
|
||||
virtual std::string ValueText() const override;
|
||||
|
||||
private:
|
||||
bool m_bVal = false; ///< Value in case of boolean node.
|
||||
bool m_bVal = false; ///< Value in case of virtual bool node.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -696,7 +789,7 @@ namespace toml_parser
|
||||
/**
|
||||
* @brief Change the value of the node. Overload of sdv::toml::INodeUpdate::ChangeValue.
|
||||
* @remarks Only valid for value nodes. Changing the value type is not supported.
|
||||
* @param[in] anyNewValue The value of the node, being either an integer, floating point number, boolean value or a
|
||||
* @param[in] anyNewValue The value of the node, being either an integer, floating point number, virtual bool value or a
|
||||
* string. Conversion is automatically done to int64, double float, bool or u8string.
|
||||
* @return Returns whether the value change was successful.
|
||||
*/
|
||||
@@ -745,7 +838,7 @@ namespace toml_parser
|
||||
/**
|
||||
* @brief Change the value of the node. Overload of sdv::toml::INodeUpdate::ChangeValue.
|
||||
* @remarks Only valid for value nodes. Changing the value type is not supported.
|
||||
* @param[in] anyNewValue The value of the node, being either an integer, floating point number, boolean value or a
|
||||
* @param[in] anyNewValue The value of the node, being either an integer, floating point number, virtual bool value or a
|
||||
* string. Conversion is automatically done to int64, double float, bool or u8string.
|
||||
* @return Returns whether the value change was successful.
|
||||
*/
|
||||
@@ -806,7 +899,7 @@ namespace toml_parser
|
||||
/**
|
||||
* @brief Change the value of the node. Overload of sdv::toml::INodeUpdate::ChangeValue.
|
||||
* @remarks Only valid for value nodes. Changing the value type is not supported.
|
||||
* @param[in] anyNewValue The value of the node, being either an integer, floating point number, boolean value or a
|
||||
* @param[in] anyNewValue The value of the node, being either an integer, floating point number, virtual bool value or a
|
||||
* string. Conversion is automatically done to int64, double float, bool or u8string.
|
||||
* @return Returns whether the value change was successful.
|
||||
*/
|
||||
@@ -826,8 +919,11 @@ namespace toml_parser
|
||||
/**
|
||||
* @brief Base structure for arrays and tables.
|
||||
*/
|
||||
class CNodeCollection : public CNode, public sdv::toml::INodeCollection, public sdv::toml::INodeCollectionInsert
|
||||
class CNodeCollection : public CNode, public sdv::toml::INodeCollection, public sdv::toml::INodeCollectionInsert,
|
||||
public sdv::toml::INodeCollectionConvert
|
||||
{
|
||||
// Friend class CNode.
|
||||
friend CNode;
|
||||
protected:
|
||||
/**
|
||||
* @brief Constructor
|
||||
@@ -842,9 +938,16 @@ namespace toml_parser
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(sdv::toml::INodeCollection)
|
||||
SDV_INTERFACE_ENTRY(sdv::toml::INodeCollectionInsert)
|
||||
SDV_INTERFACE_ENTRY(sdv::toml::INodeCollectionConvert)
|
||||
SDV_INTERFACE_CHAIN_BASE(CNode)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
* @brief Format the node automatically. This will remove the whitespace between the elements within the node. Comments
|
||||
* will not be changed. Overload of sdv::toml::INodeInfo::AutomaticFormat.
|
||||
*/
|
||||
virtual void AutomaticFormat() override;
|
||||
|
||||
/**
|
||||
* @brief Returns the amount of nodes. Overload of sdv::toml::INodeCollection::GetCount.
|
||||
* @return The amount of nodes.
|
||||
@@ -900,7 +1003,7 @@ namespace toml_parser
|
||||
* @param[in] ssName Name of the node to insert. Will be ignored for an array collection. The name must adhere to the
|
||||
* key names defined by the TOML specification. Defining the key multiple times is not allowed. Quotation of key names
|
||||
* is done automatically; the parser decides itself whether the key is bare-key, a literal key or a quoted key.
|
||||
* @param[in] anyValue The value of the node, being either an integer, floating point number, boolean value or a string.
|
||||
* @param[in] anyValue The value of the node, being either an integer, floating point number, virtual bool value or a string.
|
||||
* Conversion is automatically done to int64, double float, bool or u8string.
|
||||
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
|
||||
*/
|
||||
@@ -928,13 +1031,15 @@ namespace toml_parser
|
||||
* collection count to insert the node at the end of the collection. Table nodes cannot be inserted before value nodes
|
||||
* or arrays. If the index is referencing a position before a value node or an array, the index is automatically
|
||||
* corrected.
|
||||
* @param[in] ssKeyName Name of the table node to insert. Will be ignored if the current node is an array collection.
|
||||
* @param[in] ssName Name of the table node to insert. Will be ignored if the current node is an array collection.
|
||||
* The name must adhere to the key names defined by the TOML specification. Defining the key multiple times is not
|
||||
* allowed. Quotation of key names is done automatically; the parser decides itself whether the key is bare-key, a
|
||||
* literal key or a quoted key.
|
||||
* @param[in] ePreference The preferred form of the node to be inserted.
|
||||
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
|
||||
*/
|
||||
virtual sdv::IInterfaceAccess* InsertTable(uint32_t uiIndex, const sdv::u8string& ssKeyName) override;
|
||||
virtual sdv::IInterfaceAccess* InsertTable(uint32_t uiIndex, const sdv::u8string& ssName,
|
||||
sdv::toml::INodeCollectionInsert::EInsertPreference ePreference) override;
|
||||
|
||||
/**
|
||||
* @brief Insert a table array into the collection at the location before the supplied index. Overload of
|
||||
@@ -947,36 +1052,82 @@ namespace toml_parser
|
||||
* The name must adhere to the key names defined by the TOML specification. Defining the key multiple times is not
|
||||
* allowed. Quotation of key names is done automatically; the parser decides itself whether the key is bare-key, a
|
||||
* literal key or a quoted key.
|
||||
* @param[in] ePreference The preferred form of the node to be inserted.
|
||||
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
|
||||
*/
|
||||
virtual sdv::IInterfaceAccess* InsertTableArray(uint32_t uiIndex, const sdv::u8string& ssName) override;
|
||||
virtual sdv::IInterfaceAccess* InsertTableArray(uint32_t uiIndex, const sdv::u8string& ssName,
|
||||
sdv::toml::INodeCollectionInsert::EInsertPreference ePreference) override;
|
||||
|
||||
/**
|
||||
* @brief Insert a TOML string as a child of the current collection node. If the collection is a table, the TOML string
|
||||
* should contain values and inline/external/array-table nodes with names. If the collection is an array, the TOML
|
||||
* string should contain and inline table nodes without names. Overload of sdv::toml::INodeCollectionInsert::InsertTOML.
|
||||
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
|
||||
* collection count to insert the node at the end of the collection. Table array nodes cannot be inserted before value
|
||||
* nodes or arrays. If the index is referencing a position before a value node or an array, the index is automatically
|
||||
* corrected.
|
||||
* @param[in] ssTOML The TOML string to insert.
|
||||
* @param[in] bRollbackOnPartly If only part of the nodes could be inserted, no node will be inserted.
|
||||
* @return The result of the insertion.
|
||||
*/
|
||||
virtual sdv::toml::INodeCollectionInsert::EInsertResult InsertTOML(const sdv::u8string& ssTOML,
|
||||
virtual sdv::toml::INodeCollectionInsert::EInsertResult InsertTOML(uint32_t uiIndex, const sdv::u8string& ssTOML,
|
||||
bool bRollbackOnPartly) override;
|
||||
|
||||
/**
|
||||
* @brief Delete the current node. Overload of sdv::toml::INodeDelete::DeleteNode.
|
||||
* @brief Delete the current node. Overload of sdv::toml::INodeUpdate::DeleteNode.
|
||||
* @attention A successful deletion will cause all interfaces to the current node to become inoperable.
|
||||
* @return Returns whether the deletion was successful.
|
||||
*/
|
||||
virtual bool DeleteNode() override;
|
||||
|
||||
//protected:
|
||||
/**
|
||||
* @brief Remove a node from the collection.
|
||||
* @brief Can the node convert to an inline definition? Overload of sdv::toml::INodeCollectionConvert::CanMakeInline.
|
||||
* @return Returns whether the conversion to inline is possible. Returns 'true' when the node is already inline.
|
||||
*/
|
||||
virtual bool CanMakeInline() const override;
|
||||
|
||||
/**
|
||||
* @brief Convert the node to an inline node. Overload of sdv::toml::INodeCollectionConvert::MakeInline.
|
||||
* @return Returns whether the conversion was successful. Returns 'true' when the node was already inline.
|
||||
*/
|
||||
virtual bool MakeInline() override;
|
||||
|
||||
/**
|
||||
* @brief Can the node convert to a standard definition? Overload of sdv::toml::INodeCollectionConvert::CanMakeStandard.
|
||||
* @return Returns whether the conversion to standard is possible. Returns 'true' when the node is already defined as
|
||||
* standard node.
|
||||
*/
|
||||
virtual bool CanMakeStandard() const override;
|
||||
|
||||
/**
|
||||
* @brief Convert the node to a standard node. Overload of sdv::toml::INodeCollectionConvert::MakeStandard.
|
||||
* @return Returns whether the conversion was successful. Returns 'true' when the node was already defined as standard
|
||||
* node.
|
||||
*/
|
||||
virtual bool MakeStandard() override;
|
||||
|
||||
/**
|
||||
* @brief Delete a node from the collection.
|
||||
* @remarks The node will not be deleted, but placed in the recycle bin. Deletion will take place at collection destruction.
|
||||
* @param[in] rptrNode Reference to the smart pointer pointing to the node to remove.
|
||||
* @return Returns whether the removal was successful.
|
||||
*/
|
||||
bool RemoveNode(const std::shared_ptr<CNode>& rptrNode);
|
||||
bool DeleteNode(const std::shared_ptr<CNode>& rptrNode);
|
||||
|
||||
/**
|
||||
* @brief Insert the node into the view.
|
||||
* @remarks The node must be a descendant (direct child or an indirect child) of the node.
|
||||
* @details Insert the node into the vector (and remove it from any previous vector if still assigned). Inline nodes can be
|
||||
* assigned to stadard and inline nodes. Standard nodes can only be assigned to standard nodes. In the vector, first the
|
||||
* inline nodes and then the standard nodes are located. This means that an inline node will be placed before standard nodes
|
||||
* and standard nodes behind inline nodes, regardless of the index provided.
|
||||
* @param[in] uiIndex Location within the vector to insert the node. Could be sdv::toml::npos to insert as last node.
|
||||
* @param[in] rptrNode Reference to the smart pointer to the node to set the view for. If the node is not a direct child
|
||||
* node, the view pointer of the node will be set.
|
||||
* @return Returns true when the insertion was successful, false when node (likely because the node to insert is a standard
|
||||
* node, whereas this node is an inline node.
|
||||
*/
|
||||
bool InsertIntoView(uint32_t uiIndex, const std::shared_ptr<CNode>& rptrNode);
|
||||
|
||||
/**
|
||||
* @brief Remove a node from a view.
|
||||
@@ -985,20 +1136,19 @@ namespace toml_parser
|
||||
*/
|
||||
bool RemoveFromView(const std::shared_ptr<CNode>& rptrNode);
|
||||
|
||||
/**
|
||||
* @brief Check whether this node is the last node in the collection.
|
||||
* @param[in] rptrNode Reference to the smart pointer pointing to the node to check for.
|
||||
* @return Returns whether the provided node is the last node in the collection.
|
||||
*/
|
||||
bool CheckLast(const std::shared_ptr<CNode>& rptrNode);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Find the index belonging to the provided node.
|
||||
* @param[in] rptrNode Reference to the smart pointer holding the node to return the index for.
|
||||
* @return Return the node index. Returns npos if the node could not be found.
|
||||
*/
|
||||
uint32_t FindIndex(const std::shared_ptr<CNode>& rptrNode);
|
||||
uint32_t FindIndex(const std::shared_ptr<CNode>& rptrNode) const;
|
||||
|
||||
/**
|
||||
* @brief Is the provided child node a direct or indirect child node?
|
||||
* @param[in] rptrNode Reference to the smart pointer of the potential descendant node.
|
||||
* @return Returns whether the provided node is a descendant of the this node.
|
||||
*/
|
||||
bool IsDescendant(const std::shared_ptr<CNode>& rptrNode) const;
|
||||
|
||||
/**
|
||||
* @brief Generic inserting function for nodes.
|
||||
@@ -1023,6 +1173,24 @@ namespace toml_parser
|
||||
template <typename TNodeType, typename... TArgs>
|
||||
std::shared_ptr<CNode> Insert(uint32_t uiIndex, const CTokenRange& rrangeKeyPath, const TArgs&... rtArgs);
|
||||
|
||||
/**
|
||||
* @brief Combine the collection with the provided content (mathematical union).
|
||||
* @details Update the child nodes with the child nodes of the provided collection. Extend the collection with nodes that do
|
||||
* not exist and update the existing nodes with new values.
|
||||
* @param[in] rptrCollection Reference to the collection being used for this operation.
|
||||
* @return Returns whether the combination was successful.
|
||||
*/
|
||||
virtual bool Combine(const std::shared_ptr<CNodeCollection>& rptrCollection) = 0;
|
||||
|
||||
/**
|
||||
* @brief Reduce the collection with by the provided content (mathematical difference).
|
||||
* @details Reduce the child node with the child nodes already defined and identical in the provided collection. Different
|
||||
* nodes or nodes that are not present in the collection remain.
|
||||
* @param[in] rptrCollection Reference to the collection being used for this operation.
|
||||
* @return Returns whether the reduction was successful.
|
||||
*/
|
||||
virtual bool Reduce(const std::shared_ptr<CNodeCollection>& rptrCollection) = 0;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief When set, the child nodes need grouping (values following each other, tables and table arrays at the end).
|
||||
@@ -1156,8 +1324,23 @@ namespace toml_parser
|
||||
*/
|
||||
virtual void MakeExplicit() override;
|
||||
|
||||
/**
|
||||
* @brief Combine the collection with the provided content (mathematical union). Overload of CNodeCollection::Combine.
|
||||
* @details Update the child nodes with the child nodes of the provided collection. Extend the collection with nodes that do
|
||||
* not exist and update the existing nodes with new values.
|
||||
* @param[in] rptrCollection Reference to the collection being used for this operation.
|
||||
* @return Returns whether the combination was successful.
|
||||
*/
|
||||
virtual bool Combine(const std::shared_ptr<CNodeCollection>& rptrCollection) override;
|
||||
|
||||
//bool m_bOpenToAddChildren = true; ///< If internal table, the table can be extended until the table is closed.
|
||||
/**
|
||||
* @brief Reduce the collection with by the provided content (mathematical difference). Overload of CNodeCollection::Reduce.
|
||||
* @details Reduce the child node with the child nodes already defined and identical in the provided collection. Different
|
||||
* nodes or nodes that are not present in the collection remain.
|
||||
* @param[in] rptrCollection Reference to the collection being used for this operation.
|
||||
* @return Returns whether the reduction was successful.
|
||||
*/
|
||||
virtual bool Reduce(const std::shared_ptr<CNodeCollection>& rptrCollection) override;
|
||||
|
||||
private:
|
||||
bool m_bDefinedExplicitly = true; ///< When set, the table is defined explicitly.
|
||||
@@ -1267,6 +1450,13 @@ namespace toml_parser
|
||||
*/
|
||||
bool TableArray() const;
|
||||
|
||||
/**
|
||||
* @brief Can the node convert to a standard definition? Overload of sdv::toml::INodeCollectionConvert::CanMakeStandard.
|
||||
* @return Returns whether the conversion to standard is possible. Returns 'true' when the node is already defined as
|
||||
* standard node.
|
||||
*/
|
||||
virtual bool CanMakeStandard() const override;
|
||||
|
||||
/**
|
||||
* @brief The derived class from the node collection can be inline or not. Overload of CNode::Inline.
|
||||
* @return Returns whether the node is an inline node.
|
||||
@@ -1287,9 +1477,34 @@ namespace toml_parser
|
||||
*/
|
||||
virtual bool Inline(bool bInline) override;
|
||||
|
||||
/**
|
||||
* @brief Does the last child node need a comma following the node?
|
||||
* @return Returns whether the array was defined with the last node requiring a comma following the node.
|
||||
*/
|
||||
bool LastNodeWithSucceedingComma() const;
|
||||
|
||||
/**
|
||||
* @brief Combine the collection with the provided content (mathematical union). Overload of CNodeCollection::Combine.
|
||||
* @details Update the child nodes with the child nodes of the provided collection. Extend the collection with nodes that do
|
||||
* not exist and update the existing nodes with new values.
|
||||
* @param[in] rptrCollection Reference to the collection being used for this operation.
|
||||
* @return Returns whether the combination was successful.
|
||||
*/
|
||||
virtual bool Combine(const std::shared_ptr<CNodeCollection>& rptrCollection) override;
|
||||
|
||||
/**
|
||||
* @brief Reduce the collection with by the provided content (mathematical difference). Overload of CNodeCollection::Reduce.
|
||||
* @details Reduce the child node with the child nodes already defined and identical in the provided collection. Different
|
||||
* nodes or nodes that are not present in the collection remain.
|
||||
* @param[in] rptrCollection Reference to the collection being used for this operation.
|
||||
* @return Returns whether the reduction was successful.
|
||||
*/
|
||||
virtual bool Reduce(const std::shared_ptr<CNodeCollection>& rptrCollection) override;
|
||||
|
||||
private:
|
||||
bool m_bDefinedExplicitly = true; ///< When set, the array is defined explicitly.
|
||||
bool m_bInline = false; ///< Flag determining whether the table is inline or not.
|
||||
bool m_bDefinedExplicitly = true; ///< When set, the array is defined explicitly.
|
||||
bool m_bInline = false; ///< Flag determining whether the table is inline or not.
|
||||
bool m_bLastChildNodeWithComma = false; ///< Set when the last child node of the array initially has a comma behind the node.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1323,7 +1538,7 @@ namespace toml_parser
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Delete the current node. Overload of sdv::toml::INodeDelete::DeleteNode.
|
||||
* @brief Delete the current node. Overload of sdv::toml::INodeUpdate::DeleteNode.
|
||||
* @attention A successful deletion will cause all interfaces to the current node to become inoperable.
|
||||
* @return Returns whether the deletion was successful.
|
||||
*/
|
||||
@@ -1387,10 +1602,9 @@ namespace toml_parser
|
||||
{
|
||||
ptrTableArray = std::make_shared<CTableArray>(Parser(), prKey.first.get().StringValue(),
|
||||
prKey.first.get().RawString());
|
||||
ptrTableArray->SetParentPtr(Cast<CNodeCollection>());
|
||||
|
||||
// Add to the list
|
||||
m_lstNodes.push_back(ptrTableArray);
|
||||
// Set the parent pointer; this will add the node to the list.
|
||||
ptrTableArray->SetParentPtr(Cast<CNodeCollection>());
|
||||
}
|
||||
else
|
||||
ptrTableArray = (*itNode)->template Cast<CTableArray>();
|
||||
@@ -1401,6 +1615,7 @@ namespace toml_parser
|
||||
// Create the table.
|
||||
ptrNode = ptrTableArray->Insert<CTable>(sdv::toml::npos, CTokenRange(prKey.first, prKey.first.get().Next()),
|
||||
false, true);
|
||||
ptrNode->SetViewPtr(Cast<CNodeCollection>());
|
||||
} else if (!Cast<CArray>() && itNode != m_lstNodes.end())
|
||||
{
|
||||
// If existing... this might be a duplicate if not explicitly defined before.
|
||||
@@ -1422,10 +1637,9 @@ namespace toml_parser
|
||||
// Create the target node.
|
||||
ptrNode = std::make_shared<TNodeType>(Parser(), prKey.first.get().StringValue(), prKey.first.get().RawString(),
|
||||
rtArgs...);
|
||||
ptrNode->SetParentPtr(Cast<CNodeCollection>());
|
||||
|
||||
// Add to the list
|
||||
m_lstNodes.push_back(ptrNode);
|
||||
// Set the parent pointer; this will add the node to the list.
|
||||
ptrNode->SetParentPtr(Cast<CNodeCollection>());
|
||||
|
||||
// If the current node is implicit, take over the inline flag (this determines whether a sub-table definition is
|
||||
// allowed or not).
|
||||
@@ -1480,7 +1694,6 @@ namespace toml_parser
|
||||
// Create an implicit table node.
|
||||
ptrNode = std::make_shared<CTable>(Parser(), prKey.first.get().StringValue(), prKey.first.get().RawString(), false, false);
|
||||
ptrNode->SetParentPtr(Cast<CNodeCollection>());
|
||||
m_lstNodes.push_back(ptrNode);
|
||||
}
|
||||
|
||||
// Insert the node in the child node
|
||||
@@ -1490,15 +1703,14 @@ namespace toml_parser
|
||||
ptrNode = ptrNodeCollection->Insert<TNodeType>(sdv::toml::npos, prKey.second, rtArgs...);
|
||||
if (!ptrNode)
|
||||
throw XTOMLParseException("Could not create the node '" + prKey.first.get().StringValue() + "'.");
|
||||
|
||||
// This node is not the parent, but still presents of the created node. Add the view pointer that they are linked.
|
||||
ptrNode->SetViewPtr(Cast<CNodeCollection>());
|
||||
}
|
||||
|
||||
// Insert the node at the requested location if this node is inline or this is the view of the node.
|
||||
auto itPos = (static_cast<size_t>(uiIndex) >= m_vecNodeOrder.size()) ? m_vecNodeOrder.end() :
|
||||
m_vecNodeOrder.begin() + static_cast<size_t>(uiIndex);
|
||||
m_vecNodeOrder.insert(itPos, ptrNode);
|
||||
if (ptrNode->GetParentPtr() != Cast<CNodeCollection>())
|
||||
ptrNode->SetViewPtr(Cast<CNodeCollection>());
|
||||
|
||||
// Return the result
|
||||
return ptrNode;
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Stimpfl - initial API and implementation
|
||||
* Erik Verhoeven - writing TOML and whitespace preservation
|
||||
********************************************************************************/
|
||||
|
||||
#include "parser_toml.h"
|
||||
#include <iostream>
|
||||
#include "miscellaneous.h"
|
||||
@@ -15,7 +29,7 @@ namespace toml_parser
|
||||
{
|
||||
m_ptrRoot.reset();
|
||||
m_ptrCurrentCollection.reset();
|
||||
m_lexer.Reset();
|
||||
m_lexer.Clear();
|
||||
while (!m_stackEnvironment.empty())
|
||||
m_stackEnvironment.pop();
|
||||
}
|
||||
@@ -109,6 +123,13 @@ namespace toml_parser
|
||||
|
||||
CNodeCollection& CParser::Root()
|
||||
{
|
||||
// Create the root node if not existing.
|
||||
if (!m_ptrRoot)
|
||||
{
|
||||
m_ptrRoot = std::make_shared<CRootTable>(*this);
|
||||
m_ptrCurrentCollection = m_ptrRoot;
|
||||
}
|
||||
|
||||
auto ptrCollection = m_ptrRoot->Cast<CTable>();
|
||||
return *ptrCollection.get();
|
||||
}
|
||||
@@ -246,7 +267,7 @@ namespace toml_parser
|
||||
auto ptrCurrentCollectionStored = m_ptrCurrentCollection;
|
||||
ptrNode = m_ptrCurrentCollection->Insert<CArray>(sdv::toml::npos, rrangeKeyPath);
|
||||
m_ptrCurrentCollection = ptrNode->Cast<CNodeCollection>();
|
||||
m_stackEnvironment.push(EEnvironment::env_array);
|
||||
m_stackEnvironment.push(EEnvironment::array);
|
||||
ProcessArray(rNodeRange);
|
||||
m_stackEnvironment.pop();
|
||||
m_ptrCurrentCollection = ptrCurrentCollectionStored;
|
||||
@@ -257,7 +278,7 @@ namespace toml_parser
|
||||
auto ptrCurrentCollectionStored = m_ptrCurrentCollection;
|
||||
ptrNode = m_ptrCurrentCollection->Insert<CTable>(sdv::toml::npos, rrangeKeyPath, true);
|
||||
m_ptrCurrentCollection = ptrNode->Cast<CNodeCollection>();
|
||||
m_stackEnvironment.push(EEnvironment::env_inline_table);
|
||||
m_stackEnvironment.push(EEnvironment::inline_table);
|
||||
ProcessInlineTable(rNodeRange);
|
||||
m_stackEnvironment.pop();
|
||||
m_ptrCurrentCollection = ptrCurrentCollectionStored;
|
||||
@@ -275,8 +296,9 @@ namespace toml_parser
|
||||
std::reference_wrapper<const CToken> refToken = m_lexer.Peek();
|
||||
if (!m_stackEnvironment.empty())
|
||||
{
|
||||
// Skip newlines
|
||||
while (refToken.get().Category() == ETokenCategory::token_syntax_new_line)
|
||||
// Skip newlines if not an inline table
|
||||
while (m_stackEnvironment.top() != EEnvironment::inline_table &&
|
||||
refToken.get().Category() == ETokenCategory::token_syntax_new_line)
|
||||
{
|
||||
m_lexer.Consume();
|
||||
refToken = m_lexer.Peek();
|
||||
@@ -284,7 +306,7 @@ namespace toml_parser
|
||||
|
||||
switch (m_stackEnvironment.top())
|
||||
{
|
||||
case EEnvironment::env_array:
|
||||
case EEnvironment::array:
|
||||
{
|
||||
int32_t index = 1;
|
||||
while (refToken.get() && refToken.get().Category() == ETokenCategory::token_syntax_new_line)
|
||||
@@ -299,7 +321,7 @@ namespace toml_parser
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EEnvironment::env_inline_table:
|
||||
case EEnvironment::inline_table:
|
||||
if (!refToken.get()
|
||||
|| (refToken.get().Category() != ETokenCategory::token_syntax_comma
|
||||
&& refToken.get().Category() != ETokenCategory::token_syntax_inline_table_close))
|
||||
@@ -433,7 +455,7 @@ namespace toml_parser
|
||||
switch (refToken.get().Category())
|
||||
{
|
||||
case ETokenCategory::token_syntax_new_line:
|
||||
m_lexer.Consume();
|
||||
throw XTOMLParseException("Line break within an inline table is not allowed.");
|
||||
break;
|
||||
case ETokenCategory::token_syntax_comma:
|
||||
if (eExpect != EExpect::comma_or_end) throw XTOMLParseException("Expecting value or table end.");
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Stimpfl - initial API and implementation
|
||||
* Erik Verhoeven - writing TOML and whitespace preservation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef PARSER_TOML_H
|
||||
#define PARSER_TOML_H
|
||||
|
||||
@@ -19,16 +33,11 @@ namespace toml_parser
|
||||
class CParser : public sdv::IInterfaceAccess, public sdv::toml::ITOMLParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
CParser() = default;
|
||||
|
||||
/**
|
||||
* @brief Construct a new Parser object
|
||||
* @param[in] rssString UTF-8 encoded data of a TOML source
|
||||
*/
|
||||
CParser(const std::string& rssString);
|
||||
CParser(const std::string& rssString = std::string());
|
||||
|
||||
// Interface map
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
@@ -125,14 +134,15 @@ namespace toml_parser
|
||||
*/
|
||||
enum class EEnvironment
|
||||
{
|
||||
env_array, ///< Environment for an array
|
||||
env_inline_table ///< Environment for a table
|
||||
none, ///< No nested environment (used as default environment).
|
||||
array, ///< Environment for an array
|
||||
inline_table ///< Environment for a table
|
||||
};
|
||||
|
||||
std::stack<EEnvironment> m_stackEnvironment; ///< Tracking of environments in nested structures.
|
||||
std::shared_ptr<CRootTable> m_ptrRoot; ///< The one root node.
|
||||
std::shared_ptr<CNodeCollection> m_ptrCurrentCollection; ///< The current collection node.
|
||||
CLexer m_lexer; ///< Lexer.
|
||||
enum_stack<EEnvironment, EEnvironment::none> m_stackEnvironment; ///< Tracking of environments in nested structures.
|
||||
std::shared_ptr<CRootTable> m_ptrRoot; ///< The one root node.
|
||||
std::shared_ptr<CNodeCollection> m_ptrCurrentCollection; ///< The current collection node.
|
||||
CLexer m_lexer; ///< Lexer.
|
||||
};
|
||||
} // namespace toml_parser
|
||||
|
||||
|
||||
Reference in New Issue
Block a user