diff dep/toml11/toml/combinator.hpp @ 318:3b355fa948c7

config: use TOML instead of INI unfortunately, INI is not enough, and causes some paths including semicolons to break with our current storage of the library folders. so, I decided to switch to TOML which does support real arrays...
author Paper <paper@paper.us.eu.org>
date Wed, 12 Jun 2024 05:25:41 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/combinator.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,306 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_COMBINATOR_HPP
+#define TOML11_COMBINATOR_HPP
+#include <cassert>
+#include <cctype>
+#include <cstdio>
+
+#include <array>
+#include <iomanip>
+#include <iterator>
+#include <limits>
+#include <type_traits>
+
+#include "region.hpp"
+#include "result.hpp"
+#include "traits.hpp"
+#include "utility.hpp"
+
+// they scans characters and returns region if it matches to the condition.
+// when they fail, it does not change the location.
+// in lexer.hpp, these are used.
+
+namespace toml
+{
+namespace detail
+{
+
+// to output character as an error message.
+inline std::string show_char(const char c)
+{
+    // It suppresses an error that occurs only in Debug mode of MSVC++ on Windows.
+    // I'm not completely sure but they check the value of char to be in the
+    // range [0, 256) and some of the COMPLETELY VALID utf-8 character sometimes
+    // has negative value (if char has sign). So here it re-interprets c as
+    // unsigned char through pointer. In general, converting pointer to a
+    // pointer that has different type cause UB, but `(signed|unsigned)?char`
+    // are one of the exceptions. Converting pointer only to char and std::byte
+    // (c++17) are valid.
+    if(std::isgraph(*reinterpret_cast<unsigned char const*>(std::addressof(c))))
+    {
+        return std::string(1, c);
+    }
+    else
+    {
+        std::array<char, 5> buf;
+        buf.fill('\0');
+        const auto r = std::snprintf(
+                buf.data(), buf.size(), "0x%02x", static_cast<int>(c) & 0xFF);
+        (void) r; // Unused variable warning
+        assert(r == static_cast<int>(buf.size()) - 1);
+        return std::string(buf.data());
+    }
+}
+
+template<char C>
+struct character
+{
+    static constexpr char target = C;
+
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        if(loc.iter() == loc.end()) {return none();}
+        const auto first = loc.iter();
+
+        const char c = *(loc.iter());
+        if(c != target)
+        {
+            return none();
+        }
+        loc.advance(); // update location
+
+        return ok(region(loc, first, loc.iter()));
+    }
+};
+template<char C>
+constexpr char character<C>::target;
+
+// closed interval [Low, Up]. both Low and Up are included.
+template<char Low, char Up>
+struct in_range
+{
+    // assuming ascii part of UTF-8...
+    static_assert(Low <= Up, "lower bound should be less than upper bound.");
+
+    static constexpr char upper = Up;
+    static constexpr char lower = Low;
+
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        if(loc.iter() == loc.end()) {return none();}
+        const auto first = loc.iter();
+
+        const char c = *(loc.iter());
+        if(c < lower || upper < c)
+        {
+            return none();
+        }
+
+        loc.advance();
+        return ok(region(loc, first, loc.iter()));
+    }
+};
+template<char L, char U> constexpr char in_range<L, U>::upper;
+template<char L, char U> constexpr char in_range<L, U>::lower;
+
+// keep iterator if `Combinator` matches. otherwise, increment `iter` by 1 char.
+// for detecting invalid characters, like control sequences in toml string.
+template<typename Combinator>
+struct exclude
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        if(loc.iter() == loc.end()) {return none();}
+        auto first = loc.iter();
+
+        auto rslt = Combinator::invoke(loc);
+        if(rslt.is_ok())
+        {
+            loc.reset(first);
+            return none();
+        }
+        loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but...
+        return ok(region(loc, first, loc.iter()));
+    }
+};
+
+// increment `iter`, if matches. otherwise, just return empty string.
+template<typename Combinator>
+struct maybe
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        const auto rslt = Combinator::invoke(loc);
+        if(rslt.is_ok())
+        {
+            return rslt;
+        }
+        return ok(region(loc));
+    }
+};
+
+template<typename ... Ts>
+struct sequence;
+
+template<typename Head, typename ... Tail>
+struct sequence<Head, Tail...>
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        const auto first = loc.iter();
+        auto rslt = Head::invoke(loc);
+        if(rslt.is_err())
+        {
+            loc.reset(first);
+            return none();
+        }
+        return sequence<Tail...>::invoke(loc, std::move(rslt.unwrap()), first);
+    }
+
+    // called from the above function only, recursively.
+    template<typename Iterator>
+    static result<region, none_t>
+    invoke(location& loc, region reg, Iterator first)
+    {
+        const auto rslt = Head::invoke(loc);
+        if(rslt.is_err())
+        {
+            loc.reset(first);
+            return none();
+        }
+        reg += rslt.unwrap(); // concat regions
+        return sequence<Tail...>::invoke(loc, std::move(reg), first);
+    }
+};
+
+template<typename Head>
+struct sequence<Head>
+{
+    // would be called from sequence<T ...>::invoke only.
+    template<typename Iterator>
+    static result<region, none_t>
+    invoke(location& loc, region reg, Iterator first)
+    {
+        const auto rslt = Head::invoke(loc);
+        if(rslt.is_err())
+        {
+            loc.reset(first);
+            return none();
+        }
+        reg += rslt.unwrap(); // concat regions
+        return ok(reg);
+    }
+};
+
+template<typename ... Ts>
+struct either;
+
+template<typename Head, typename ... Tail>
+struct either<Head, Tail...>
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        const auto rslt = Head::invoke(loc);
+        if(rslt.is_ok()) {return rslt;}
+        return either<Tail...>::invoke(loc);
+    }
+};
+template<typename Head>
+struct either<Head>
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        return Head::invoke(loc);
+    }
+};
+
+template<typename T, typename N>
+struct repeat;
+
+template<std::size_t N> struct exactly{};
+template<std::size_t N> struct at_least{};
+struct unlimited{};
+
+template<typename T, std::size_t N>
+struct repeat<T, exactly<N>>
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        region retval(loc);
+        const auto first = loc.iter();
+        for(std::size_t i=0; i<N; ++i)
+        {
+            auto rslt = T::invoke(loc);
+            if(rslt.is_err())
+            {
+                loc.reset(first);
+                return none();
+            }
+            retval += rslt.unwrap();
+        }
+        return ok(std::move(retval));
+    }
+};
+
+template<typename T, std::size_t N>
+struct repeat<T, at_least<N>>
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        region retval(loc);
+
+        const auto first = loc.iter();
+        for(std::size_t i=0; i<N; ++i)
+        {
+            auto rslt = T::invoke(loc);
+            if(rslt.is_err())
+            {
+                loc.reset(first);
+                return none();
+            }
+            retval += rslt.unwrap();
+        }
+        while(true)
+        {
+            auto rslt = T::invoke(loc);
+            if(rslt.is_err())
+            {
+                return ok(std::move(retval));
+            }
+            retval += rslt.unwrap();
+        }
+    }
+};
+
+template<typename T>
+struct repeat<T, unlimited>
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        region retval(loc);
+        while(true)
+        {
+            auto rslt = T::invoke(loc);
+            if(rslt.is_err())
+            {
+                return ok(std::move(retval));
+            }
+            retval += rslt.unwrap();
+        }
+    }
+};
+
+} // detail
+} // toml
+#endif// TOML11_COMBINATOR_HPP