Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add docs and address other PR comments #5

Merged
merged 5 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ endif()
option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ${JSON_BuildTests_INIT})
option(JSON_CI "Enable CI build targets." OFF)
option(JSON_Diagnostics "Use extended diagnostic messages." OFF)
option(JSON_Diagnostic_Positions "Enable diagnostic positions." OFF)
option(JSON_GlobalUDLs "Place user-defined string literals in the global namespace." ON)
option(JSON_ImplicitConversions "Enable implicit conversions." ON)
option(JSON_DisableEnumSerialization "Disable default integer enum serialization." OFF)
Expand Down Expand Up @@ -96,6 +97,10 @@ if (JSON_Diagnostics)
message(STATUS "Diagnostics enabled")
endif()

if (JSON_Diagnostic_Positions)
message(STATUS "Diagnostic positions enabled")
endif()

if (NOT JSON_GlobalUDLs)
message(STATUS "User-defined string literals are not put in the global namespace")
endif()
Expand Down Expand Up @@ -123,6 +128,7 @@ target_compile_definitions(
$<$<NOT:$<BOOL:${JSON_ImplicitConversions}>>:JSON_USE_IMPLICIT_CONVERSIONS=0>
$<$<BOOL:${JSON_DisableEnumSerialization}>:JSON_DISABLE_ENUM_SERIALIZATION=1>
$<$<BOOL:${JSON_Diagnostics}>:JSON_DIAGNOSTICS=1>
$<$<BOOL:${JSON_Diagnostic_Positions}>:JSON_DIAGNOSTIC_POSITIONS=1>
$<$<BOOL:${JSON_LegacyDiscardedValueComparison}>:JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1>
)

Expand Down
35 changes: 35 additions & 0 deletions docs/examples/diagnostic_positions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <iostream>

# define JSON_DIAGNOSTIC_POSITIONS 1
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main()
{
std::string json_string = R"(
{
"address": {
"street": "Fake Street",
"housenumber": 1
}
}
)";
json j = json::parse(json_string);

std::cout << "Root diagnostic positions: \n";
std::cout << "\tstart_pos: " << j.start_pos() << '\n';
std::cout << "\tend_pos:" << j.end_pos() << "\n\n";

std::cout << "address diagnostic positions: \n";
std::cout << "\tstart_pos:" << j["address"].start_pos() << '\n';
std::cout << "\tend_pos:" << j["address"].end_pos() << "\n\n";

std::cout << "street diagnostic positions: \n";
std::cout << "\tstart_pos:" << j["address"]["street"].start_pos() << '\n';
std::cout << "\tend_pos:" << j["address"]["street"].end_pos() << "\n\n";

std::cout << "housenumber diagnostic positions: \n";
std::cout << "\tstart_pos:" << j["address"]["housenumber"].start_pos() << '\n';
std::cout << "\tend_pos:" << j["address"]["housenumber"].end_pos() << "\n\n";
}
15 changes: 15 additions & 0 deletions docs/examples/diagnostic_positions.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Root diagnostic positions:
start_pos: 5
end_pos:109

address diagnostic positions:
start_pos:26
end_pos:103

street diagnostic positions:
start_pos:50
end_pos:63

housenumber diagnostic positions:
start_pos:92
end_pos:93
52 changes: 52 additions & 0 deletions docs/mkdocs/docs/api/macros/json_diagnostic_positions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# JSON_DIAGNOSTIC_POSITIONS

```cpp
#define JSON_DIAGNOSTIC_POSITIONS /* value */
```

This macro enables position diagnostics for generated JSON objects.

When enabled, two new properties: `start_pos()` and `end_pos()` are added to `nlohmann::json` objects and fields. `start_pos()` returns the start position of that JSON object/field in the original string the object was parsed from. Likewise, `end_pos()` returns the end position of that JSON object/field in the original string the object was parsed from.

For objects and arrays, the start and end positions represent the positions of the opening and closing braces or brackets, respectively. For fields, the start and end positions represent either the opening and closing quotes for that field's value or the first and character after last in the field's numerical or predefined true/false/null values.

`start_pos()` and `end_pos()` are only set if the JSON object was parsed using `json::parse()`. For all other cases, `std::string::npos` will be returned.

Note that enabling this macro increases the size of every JSON value by two size_t fields and adds
slight runtime overhead.

## Default definition

The default value is `0` (position diagnostics are switched off).

```cpp
#define JSON_DIAGNOSTIC_POSITIONS 0
```

When the macro is not defined, the library will define it to its default value.

## Notes

!!! hint "CMake option"

Diagnostic messages can also be controlled with the CMake option
[`JSON_Diagnostic_Positions`](../../integration/cmake.md#json_diagnostic_positions) (`OFF` by default)
which defines `JSON_DIAGNOSTIC_POSITIONS` accordingly.

## Examples

??? example "Example 1: retrieving positions"

```cpp
--8<-- "examples/diagnostic_positions.cpp"
```

Output:

```
--8<-- "examples/diagnostic_positions.output"
```

The output shows the start/end positions of all the objects and fields in the JSON string.
## Version history

3 changes: 3 additions & 0 deletions docs/mkdocs/docs/integration/cmake.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ Enable CI build targets. The exact targets are used during the several CI steps

Enable [extended diagnostic messages](../home/exceptions.md#extended-diagnostic-messages) by defining macro [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This option is `OFF` by default.

### `JSON_Diagnostic_Positions`
Enable position diagnostics by defining macro [`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md). This option is off by default.

### `JSON_DisableEnumSerialization`

Disable default `enum` serialization by defining the macro
Expand Down
12 changes: 6 additions & 6 deletions include/nlohmann/detail/abi_macros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
#define JSON_DIAGNOSTICS 0
#endif

#ifndef DIAGNOSTIC_POSITIONS
#define DIAGNOSTIC_POSITIONS 0
#ifndef JSON_DIAGNOSTIC_POSITIONS
#define JSON_DIAGNOSTIC_POSITIONS 0
#endif

#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
Expand All @@ -40,10 +40,10 @@
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
#endif

#if DIAGNOSTIC_POSITIONS
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp
#if JSON_DIAGNOSTIC_POSITIONS
#define NLOHMANN_JSON_ABI_TAG_JSON_DIAGNOSTIC_POSITIONS _dp
#else
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS
#define NLOHMANN_JSON_ABI_TAG_JSON_DIAGNOSTIC_POSITIONS
#endif

#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
Expand All @@ -65,7 +65,7 @@
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \
NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS)
NLOHMANN_JSON_ABI_TAG_JSON_DIAGNOSTIC_POSITIONS)

// Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
Expand Down
2 changes: 1 addition & 1 deletion include/nlohmann/detail/input/input_adapters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ typename container_input_adapter_factory_impl::container_input_adapter_factory<C
}

// specialization for std::string
using string_input_adapter = decltype(input_adapter(std::declval<std::string>()));
using string_input_adapter_type = decltype(input_adapter(std::declval<std::string>()));
sushshring marked this conversation as resolved.
Show resolved Hide resolved

#ifndef JSON_NO_IO
// Special cases with fast paths
Expand Down
44 changes: 29 additions & 15 deletions include/nlohmann/detail/input/json_sax.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/string_concat.hpp>
#include <nlohmann/detail/input/lexer.hpp>

NLOHMANN_JSON_NAMESPACE_BEGIN

/*!
Expand Down Expand Up @@ -231,7 +232,7 @@ class json_sax_dom_parser
{
ref_stack.push_back(handle_value(BasicJsonType::value_t::object));

#if DIAGNOSTIC_POSITIONS
#if JSON_DIAGNOSTIC_POSITIONS
// Manually set the start position of the object here.
// Ensure this is after the call to handle_value to ensure correct start position.
if (m_lexer_ref)
Expand Down Expand Up @@ -265,7 +266,7 @@ class json_sax_dom_parser
JSON_ASSERT(!ref_stack.empty());
JSON_ASSERT(ref_stack.back()->is_object());

#if DIAGNOSTIC_POSITIONS
#if JSON_DIAGNOSTIC_POSITIONS
if (m_lexer_ref)
{
ref_stack.back()->end_position = m_lexer_ref->get_position();
Expand All @@ -281,7 +282,7 @@ class json_sax_dom_parser
{
ref_stack.push_back(handle_value(BasicJsonType::value_t::array));

#if DIAGNOSTIC_POSITIONS
#if JSON_DIAGNOSTIC_POSITIONS
// Manually set the start position of the array here.
// Ensure this is after the call to handle_value to ensure correct start position.
if (m_lexer_ref)
Expand All @@ -303,7 +304,7 @@ class json_sax_dom_parser
JSON_ASSERT(!ref_stack.empty());
JSON_ASSERT(ref_stack.back()->is_array());

#if DIAGNOSTIC_POSITIONS
#if JSON_DIAGNOSTIC_POSITIONS
if (m_lexer_ref)
{
ref_stack.back()->end_position = m_lexer_ref->get_position();
Expand Down Expand Up @@ -334,7 +335,8 @@ class json_sax_dom_parser
}

private:
#if DIAGNOSTIC_POSITIONS

#if JSON_DIAGNOSTIC_POSITIONS
void handle_diagnostic_positions_for_json_value(BasicJsonType& v)
{
if (m_lexer_ref)
Expand Down Expand Up @@ -394,6 +396,7 @@ class json_sax_dom_parser
}
}
#endif

/*!
@invariant If the ref stack is empty, then the passed value will be the new
root.
Expand All @@ -408,7 +411,7 @@ class json_sax_dom_parser
{
root = BasicJsonType(std::forward<Value>(v));

#if DIAGNOSTIC_POSITIONS
#if JSON_DIAGNOSTIC_POSITIONS
handle_diagnostic_positions_for_json_value(root);
#endif

Expand All @@ -420,18 +423,22 @@ class json_sax_dom_parser
if (ref_stack.back()->is_array())
{
ref_stack.back()->m_data.m_value.array->emplace_back(std::forward<Value>(v));
#if DIAGNOSTIC_POSITIONS

#if JSON_DIAGNOSTIC_POSITIONS
handle_diagnostic_positions_for_json_value(ref_stack.back()->m_data.m_value.array->back());
#endif

return &(ref_stack.back()->m_data.m_value.array->back());
}

JSON_ASSERT(ref_stack.back()->is_object());
JSON_ASSERT(object_element);
*object_element = BasicJsonType(std::forward<Value>(v));
#if DIAGNOSTIC_POSITIONS

#if JSON_DIAGNOSTIC_POSITIONS
handle_diagnostic_positions_for_json_value(*object_element);
#endif

return object_element;
}

Expand Down Expand Up @@ -463,7 +470,7 @@ class json_sax_dom_callback_parser
using lexer_t = lexer<BasicJsonType, InputAdapterType>;

json_sax_dom_callback_parser(BasicJsonType& r,
const parser_callback_t cb,
parser_callback_t cb,
const bool allow_exceptions_ = true,
lexer_t* lexer_ = nullptr)
: root(r), callback(std::move(cb)), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_)
Expand Down Expand Up @@ -531,7 +538,8 @@ class json_sax_dom_callback_parser

if (ref_stack.back())
{
#if DIAGNOSTIC_POSITIONS

#if JSON_DIAGNOSTIC_POSITIONS
// Manually set the start position of the object here.
// Ensure this is after the call to handle_value to ensure correct start position.
if (m_lexer_ref)
Expand Down Expand Up @@ -579,12 +587,14 @@ class json_sax_dom_callback_parser
}
else
{
#if DIAGNOSTIC_POSITIONS

#if JSON_DIAGNOSTIC_POSITIONS
if (m_lexer_ref)
{
ref_stack.back()->end_position = m_lexer_ref->get_position();
}
#endif

ref_stack.back()->set_parents();
}
}
Expand Down Expand Up @@ -620,7 +630,8 @@ class json_sax_dom_callback_parser

if (ref_stack.back())
{
#if DIAGNOSTIC_POSITIONS

#if JSON_DIAGNOSTIC_POSITIONS
// Manually set the start position of the array here.
// Ensure this is after the call to handle_value to ensure correct start position.
if (m_lexer_ref)
Expand Down Expand Up @@ -650,12 +661,14 @@ class json_sax_dom_callback_parser
keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
if (keep)
{
#if DIAGNOSTIC_POSITIONS

#if JSON_DIAGNOSTIC_POSITIONS
if (m_lexer_ref)
{
ref_stack.back()->end_position = m_lexer_ref->get_position();
}
#endif

ref_stack.back()->set_parents();
}
else
Expand Down Expand Up @@ -699,7 +712,7 @@ class json_sax_dom_callback_parser

private:

#if DIAGNOSTIC_POSITIONS
#if JSON_DIAGNOSTIC_POSITIONS
void handle_diagnostic_positions_for_json_value(BasicJsonType& v)
{
if (m_lexer_ref)
Expand Down Expand Up @@ -789,7 +802,8 @@ class json_sax_dom_callback_parser

// create value
auto value = BasicJsonType(std::forward<Value>(v));
#if DIAGNOSTIC_POSITIONS

#if JSON_DIAGNOSTIC_POSITIONS
handle_diagnostic_positions_for_json_value(value);
#endif

Expand Down
Loading