aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.ucl
diff options
context:
space:
mode:
Diffstat (limited to 'nihil.ucl')
-rw-r--r--nihil.ucl/CMakeLists.txt17
-rw-r--r--nihil.ucl/boolean.cc77
-rw-r--r--nihil.ucl/boolean.ccm60
-rw-r--r--nihil.ucl/emit.cc21
-rw-r--r--nihil.ucl/emit.ccm15
-rw-r--r--nihil.ucl/error.cc19
-rw-r--r--nihil.ucl/error.ccm5
-rw-r--r--nihil.ucl/integer.cc76
-rw-r--r--nihil.ucl/integer.ccm65
-rw-r--r--nihil.ucl/object.cc123
-rw-r--r--nihil.ucl/object.ccm198
-rw-r--r--nihil.ucl/parser.cc75
-rw-r--r--nihil.ucl/parser.ccm58
-rw-r--r--nihil.ucl/real.cc79
-rw-r--r--nihil.ucl/real.ccm65
-rw-r--r--nihil.ucl/string.cc139
-rw-r--r--nihil.ucl/string.ccm122
-rw-r--r--nihil.ucl/type.cc62
-rw-r--r--nihil.ucl/type.ccm48
19 files changed, 775 insertions, 549 deletions
diff --git a/nihil.ucl/CMakeLists.txt b/nihil.ucl/CMakeLists.txt
index cb051a3..0ee024c 100644
--- a/nihil.ucl/CMakeLists.txt
+++ b/nihil.ucl/CMakeLists.txt
@@ -4,8 +4,9 @@ pkg_check_modules(LIBUCL REQUIRED libucl)
add_library(nihil.ucl STATIC)
target_link_libraries(nihil.ucl PUBLIC nihil)
-target_sources(nihil.ucl PUBLIC
- FILE_SET modules TYPE CXX_MODULES FILES
+
+target_sources(nihil.ucl
+ PUBLIC FILE_SET modules TYPE CXX_MODULES FILES
nihil.ucl.ccm
emit.ccm
error.ccm
@@ -20,6 +21,18 @@ target_sources(nihil.ucl PUBLIC
map.ccm
real.ccm
string.ccm
+
+ PRIVATE
+ emit.cc
+ error.cc
+ parser.cc
+ type.cc
+
+ object.cc
+ boolean.cc
+ integer.cc
+ real.cc
+ string.cc
)
target_compile_options(nihil.ucl PUBLIC ${LIBUCL_CFLAGS_OTHER})
diff --git a/nihil.ucl/boolean.cc b/nihil.ucl/boolean.cc
new file mode 100644
index 0000000..95b4e2f
--- /dev/null
+++ b/nihil.ucl/boolean.cc
@@ -0,0 +1,77 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <compare>
+#include <cstdlib>
+
+#include <ucl.h>
+
+module nihil.ucl;
+
+namespace nihil::ucl {
+
+boolean::boolean() : boolean(false)
+{
+}
+
+boolean::boolean(ref_t, ::ucl_object_t const *uobj)
+ : object(nihil::ucl::ref, uobj)
+{
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
+}
+
+boolean::boolean(noref_t, ::ucl_object_t *uobj)
+ : object(noref, uobj)
+{
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
+}
+
+boolean::boolean(contained_type value)
+ : object(noref, ::ucl_object_frombool(value))
+{
+ if (_object == nullptr)
+ throw error("failed to create UCL object");
+}
+
+auto boolean::value(this boolean const &self)
+-> contained_type
+{
+ auto v = contained_type{};
+ auto const *uobj = self.get_ucl_object();
+
+ if (::ucl_object_toboolean_safe(uobj, &v))
+ return v;
+
+ std::abort();
+}
+
+auto operator== (boolean const &a, boolean const &b)
+-> bool
+{
+ return a.value() == b.value();
+}
+
+auto operator<=> (boolean const &a, boolean const &b)
+-> std::strong_ordering
+{
+ return a.value() <=> b.value();
+}
+
+auto operator== (boolean const &a, boolean::contained_type b)
+-> bool
+{
+ return a.value() == b;
+}
+
+auto operator<=> (boolean const &a, boolean::contained_type b)
+-> std::strong_ordering
+{
+ return a.value() <=> b;
+}
+
+} // namespace nihil::ucl
diff --git a/nihil.ucl/boolean.ccm b/nihil.ucl/boolean.ccm
index 6a93867..78ede17 100644
--- a/nihil.ucl/boolean.ccm
+++ b/nihil.ucl/boolean.ccm
@@ -23,70 +23,28 @@ export struct boolean final : object {
inline static constexpr object_type ucl_type = object_type::boolean;
// Create a new boolean from a UCL object.
- boolean(ref_t, ::ucl_object_t const *uobj)
- : object(nihil::ucl::ref, uobj)
- {
- if (type() != ucl_type)
- throw type_mismatch(ucl_type, type());
- }
-
- boolean(noref_t, ::ucl_object_t *uobj)
- : object(noref, uobj)
- {
- if (type() != ucl_type)
- throw type_mismatch(ucl_type, type());
- }
+ boolean(ref_t, ::ucl_object_t const *uobj);
+ boolean(noref_t, ::ucl_object_t *uobj);
// Create a new default-initialised boolean.
- boolean() : boolean(false) {}
+ boolean();
// Create a new boolean from a value.
- explicit boolean(contained_type value)
- : object(noref, ::ucl_object_frombool(value))
- {
- if (_object == nullptr)
- throw error("failed to create UCL object");
- }
+ explicit boolean(contained_type value);
// Return this object's value.
- auto value(this boolean const &self) -> contained_type
- {
- auto v = contained_type{};
- auto const *uobj = self.get_ucl_object();
-
- if (::ucl_object_toboolean_safe(uobj, &v))
- return v;
-
- std::abort();
- }
+ auto value(this boolean const &self) -> contained_type;
};
/*
* Comparison operators.
*/
-export auto operator== (boolean const &a, boolean const &b)
- -> bool
-{
- return a.value() == b.value();
-}
-
+export auto operator== (boolean const &a, boolean const &b) -> bool;
+export auto operator== (boolean const &a, boolean::contained_type b) -> bool;
export auto operator<=> (boolean const &a, boolean const &b)
- -> std::strong_ordering
-{
- return a.value() <=> b.value();
-}
-
-export auto operator== (boolean const &a, boolean::contained_type b)
- -> bool
-{
- return a.value() == b;
-}
-
+ -> std::strong_ordering;
export auto operator<=> (boolean const &a, boolean::contained_type b)
- -> std::strong_ordering
-{
- return a.value() <=> b;
-}
+ -> std::strong_ordering;
} // namespace nihil::ucl
diff --git a/nihil.ucl/emit.cc b/nihil.ucl/emit.cc
new file mode 100644
index 0000000..480ddd8
--- /dev/null
+++ b/nihil.ucl/emit.cc
@@ -0,0 +1,21 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <iostream>
+#include <iterator>
+
+module nihil.ucl;
+
+namespace nihil::ucl {
+
+auto operator<<(std::ostream &stream, object const &o)
+-> std::ostream &
+{
+ emit(o, emitter::json, std::ostream_iterator<char>(stream));
+ return stream;
+}
+
+} // namespace nihil::ucl
diff --git a/nihil.ucl/emit.ccm b/nihil.ucl/emit.ccm
index c4aa79b..849c5a7 100644
--- a/nihil.ucl/emit.ccm
+++ b/nihil.ucl/emit.ccm
@@ -9,7 +9,7 @@ module;
#include <cstdlib>
#include <format>
#include <iterator>
-#include <iostream>
+#include <iosfwd>
#include <span>
#include <string>
#include <utility>
@@ -34,8 +34,8 @@ export enum struct emitter {
*
* We can't throw exceptions here since we're called from C code. The emit
* functions return an integer value, but it's not really clear what this is
- * for (for example, returning errors?) and the C API seems to mostly ignore
- * it. So, we just eat errors and keep going.
+ * for and the C API seems to mostly ignore it. So, we just eat errors and
+ * keep going.
*/
template<std::output_iterator<char> Iterator>
struct emit_wrapper {
@@ -130,7 +130,7 @@ private:
export auto emit(object const &object, emitter format,
std::output_iterator<char> auto &&it)
- -> void
+-> void
{
auto ucl_format = static_cast<ucl_emitter>(format);
auto wrapper = emit_wrapper(it);
@@ -144,12 +144,7 @@ export auto emit(object const &object, emitter format,
* Basic ostream printer for UCL; default to JSON since it's probably what
* most people expect.
*/
-export auto operator<<(std::ostream &stream, object const &o)
- -> std::ostream &
-{
- emit(o, emitter::json, std::ostream_iterator<char>(stream));
- return stream;
-}
+export auto operator<<(std::ostream &stream, object const &o) -> std::ostream &;
} // namespace nihil::ucl
diff --git a/nihil.ucl/error.cc b/nihil.ucl/error.cc
new file mode 100644
index 0000000..2f19cb7
--- /dev/null
+++ b/nihil.ucl/error.cc
@@ -0,0 +1,19 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <string>
+#include <utility>
+
+module nihil.ucl;
+
+namespace nihil::ucl {
+
+error::error(std::string what)
+ : generic_error(std::move(what))
+{
+}
+
+} // namespace nihil::ucl
diff --git a/nihil.ucl/error.ccm b/nihil.ucl/error.ccm
index c6a0f2d..cdb5c2b 100644
--- a/nihil.ucl/error.ccm
+++ b/nihil.ucl/error.ccm
@@ -4,8 +4,7 @@
module;
-#include <format>
-#include <utility>
+#include <string>
export module nihil.ucl:error;
@@ -17,7 +16,7 @@ namespace nihil::ucl {
* Exception thrown when an issue occurs with UCL.
*/
export struct error : generic_error {
- error(std::string what) : generic_error(std::move(what)) {}
+ error(std::string what);
};
} // namespace nihil::ucl
diff --git a/nihil.ucl/integer.cc b/nihil.ucl/integer.cc
new file mode 100644
index 0000000..16328d4
--- /dev/null
+++ b/nihil.ucl/integer.cc
@@ -0,0 +1,76 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <compare>
+#include <cstdlib>
+
+#include <ucl.h>
+
+module nihil.ucl;
+
+namespace nihil::ucl {
+
+integer::integer(ref_t, ::ucl_object_t const *uobj)
+ : object(nihil::ucl::ref, uobj)
+{
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
+}
+
+integer::integer(noref_t, ::ucl_object_t *uobj)
+ : object(noref, uobj)
+{
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
+}
+
+integer::integer()
+ : integer(0)
+{}
+
+integer::integer(contained_type value)
+ : object(noref, ::ucl_object_fromint(value))
+{
+ if (_object == nullptr)
+ throw error("failed to create UCL object");
+}
+
+auto integer::value(this integer const &self) -> contained_type
+{
+ auto v = contained_type{};
+ auto const *uobj = self.get_ucl_object();
+
+ if (::ucl_object_toint_safe(uobj, &v))
+ return v;
+
+ std::abort();
+}
+
+auto operator== (integer const &a, integer const &b)
+-> bool
+{
+ return a.value() == b.value();
+}
+
+auto operator<=> (integer const &a, integer const &b)
+-> std::strong_ordering
+{
+ return a.value() <=> b.value();
+}
+
+auto operator== (integer const &a, integer::contained_type b)
+-> bool
+{
+ return a.value() == b;
+}
+
+auto operator<=> (integer const &a, integer::contained_type b)
+-> std::strong_ordering
+{
+ return a.value() <=> b;
+}
+
+} // namespace nihil::ucl
diff --git a/nihil.ucl/integer.ccm b/nihil.ucl/integer.ccm
index 482a716..e43ae8b 100644
--- a/nihil.ucl/integer.ccm
+++ b/nihil.ucl/integer.ccm
@@ -4,10 +4,9 @@
module;
-#include <cassert>
+#include <compare>
#include <cstdint>
#include <cstdlib>
-#include <string>
#include <ucl.h>
@@ -22,72 +21,28 @@ export struct integer final : object {
inline static constexpr object_type ucl_type = object_type::integer;
// Create a new integer from a UCL object.
- integer(ref_t, ::ucl_object_t const *uobj)
- : object(nihil::ucl::ref, uobj)
- {
- if (type() != ucl_type)
- throw type_mismatch(ucl_type, type());
- }
-
- integer(noref_t, ::ucl_object_t *uobj)
- : object(noref, uobj)
- {
- if (type() != ucl_type)
- throw type_mismatch(ucl_type, type());
- }
+ integer(ref_t, ::ucl_object_t const *uobj);
+ integer(noref_t, ::ucl_object_t *uobj);
// Create a new default-initialised integer.
- integer()
- : integer(0)
- {}
+ integer();
// Create a new integer from a value.
- explicit integer(contained_type value)
- : object(noref, ::ucl_object_fromint(value))
- {
- if (_object == nullptr)
- throw error("failed to create UCL object");
- }
+ explicit integer(contained_type value);
// Return the value of this object.
- auto value(this integer const &self) -> contained_type
- {
- auto v = contained_type{};
- auto const *uobj = self.get_ucl_object();
-
- if (::ucl_object_toint_safe(uobj, &v))
- return v;
-
- std::abort();
- }
+ auto value(this integer const &self) -> contained_type;
};
/*
* Comparison operators.
*/
-export auto operator== (integer const &a, integer const &b)
- -> bool
-{
- return a.value() == b.value();
-}
-
+export auto operator== (integer const &a, integer const &b) -> bool;
+export auto operator== (integer const &a, integer::contained_type b) -> bool;
export auto operator<=> (integer const &a, integer const &b)
- -> std::strong_ordering
-{
- return a.value() <=> b.value();
-}
-
-export auto operator== (integer const &a, integer::contained_type b)
- -> bool
-{
- return a.value() == b;
-}
-
+ -> std::strong_ordering;
export auto operator<=> (integer const &a, integer::contained_type b)
- -> std::strong_ordering
-{
- return a.value() <=> b;
-}
+ -> std::strong_ordering;
} // namespace nihil::ucl
diff --git a/nihil.ucl/object.cc b/nihil.ucl/object.cc
new file mode 100644
index 0000000..f435b90
--- /dev/null
+++ b/nihil.ucl/object.cc
@@ -0,0 +1,123 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <cstdlib>
+#include <string>
+#include <utility>
+
+#include <ucl.h>
+
+module nihil.ucl;
+
+namespace nihil::ucl {
+
+object::object(ref_t, ::ucl_object_t const *object)
+ : _object(::ucl_object_ref(object))
+{
+}
+
+object::object(noref_t, ::ucl_object_t *object)
+ : _object(object)
+{
+}
+
+object::~object() {
+ if (_object != nullptr)
+ ::ucl_object_unref(_object);
+}
+
+object::object(object &&other) noexcept
+ : _object(std::exchange(other._object, nullptr))
+{}
+
+object::object(object const &other) noexcept
+ : _object(nullptr)
+{
+ *this = other;
+}
+
+auto object::operator=(this object &self, object &&other) noexcept
+ -> object &
+{
+ if (&self != &other)
+ self._object = std::exchange(other._object, nullptr);
+ return self;
+}
+
+auto object::operator=(this object &self, object const &other)
+ -> object &
+{
+ if (&self != &other) {
+ auto *new_uobj = ::ucl_object_copy(other.get_ucl_object());
+ if (new_uobj == nullptr)
+ throw error("failed to copy UCL object");
+
+ if (self._object != nullptr)
+ ::ucl_object_unref(self._object);
+ self._object = new_uobj;
+ }
+
+ return self;
+}
+
+auto object::ref(this object const &self) -> object
+{
+ return object(nihil::ucl::ref, self.get_ucl_object());
+}
+
+auto object::type(this object const &self) -> object_type
+{
+ auto utype = ::ucl_object_type(self.get_ucl_object());
+ return static_cast<object_type>(utype);
+}
+
+auto object::get_ucl_object(this object &self) -> ::ucl_object_t *
+{
+ if (self._object == nullptr)
+ throw error("attempt to access empty UCL object");
+ return self._object;
+}
+
+auto object::get_ucl_object(this object const &self) -> ::ucl_object_t const *
+{
+ if (self._object == nullptr)
+ throw error("attempt to access empty UCL object");
+ return self._object;
+}
+
+// Return the key of this object.
+auto object::key(this object const &self) -> std::string_view
+{
+ auto dlen = std::size_t{};
+ auto const *dptr = ::ucl_object_keyl(self.get_ucl_object(),
+ &dlen);
+ return {dptr, dlen};
+}
+
+auto swap(object &a, object &b) -> void
+{
+ std::swap(a._object, b._object);
+}
+
+auto operator<=>(object const &lhs, object const &rhs) -> std::strong_ordering
+{
+ auto cmp = ::ucl_object_compare(lhs.get_ucl_object(),
+ rhs.get_ucl_object());
+
+ if (cmp < 0)
+ return std::strong_ordering::less;
+ else if (cmp > 0)
+ return std::strong_ordering::greater;
+ else
+ return std::strong_ordering::equal;
+}
+
+auto operator==(object const &lhs, object const &rhs) -> bool
+{
+ return (lhs <=> rhs) == std::strong_ordering::equal;
+}
+
+} // namespace nihil::ucl
diff --git a/nihil.ucl/object.ccm b/nihil.ucl/object.ccm
index b220335..5becfa8 100644
--- a/nihil.ucl/object.ccm
+++ b/nihil.ucl/object.ccm
@@ -10,12 +10,9 @@ module;
*
*/
-#include <algorithm>
-#include <cassert>
+#include <compare>
#include <cstddef>
-#include <format>
#include <string>
-#include <utility>
#include <ucl.h>
@@ -44,103 +41,40 @@ export struct object {
// Create an object from an existing ucl_object_t. The first argument
// determines whether we ref the object or not.
- object(ref_t, ::ucl_object_t const *object)
- : _object(::ucl_object_ref(object))
- {
- }
-
- object(noref_t, ::ucl_object_t *object)
- : _object(object)
- {
- }
+ object(ref_t, ::ucl_object_t const *object);
+ object(noref_t, ::ucl_object_t *object);
// Free our object on destruction.
- virtual ~object() {
- if (_object != nullptr)
- ::ucl_object_unref(_object);
- }
+ virtual ~object();
// Movable.
- object(object &&other) noexcept
- : _object(std::exchange(other._object, nullptr))
- {}
-
- auto operator=(this object &self, object &&other) noexcept
- -> object &
- {
- if (&self != &other)
- self._object = std::exchange(other._object, nullptr);
- return self;
- }
+ object(object &&other) noexcept;
+ auto operator=(this object &self, object &&other) noexcept -> object&;
// Copyable.
- object(object const &other) noexcept
- : _object(nullptr)
- {
- *this = other;
- }
-
- auto operator=(this object &self, object const &other)
- -> object &
- {
- if (&self != &other) {
- auto *new_uobj = ::ucl_object_copy(other.get_ucl_object());
- if (new_uobj == nullptr)
- throw error("failed to copy UCL object");
-
- if (self._object != nullptr)
- ::ucl_object_unref(self._object);
- self._object = new_uobj;
- }
-
- return self;
- }
+ // Note that this copies the entire UCL object.
+ object(object const &other) noexcept;
+ auto operator=(this object &self, object const &other) -> object &;
// Increase the refcount of this object.
- auto ref(this object const &self) -> object
- {
- return object(nihil::ucl::ref, self.get_ucl_object());
- }
+ auto ref(this object const &self) -> object;
// Return the type of this object.
- auto type(this object const &self) -> object_type
- {
- auto utype = ::ucl_object_type(self.get_ucl_object());
- return static_cast<object_type>(utype);
- }
+ auto type(this object const &self) -> object_type;
// Return the underlying object.
- auto get_ucl_object(this object &self) -> ::ucl_object_t *
- {
- if (self._object == nullptr)
- throw error("attempt to access empty UCL object");
- return self._object;
- }
-
- auto get_ucl_object(this object const &self) -> ::ucl_object_t const *
- {
- if (self._object == nullptr)
- throw error("attempt to access empty UCL object");
- return self._object;
- }
+ auto get_ucl_object(this object &self) -> ::ucl_object_t *;
+
+ auto get_ucl_object(this object const &self) -> ::ucl_object_t const *;
// Return the key of this object.
- auto key(this object const &self) -> std::string_view
- {
- auto dlen = std::size_t{};
- auto const *dptr = ::ucl_object_keyl(self.get_ucl_object(),
- &dlen);
- return {dptr, dlen};
- }
+ auto key(this object const &self) -> std::string_view;
protected:
// The object we're wrapping.
::ucl_object_t *_object = nullptr;
- friend auto swap(object &a, object &b) -> void
- {
- std::swap(a._object, b._object);
- }
+ friend auto swap(object &a, object &b) -> void;
private:
@@ -152,104 +86,8 @@ private:
* Object comparison.
*/
+export auto operator==(object const &lhs, object const &rhs) -> bool;
export auto operator<=>(object const &lhs, object const &rhs)
- -> std::strong_ordering
-{
- auto cmp = ::ucl_object_compare(lhs.get_ucl_object(),
- rhs.get_ucl_object());
-
- if (cmp < 0)
- return std::strong_ordering::less;
- else if (cmp > 0)
- return std::strong_ordering::greater;
- else
- return std::strong_ordering::equal;
-}
-
-export auto operator==(object const &lhs, object const &rhs) -> bool
-{
- return (lhs <=> rhs) == std::strong_ordering::equal;
-}
-
-/***********************************************************************
- * Object iteration.
- */
-
-export struct iterator {
- using difference_type = std::ptrdiff_t;
- using value_type = object;
- using reference = value_type &;
- using const_reference = value_type const &;
- using pointer = value_type *;
- using const_pointer = value_type const *;
-
- struct sentinel{};
-
- explicit iterator(object const &obj)
- {
- _state = std::make_shared<state>(obj);
- ++(*this);
- }
-
- auto operator==(this iterator const &self, sentinel) -> bool
- {
- return (self._state->cur == nullptr);
- }
-
- auto operator++(this iterator &self) -> iterator &
- {
- self._state->next();
- return self;
- }
-
- auto operator++(this iterator &self, int) -> iterator &
- {
- self._state->next();
- return self;
- }
-
- auto operator*(this iterator const &self) -> object {
- return object(ref, self._state->cur);
- }
-
-private:
- struct state {
- state(object const &obj)
- {
- auto const *uobj = obj.get_ucl_object();
- if ((iter = ::ucl_object_iterate_new(uobj)) == nullptr)
- throw error("failed to create UCL iterator");
- }
-
- state(state const &) = delete;
- auto operator=(this state &, state const &) -> state& = delete;
-
- ~state() {
- if (iter != nullptr)
- ::ucl_object_iterate_free(iter);
- }
-
- auto next() -> void {
- cur = ::ucl_object_iterate_safe(iter, true);
- }
-
- ucl_object_iter_t iter = nullptr;
- ucl_object_t const *cur = nullptr;
- };
-
- std::shared_ptr<state> _state;
-};
-
-static_assert(std::input_iterator<iterator>);
-
-export auto begin(object const &o) -> iterator
-{
- return iterator(o);
-}
-
-export auto end(object const &) -> iterator::sentinel
-{
- return {};
-}
+ -> std::strong_ordering;
} // namespace nihil::ucl
diff --git a/nihil.ucl/parser.cc b/nihil.ucl/parser.cc
new file mode 100644
index 0000000..816116d
--- /dev/null
+++ b/nihil.ucl/parser.cc
@@ -0,0 +1,75 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <functional>
+#include <string>
+
+#include <ucl.h>
+
+module nihil.ucl;
+
+namespace nihil::ucl {
+
+parse_error::parse_error(std::string what)
+ : error(std::move(what))
+{
+}
+
+auto macro_handler::handle(unsigned char const *data, std::size_t len, void *ud)
+-> bool
+{
+ auto handler = static_cast<macro_handler *>(ud);
+ auto string = std::string_view(
+ reinterpret_cast<char const *>(data),
+ len);
+ return handler->callback(string);
+}
+
+parser::parser(int flags)
+{
+ if ((_parser = ::ucl_parser_new(flags)) != nullptr)
+ return;
+
+ throw error("failed to create UCL parser");
+}
+
+parser::parser()
+ : parser(0)
+{
+}
+
+parser::~parser()
+{
+ if (_parser)
+ ::ucl_parser_free(_parser);
+}
+
+auto parser::register_value(
+ this parser &self,
+ std::string_view variable,
+ std::string_view value)
+-> void
+{
+ ::ucl_parser_register_variable(
+ self._parser,
+ std::string(variable).c_str(),
+ std::string(value).c_str());
+}
+
+auto parser::top(this parser &self) -> map<object>
+{
+ if (self._parser == nullptr)
+ throw error("attempt to call top() on an empty parser");
+
+ auto obj = ::ucl_parser_get_object(self._parser);
+ if (obj == nullptr)
+ throw error("attempt to call top() on an empty parser");
+
+ // ucl_parser_get_objects() refs the object for us.
+ return {noref, obj};
+}
+
+} // namespace nihil::ucl
diff --git a/nihil.ucl/parser.ccm b/nihil.ucl/parser.ccm
index 9b87773..f817b76 100644
--- a/nihil.ucl/parser.ccm
+++ b/nihil.ucl/parser.ccm
@@ -25,7 +25,7 @@ namespace nihil::ucl {
* Exception thrown when an issue occurs parsing UCL.
*/
export struct parse_error : error {
- parse_error(std::string what) : error(std::move(what)) {}
+ parse_error(std::string what);
};
// UCL parser flags.
@@ -33,8 +33,6 @@ export inline constexpr int parser_key_lower = UCL_PARSER_KEY_LOWERCASE;
export inline constexpr int parser_zerocopy = UCL_PARSER_ZEROCOPY;
export inline constexpr int parser_no_time = UCL_PARSER_NO_TIME;
-export struct parser;
-
// A macro handler. This proxies the C API callback to the C++ API.
using macro_callback_t = bool (std::string_view);
@@ -42,39 +40,25 @@ struct macro_handler {
std::function<macro_callback_t> callback;
// Handle a callback from the C API.
- static auto handle(unsigned char const *data, std::size_t len, void *ud)
- -> bool
- {
- auto handler = static_cast<macro_handler *>(ud);
- auto string = std::string_view(
- reinterpret_cast<char const *>(data),
- len);
- return handler->callback(string);
- }
+ static auto handle(
+ unsigned char const *data,
+ std::size_t len, void
+ *ud)
+ -> bool;
};
/*
* A UCL parser. This wraps the C ucl_parser API.
*/
export struct parser {
-
// Create a new parser with the given flags.
- parser(int flags) {
- if ((_parser = ::ucl_parser_new(flags)) != nullptr)
- return;
-
- throw error("failed to create UCL parser");
- }
+ parser(int flags);
// Create a new parser with the default flags.
- parser() : parser(0) {}
+ parser();
// Destroy our parser when we're destroyed.
- ~parser()
- {
- if (_parser)
- ::ucl_parser_free(_parser);
- }
+ ~parser();
// Add a parser macro. Unlike ucl_parser_register_macro, this doesn't
// take a userdata parameter; it's assumed the user will use lambda
@@ -99,17 +83,12 @@ export struct parser {
// Add a parser variable.
auto register_value(this parser &self,
std::string_view variable,
- std::string_view value) -> void
- {
- ::ucl_parser_register_variable(self._parser,
- std::string(variable).c_str(),
- std::string(value).c_str());
- }
+ std::string_view value) -> void;
// Add data to the parser.
auto add(this parser &self,
std::ranges::contiguous_range auto &&data)
- -> void
+ -> void
// Only bytes (chars) are permitted.
requires(sizeof(std::ranges::range_value_t<decltype(data)>) == 1)
{
@@ -125,7 +104,7 @@ export struct parser {
}
auto add(this parser &self, std::ranges::range auto &&data)
- -> void
+ -> void
requires (!std::ranges::contiguous_range<decltype(data)>)
{
auto cdata = std::vector<char>(
@@ -135,18 +114,7 @@ export struct parser {
}
// Return the top object of this parser.
- auto top(this parser &self) -> map<object>
- {
- if (self._parser == nullptr)
- throw error("attempt to call top() on an empty parser");
-
- auto obj = ::ucl_parser_get_object(self._parser);
- if (obj == nullptr)
- throw error("attempt to call top() on an empty parser");
-
- // ucl_parser_get_objects() refs the object for us.
- return {noref, obj};
- }
+ auto top(this parser &self) -> map<object>;
private:
// The parser object. Should never be null, unless we've been
diff --git a/nihil.ucl/real.cc b/nihil.ucl/real.cc
new file mode 100644
index 0000000..b371072
--- /dev/null
+++ b/nihil.ucl/real.cc
@@ -0,0 +1,79 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <cassert>
+#include <compare>
+#include <cstdlib>
+#include <string>
+
+#include <ucl.h>
+
+module nihil.ucl;
+
+namespace nihil::ucl {
+
+real::real(ref_t, ::ucl_object_t const *uobj)
+ : object(nihil::ucl::ref, uobj)
+{
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
+}
+
+real::real(noref_t, ::ucl_object_t *uobj)
+ : object(noref, uobj)
+{
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
+}
+
+real::real()
+ : real(0)
+{
+}
+
+real::real(contained_type value)
+ : object(noref, ::ucl_object_fromdouble(value))
+{
+ if (_object == nullptr)
+ throw error("failed to create UCL object");
+}
+
+auto real::value(this real const &self) -> contained_type
+{
+ auto v = contained_type{};
+ auto const *uobj = self.get_ucl_object();
+
+ if (::ucl_object_todouble_safe(uobj, &v))
+ return v;
+
+ std::abort();
+}
+
+auto operator== (real const &a, real const &b)
+-> bool
+{
+ return a.value() == b.value();
+}
+
+auto operator<=> (real const &a, real const &b)
+-> std::partial_ordering
+{
+ return a.value() <=> b.value();
+}
+
+auto operator== (real const &a, real::contained_type b)
+-> bool
+{
+ return a.value() == b;
+}
+
+auto operator<=> (real const &a, real::contained_type b)
+-> std::partial_ordering
+{
+ return a.value() <=> b;
+}
+
+} // namespace nihil::ucl
diff --git a/nihil.ucl/real.ccm b/nihil.ucl/real.ccm
index 260e993..e0ecbb5 100644
--- a/nihil.ucl/real.ccm
+++ b/nihil.ucl/real.ccm
@@ -4,9 +4,7 @@
module;
-#include <cassert>
-#include <cstdlib>
-#include <string>
+#include <compare>
#include <ucl.h>
@@ -22,72 +20,29 @@ export struct real final : object {
inline static constexpr object_type ucl_type = object_type::real;
// Create a new real from a UCL object.
- real(ref_t, ::ucl_object_t const *uobj)
- : object(nihil::ucl::ref, uobj)
- {
- if (type() != ucl_type)
- throw type_mismatch(ucl_type, type());
- }
-
- real(noref_t, ::ucl_object_t *uobj)
- : object(noref, uobj)
- {
- if (type() != ucl_type)
- throw type_mismatch(ucl_type, type());
- }
+ real(ref_t, ::ucl_object_t const *uobj);
+ real(noref_t, ::ucl_object_t *uobj);
// Create a default-initialised real.
- real()
- : real(0)
- {}
+ real();
// Create a new real from a value.
- explicit real(contained_type value)
- : object(noref, ::ucl_object_fromdouble(value))
- {
- if (_object == nullptr)
- throw error("failed to create UCL object");
- }
+ explicit real(contained_type value);
// Return the value of this real.
- auto value(this real const &self) -> contained_type
- {
- auto v = contained_type{};
- auto const *uobj = self.get_ucl_object();
-
- if (::ucl_object_todouble_safe(uobj, &v))
- return v;
-
- std::abort();
- }
+ auto value(this real const &self) -> contained_type;
};
/*
* Comparison operators.
*/
-export auto operator== (real const &a, real const &b)
- -> bool
-{
- return a.value() == b.value();
-}
+export auto operator== (real const &a, real const &b) -> bool;
+export auto operator== (real const &a, real::contained_type b) -> bool;
export auto operator<=> (real const &a, real const &b)
- -> std::partial_ordering
-{
- return a.value() <=> b.value();
-}
-
-export auto operator== (real const &a, real::contained_type b)
- -> bool
-{
- return a.value() == b;
-}
-
+ -> std::partial_ordering;
export auto operator<=> (real const &a, real::contained_type b)
- -> std::partial_ordering
-{
- return a.value() <=> b;
-}
+ -> std::partial_ordering;
} // namespace nihil::ucl
diff --git a/nihil.ucl/string.cc b/nihil.ucl/string.cc
new file mode 100644
index 0000000..d2f4618
--- /dev/null
+++ b/nihil.ucl/string.cc
@@ -0,0 +1,139 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <cstdlib>
+#include <string>
+
+#include <ucl.h>
+
+module nihil.ucl;
+
+namespace nihil::ucl {
+
+string::string(ref_t, ::ucl_object_t const *uobj)
+ : object(nihil::ucl::ref, uobj)
+{
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
+}
+
+string::string(noref_t, ::ucl_object_t *uobj)
+ : object(noref, uobj)
+{
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
+}
+
+string::string()
+ : string(std::string_view(""))
+{}
+
+string::string(std::string_view value)
+ : object(nihil::ucl::ref,
+ ::ucl_object_fromstring_common(
+ value.data(), value.size(),
+ UCL_STRING_RAW))
+{
+ if (_object == nullptr)
+ throw error("failed to create UCL object");
+}
+
+auto string::value(this string const &self) -> contained_type
+{
+ char const *dptr{};
+ std::size_t dlen;
+
+ auto const *uobj = self.get_ucl_object();
+ if (::ucl_object_tolstring_safe(uobj, &dptr, &dlen))
+ return {dptr, dlen};
+
+ // This should never fail.
+ std::abort();
+}
+
+auto string::size(this string const &self) -> size_type
+{
+ return self.value().size();
+}
+
+auto string::empty(this string const &self) -> bool
+{
+ return self.size() == 0;
+}
+
+auto string::data(this string const &self) -> pointer
+{
+ char const *dptr{};
+
+ auto const *uobj = self.get_ucl_object();
+ if (::ucl_object_tostring_safe(uobj, &dptr))
+ return dptr;
+
+ // This should never fail.
+ std::abort();
+}
+
+auto string::begin(this string const &self) -> iterator
+{
+ return self.data();
+}
+
+auto string::end(this string const &self) -> iterator
+{
+ return self.data() + self.size();
+}
+
+auto operator== (string const &a, string const &b)
+ -> bool
+{
+ return a.value() == b.value();
+}
+
+auto operator<=> (string const &a, string const &b)
+ -> std::strong_ordering
+{
+ return a.value() <=> b.value();
+}
+
+/*
+ * For convenience, allow comparison with C++ strings without having to
+ * construct a temporary UCL object.
+ */
+
+auto operator==(string const &lhs, std::string_view rhs) -> bool
+{
+ return lhs.value() == rhs;
+}
+
+auto operator<=>(string const &lhs, std::string_view rhs)
+ -> std::strong_ordering
+{
+ return lhs.value() <=> rhs;
+}
+
+auto operator==(string const &lhs, std::string const &rhs) -> bool
+{
+ return lhs == std::string_view(rhs);
+}
+
+auto operator<=>(string const &lhs, std::string const &rhs)
+ -> std::strong_ordering
+{
+ return lhs <=> std::string_view(rhs);
+}
+
+auto operator==(string const &lhs, char const *rhs) -> bool
+{
+ return lhs == std::string_view(rhs);
+}
+
+auto operator<=>(string const &lhs, char const *rhs)
+ -> std::strong_ordering
+{
+ return lhs <=> std::string_view(rhs);
+}
+
+} // namespace nihil::ucl
diff --git a/nihil.ucl/string.ccm b/nihil.ucl/string.ccm
index f92c82c..f8dc1cd 100644
--- a/nihil.ucl/string.ccm
+++ b/nihil.ucl/string.ccm
@@ -4,7 +4,6 @@
module;
-#include <cassert>
#include <cstdlib>
#include <string>
@@ -28,35 +27,14 @@ export struct string final : object {
using iterator = pointer;
// Create a new string from a UCL object.
- string(ref_t, ::ucl_object_t const *uobj)
- : object(nihil::ucl::ref, uobj)
- {
- if (type() != ucl_type)
- throw type_mismatch(ucl_type, type());
- }
-
- string(noref_t, ::ucl_object_t *uobj)
- : object(noref, uobj)
- {
- if (type() != ucl_type)
- throw type_mismatch(ucl_type, type());
- }
+ string(ref_t, ::ucl_object_t const *uobj);
+ string(noref_t, ::ucl_object_t *uobj);
// Create a new empty string.
- string()
- : string(std::string_view(""))
- {}
+ string();
// Create a new UCL string from a string.
- explicit string(std::string_view value)
- : object(nihil::ucl::ref,
- ::ucl_object_fromstring_common(
- value.data(), value.size(),
- UCL_STRING_RAW))
- {
- if (_object == nullptr)
- throw error("failed to create UCL object");
- }
+ explicit string(std::string_view value);
// Create a new UCL string from an iterator pair.
template<std::contiguous_iterator Iterator>
@@ -77,108 +55,44 @@ export struct string final : object {
{}
// Return the value of this string.
- auto value(this string const &self) -> contained_type
- {
- char const *dptr{};
- std::size_t dlen;
-
- auto const *uobj = self.get_ucl_object();
- if (::ucl_object_tolstring_safe(uobj, &dptr, &dlen))
- return {dptr, dlen};
-
- // This should never fail.
- std::abort();
- }
+ auto value(this string const &self) -> contained_type;
// Return the size of this string.
- auto size(this string const &self) -> size_type
- {
- return self.value().size();
- }
+ auto size(this string const &self) -> size_type;
// Test if this string is empty.
- auto empty(this string const &self) -> bool
- {
- return self.size() == 0;
- }
+ auto empty(this string const &self) -> bool;
// Access this string's data
- auto data(this string const &self) -> pointer
- {
- char const *dptr{};
-
- auto const *uobj = self.get_ucl_object();
- if (::ucl_object_tostring_safe(uobj, &dptr))
- return dptr;
-
- // This should never fail.
- std::abort();
- }
+ auto data(this string const &self) -> pointer;
// Iterator access
- auto begin(this string const &self) -> iterator
- {
- return self.data();
- }
-
- auto end(this string const &self) -> iterator
- {
- return self.data() + self.size();
- }
+ auto begin(this string const &self) -> iterator;
+ auto end(this string const &self) -> iterator;
};
/*
* Comparison operators.
*/
-export auto operator== (string const &a, string const &b)
- -> bool
-{
- return a.value() == b.value();
-}
-
+export auto operator== (string const &a, string const &b) -> bool;
export auto operator<=> (string const &a, string const &b)
- -> std::strong_ordering
-{
- return a.value() <=> b.value();
-}
+ -> std::strong_ordering;
/*
* For convenience, allow comparison with C++ strings without having to
* construct a temporary UCL object.
*/
-export auto operator==(string const &lhs, std::string_view rhs) -> bool
-{
- return lhs.value() == rhs;
-}
+export auto operator==(string const &lhs, std::string_view rhs) -> bool;
+export auto operator==(string const &lhs, std::string const &rhs) -> bool;
+export auto operator==(string const &lhs, char const *rhs) -> bool;
export auto operator<=>(string const &lhs, std::string_view rhs)
- -> std::strong_ordering
-{
- return lhs.value() <=> rhs;
-}
-
-export auto operator==(string const &lhs, std::string const &rhs) -> bool
-{
- return lhs == std::string_view(rhs);
-}
-
+ -> std::strong_ordering;
export auto operator<=>(string const &lhs, std::string const &rhs)
- -> std::strong_ordering
-{
- return lhs <=> std::string_view(rhs);
-}
-
-export auto operator==(string const &lhs, char const *rhs) -> bool
-{
- return lhs == std::string_view(rhs);
-}
-
+ -> std::strong_ordering;
export auto operator<=>(string const &lhs, char const *rhs)
- -> std::strong_ordering
-{
- return lhs <=> std::string_view(rhs);
-}
+ -> std::strong_ordering;
} // namespace nihil::ucl
diff --git a/nihil.ucl/type.cc b/nihil.ucl/type.cc
new file mode 100644
index 0000000..a008aa3
--- /dev/null
+++ b/nihil.ucl/type.cc
@@ -0,0 +1,62 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <format>
+
+module nihil.ucl;
+
+namespace nihil::ucl {
+
+auto str(object_type type) -> std::string_view {
+ using namespace std::literals;
+
+ switch (type) {
+ case object_type::object:
+ return "object"sv;
+ case object_type::array:
+ return "array"sv;
+ case object_type::integer:
+ return "integer"sv;
+ case object_type::real:
+ return "real"sv;
+ case object_type::string:
+ return "string"sv;
+ case object_type::boolean:
+ return "boolean"sv;
+ case object_type::time:
+ return "time"sv;
+ case object_type::userdata:
+ return "userdata"sv;
+ case object_type::null:
+ return "null"sv;
+ default:
+ // Don't fail here, since UCL might add more types that we
+ // don't know about.
+ return "unknown"sv;
+ }
+}
+
+type_mismatch::type_mismatch(
+ object_type expected_type, object_type actual_type)
+ : error(std::format("UCL type mismatch: expected type '{}' "
+ "!= actual type '{}'",
+ str(expected_type), str(actual_type)))
+ , _expected_type(expected_type)
+ , _actual_type(actual_type)
+{
+}
+
+auto type_mismatch::expected_type(this type_mismatch const &self) -> object_type
+{
+ return self._expected_type;
+}
+
+auto type_mismatch::actual_type(this type_mismatch const &self) -> object_type
+{
+ return self._actual_type;
+}
+
+} // namespace nihil::ucl
diff --git a/nihil.ucl/type.ccm b/nihil.ucl/type.ccm
index bf6c6bc..088d196 100644
--- a/nihil.ucl/type.ccm
+++ b/nihil.ucl/type.ccm
@@ -30,34 +30,7 @@ export enum struct object_type {
};
// Get the name of a type.
-export auto str(object_type type) -> std::string_view {
- using namespace std::literals;
-
- switch (type) {
- case object_type::object:
- return "object"sv;
- case object_type::array:
- return "array"sv;
- case object_type::integer:
- return "integer"sv;
- case object_type::real:
- return "real"sv;
- case object_type::string:
- return "string"sv;
- case object_type::boolean:
- return "boolean"sv;
- case object_type::time:
- return "time"sv;
- case object_type::userdata:
- return "userdata"sv;
- case object_type::null:
- return "null"sv;
- default:
- // Don't fail here, since UCL might add more types that we
- // don't know about.
- return "unknown"sv;
- }
-}
+export auto str(object_type type) -> std::string_view;
// Concept of a UCL data type.
export template<typename T>
@@ -69,25 +42,12 @@ concept datatype = requires(T o) {
// Exception thrown when a type assertion fails.
export struct type_mismatch : error {
- type_mismatch(object_type expected_type, object_type actual_type)
- : error(std::format("UCL type mismatch: expected type '{}' "
- "!= actual type '{}'",
- str(expected_type), str(actual_type)))
- , _expected_type(expected_type)
- , _actual_type(actual_type)
- {}
+ type_mismatch(object_type expected_type, object_type actual_type);
// The type we expected.
- auto expected_type(this type_mismatch const &self) -> object_type
- {
- return self._expected_type;
- }
-
+ auto expected_type(this type_mismatch const &self) -> object_type;
// The type we got.
- auto actual_type(this type_mismatch const &self) -> object_type
- {
- return self._actual_type;
- }
+ auto actual_type(this type_mismatch const &self) -> object_type;
private:
object_type _expected_type;