Skip to content

Commit

Permalink
fixed date parsing when the year has a leading zero (closes #130)
Browse files Browse the repository at this point in the history
also:
- fixed omitting value part from hex/bin/oct being accepted without error (closes #129)
- added spec bug github template
  • Loading branch information
marzer committed Jan 5, 2022
1 parent b41e12f commit de2413e
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 25 deletions.
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
name: Bug report
about: Found a bug? Help me squash it.
about: Regular ol' bugs.
title: ''
labels: bug
labels: [ "bug" ]
assignees: marzer

---
Expand Down
55 changes: 55 additions & 0 deletions .github/ISSUE_TEMPLATE/spec_bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
name: TOML spec conformance bug
about: Bugs relating to the library's TOML spec conformance (or lack thereof).
title: ''
labels: [ "bug", "TOML spec" ]
assignees: marzer

---

<!--
Replace the HTML/TOML comments below with the requested information.
Please don't delete this template and roll your own!
Thanks for contributing!
-->


## The non-conforming TOML snippet
```toml

# your TOML here

```


## What you expected
<!--
e.g. a link to, or snippet from, the TOML spec, or some reasonable description thereof
-->


## What you got
<!--
e.g toml-test output
-->


## Environment
**toml++ version and/or commit hash:**
<!--
If you're using the single-header version of the library, the version number is right at the top of the file.
Otherwise you can find it by opening toml++/impl/version.h; it'll be represented by three defines -
TOML_LIB_MAJOR, TOML_LIB_MINOR and TOML_LIB_PATCH.
If you're not using any particular release and are instead just living large at HEAD of master, the commit hash
would be super helpful too, though it's not critical.
-->

**Any other useful information:**
<!--
Anything else you think will help me fix the issue. Since this report is for general spec conformance handling
you probably don't need to worry about compiler versions, compilation flags, et cetera, though include them if
you feel they're relevant.
-->
5 changes: 2 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ code changes at callsites or in build systems are indicated with ⚠&#xFE0F;.
- fixed missing `TOML_API` on interfaces
- fixed parser not correctly round-tripping the format of binary and octal integers in some cases
- fixed strong exception guarantee edge-cases in `toml::table` and `toml::array`
- fixed some incorrect unicode scalar sequence transformations (#125) (@moorereason)
- fixed extended-precision fractional times causing parse error instead of truncating per the spec (#127) (@moorereason)
- fixed some non-spec vertical whitespace being accepted as line breaks (#128) (@moorereason)
- fixed some incorrect unicode scalar sequence transformations (#125)
- fixed a number of spec conformance issues (#127, #128, #129) (@moorereason)

#### Additions:
- added `operator->` to `toml::value` for class types
Expand Down
2 changes: 1 addition & 1 deletion include/toml++/impl/formatter.inl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

TOML_IMPL_NAMESPACE_START
{
enum class formatted_string_traits : unsigned
enum class TOML_CLOSED_FLAGS_ENUM formatted_string_traits : unsigned
{
none,
line_breaks = 1u << 0, // \n
Expand Down
2 changes: 1 addition & 1 deletion include/toml++/impl/forward_declarations.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ TOML_NAMESPACE_START // abi namespace
}

/// \brief Metadata associated with TOML values.
enum class TOML_OPEN_FLAGS_ENUM value_flags : uint16_t
enum class TOML_OPEN_FLAGS_ENUM value_flags : uint16_t // being an "OPEN" flags enum is not an error
{
/// \brief None.
none,
Expand Down
26 changes: 18 additions & 8 deletions include/toml++/impl/parser.inl
Original file line number Diff line number Diff line change
Expand Up @@ -2088,6 +2088,9 @@ TOML_IMPL_NAMESPACE_START
if (*cp != traits::prefix_codepoint)
set_error_and_return_default("expected '"sv, traits::prefix, "', saw '"sv, to_sv(*cp), "'"sv);
advance_and_return_if_error_or_eof({});

if (!traits::is_digit(*cp))
set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
}

// consume value chars
Expand Down Expand Up @@ -2400,7 +2403,6 @@ TOML_IMPL_NAMESPACE_START
node_ptr parse_inline_table();

TOML_NODISCARD
TOML_NEVER_INLINE
node_ptr parse_value_known_prefixes()
{
return_if_error({});
Expand Down Expand Up @@ -2505,8 +2507,8 @@ TOML_IMPL_NAMESPACE_START
begins_zero = 1 << 14,

signs_msk = has_plus | has_minus,
bzero_msk = begins_zero | has_digits,
bdigit_msk = begins_digit | has_digits,
bdigit_msk = has_digits | begins_digit,
bzero_msk = bdigit_msk | begins_zero,
};
value_traits traits = has_nothing;
const auto has_any = [&](auto t) noexcept { return (traits & t) != has_nothing; };
Expand All @@ -2516,7 +2518,11 @@ TOML_IMPL_NAMESPACE_START
// examine the first character to get the 'begins with' traits
// (good fail-fast opportunity; all the remaining types begin with numeric digits or signs)
if (is_decimal_digit(*cp))
add_trait(*cp == U'0' ? begins_zero : begins_digit);
{
add_trait(begins_digit);
if (*cp == U'0')
add_trait(begins_zero);
}
else if (is_match(*cp, U'+', U'-'))
add_trait(begins_sign);
else
Expand Down Expand Up @@ -2601,8 +2607,12 @@ TOML_IMPL_NAMESPACE_START
return_if_error({});

// force further scanning if this could have been a date-time with a space instead of a T
if (char_count == 10u && traits == (bdigit_msk | has_minus) && chars[4] == U'-' && chars[7] == U'-'
&& !is_eof() && *cp == U' ')
if (char_count == 10u //
&& (traits | begins_zero) == (bzero_msk | has_minus) //
&& chars[4] == U'-' //
&& chars[7] == U'-' //
&& !is_eof() //
&& *cp == U' ')
{
const auto pre_advance_count = advance_count;
const auto pre_scan_traits = traits;
Expand Down Expand Up @@ -2646,7 +2656,7 @@ TOML_IMPL_NAMESPACE_START
// the only valid value type is an integer.
if (char_count == 1u)
{
if (has_any(begins_zero | begins_digit))
if (has_any(begins_digit))
{
val.reset(new value{ static_cast<int64_t>(chars[0] - U'0') });
advance(); // skip the digit
Expand Down Expand Up @@ -2692,7 +2702,7 @@ TOML_IMPL_NAMESPACE_START
val.reset(new value{ i });
val->ref_cast<int64_t>().flags(flags);
}
else if (has_any(has_e) || (has_any(begins_zero | begins_digit) && chars[1] == U'.'))
else if (has_any(has_e) || (has_any(begins_digit) && chars[1] == U'.'))
val.reset(new value{ parse_float() });
else if (has_any(begins_sign))
{
Expand Down
5 changes: 5 additions & 0 deletions tests/parsing_integers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ TEST_CASE("parsing - integers (hex, bin, oct)")
parsing_should_fail(FILE_LINE_ARGS, "val = 0o1000000000000000000000"sv);
parsing_should_fail(FILE_LINE_ARGS, "val = 0b1000000000000000000000000000000000000000000000000000000000000000"sv);

// missing values after base prefix
parsing_should_fail(FILE_LINE_ARGS, "val = 0x "sv);
parsing_should_fail(FILE_LINE_ARGS, "val = 0o "sv);
parsing_should_fail(FILE_LINE_ARGS, "val = 0b "sv);

// value tests
parse_expected_value(FILE_LINE_ARGS, "0xDEADBEEF"sv, 0xDEADBEEF);
parse_expected_value(FILE_LINE_ARGS, "0xdeadbeef"sv, 0xDEADBEEF);
Expand Down
17 changes: 17 additions & 0 deletions tests/user_feedback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,21 @@ b = []
parsing_should_succeed(FILE_LINE_ARGS, "\t"sv);
parsing_should_succeed(FILE_LINE_ARGS, "\n"sv);
}

SECTION("github/issues/129") // https://github.com/marzer/tomlplusplus/issues/129
{
parsing_should_fail(FILE_LINE_ARGS, R"(
hex = 0x
oct = 0o
bin = 0b
)"sv);
}

SECTION("github/issues/130") // https://github.com/marzer/tomlplusplus/issues/130
{
parse_expected_value(FILE_LINE_ARGS, "0400-01-01 00:00:00"sv, toml::date_time{ { 400, 1, 1 }, { 0, 0, 0 } });
parse_expected_value(FILE_LINE_ARGS, "0400-01-01 "sv, toml::date{ 400, 1, 1 });
parse_expected_value(FILE_LINE_ARGS, "0400-01-01T00:00:00"sv, toml::date_time{ { 400, 1, 1 }, { 0, 0, 0 } });
parse_expected_value(FILE_LINE_ARGS, "1000-01-01 00:00:00"sv, toml::date_time{ { 1000, 1, 1 }, { 0, 0, 0 } });
}
}
1 change: 1 addition & 0 deletions toml++.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<None Include=".github\ISSUE_TEMPLATE\bug_report.md" />
<None Include=".github\ISSUE_TEMPLATE\config.yml" />
<None Include=".github\ISSUE_TEMPLATE\feature_request.md" />
<None Include=".github\ISSUE_TEMPLATE\spec_bug_report.md" />
<None Include=".github\pull_request_template.md" />
<None Include=".gitignore" />
<None Include=".runsettings" />
Expand Down
3 changes: 3 additions & 0 deletions toml++.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@
<None Include="include\toml++\impl\unicode.inl">
<Filter>include\impl</Filter>
</None>
<None Include=".github\ISSUE_TEMPLATE\spec_bug_report.md">
<Filter>.github</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Filter Include=".circleci">
Expand Down
30 changes: 20 additions & 10 deletions toml.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,7 @@ TOML_NAMESPACE_START // abi namespace
}
}

enum class TOML_OPEN_FLAGS_ENUM value_flags : uint16_t
enum class TOML_OPEN_FLAGS_ENUM value_flags : uint16_t // being an "OPEN" flags enum is not an error
{
none,
format_as_binary = 1,
Expand Down Expand Up @@ -12698,6 +12698,9 @@ TOML_IMPL_NAMESPACE_START
if (*cp != traits::prefix_codepoint)
set_error_and_return_default("expected '"sv, traits::prefix, "', saw '"sv, to_sv(*cp), "'"sv);
advance_and_return_if_error_or_eof({});

if (!traits::is_digit(*cp))
set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
}

// consume value chars
Expand Down Expand Up @@ -13010,7 +13013,6 @@ TOML_IMPL_NAMESPACE_START
node_ptr parse_inline_table();

TOML_NODISCARD
TOML_NEVER_INLINE
node_ptr parse_value_known_prefixes()
{
return_if_error({});
Expand Down Expand Up @@ -13114,8 +13116,8 @@ TOML_IMPL_NAMESPACE_START
begins_digit = 1 << 13,
begins_zero = 1 << 14,
signs_msk = has_plus | has_minus,
bzero_msk = begins_zero | has_digits,
bdigit_msk = begins_digit | has_digits,
bdigit_msk = has_digits | begins_digit,
bzero_msk = bdigit_msk | begins_zero,
};
value_traits traits = has_nothing;
const auto has_any = [&](auto t) noexcept { return (traits & t) != has_nothing; };
Expand All @@ -13125,7 +13127,11 @@ TOML_IMPL_NAMESPACE_START
// examine the first character to get the 'begins with' traits
// (good fail-fast opportunity; all the remaining types begin with numeric digits or signs)
if (is_decimal_digit(*cp))
add_trait(*cp == U'0' ? begins_zero : begins_digit);
{
add_trait(begins_digit);
if (*cp == U'0')
add_trait(begins_zero);
}
else if (is_match(*cp, U'+', U'-'))
add_trait(begins_sign);
else
Expand Down Expand Up @@ -13210,8 +13216,12 @@ TOML_IMPL_NAMESPACE_START
return_if_error({});

// force further scanning if this could have been a date-time with a space instead of a T
if (char_count == 10u && traits == (bdigit_msk | has_minus) && chars[4] == U'-' && chars[7] == U'-'
&& !is_eof() && *cp == U' ')
if (char_count == 10u //
&& (traits | begins_zero) == (bzero_msk | has_minus) //
&& chars[4] == U'-' //
&& chars[7] == U'-' //
&& !is_eof() //
&& *cp == U' ')
{
const auto pre_advance_count = advance_count;
const auto pre_scan_traits = traits;
Expand Down Expand Up @@ -13255,7 +13265,7 @@ TOML_IMPL_NAMESPACE_START
// the only valid value type is an integer.
if (char_count == 1u)
{
if (has_any(begins_zero | begins_digit))
if (has_any(begins_digit))
{
val.reset(new value{ static_cast<int64_t>(chars[0] - U'0') });
advance(); // skip the digit
Expand Down Expand Up @@ -13301,7 +13311,7 @@ TOML_IMPL_NAMESPACE_START
val.reset(new value{ i });
val->ref_cast<int64_t>().flags(flags);
}
else if (has_any(has_e) || (has_any(begins_zero | begins_digit) && chars[1] == U'.'))
else if (has_any(has_e) || (has_any(begins_digit) && chars[1] == U'.'))
val.reset(new value{ parse_float() });
else if (has_any(begins_sign))
{
Expand Down Expand Up @@ -14403,7 +14413,7 @@ TOML_PUSH_WARNINGS;

TOML_IMPL_NAMESPACE_START
{
enum class formatted_string_traits : unsigned
enum class TOML_CLOSED_FLAGS_ENUM formatted_string_traits : unsigned
{
none,
line_breaks = 1u << 0, // \n
Expand Down

0 comments on commit de2413e

Please sign in to comment.