aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.ucl/parser.cc
diff options
context:
space:
mode:
authorLexi Winter <lexi@le-fay.org>2025-06-26 20:47:45 +0100
committerLexi Winter <lexi@le-fay.org>2025-06-26 20:47:45 +0100
commit90aa957ca9b7c217af7569009d1675e0f3ff8e9b (patch)
treee6a61ca2b6928e6414372b9b1484ce80fa2fb0b3 /nihil.ucl/parser.cc
parent1db86c401df11423c945634d8b2a483e97afa878 (diff)
downloadnihil-90aa957ca9b7c217af7569009d1675e0f3ff8e9b.tar.gz
nihil-90aa957ca9b7c217af7569009d1675e0f3ff8e9b.tar.bz2
ucl, config: use monadic error handling more
Diffstat (limited to 'nihil.ucl/parser.cc')
-rw-r--r--nihil.ucl/parser.cc71
1 files changed, 49 insertions, 22 deletions
diff --git a/nihil.ucl/parser.cc b/nihil.ucl/parser.cc
index 816116d..611fe50 100644
--- a/nihil.ucl/parser.cc
+++ b/nihil.ucl/parser.cc
@@ -4,6 +4,7 @@
module;
+#include <expected>
#include <functional>
#include <string>
@@ -11,15 +12,23 @@ module;
module nihil.ucl;
+import nihil;
+
namespace nihil::ucl {
-parse_error::parse_error(std::string what)
- : error(std::move(what))
+auto make_parser(int flags) -> std::expected<parser, nihil::error>
{
+ auto *p = ::ucl_parser_new(flags);
+ if (p != nullptr)
+ return p;
+
+ // TODO: Is there a way to get the actual error here?
+ return std::unexpected(nihil::error("failed to create parser"));
}
-auto macro_handler::handle(unsigned char const *data, std::size_t len, void *ud)
--> bool
+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(
@@ -28,48 +37,66 @@ auto macro_handler::handle(unsigned char const *data, std::size_t len, void *ud)
return handler->callback(string);
}
-parser::parser(int flags)
+parser::parser(::ucl_parser *uclp)
+ : m_parser(uclp)
{
- if ((_parser = ::ucl_parser_new(flags)) != nullptr)
- return;
+}
- throw error("failed to create UCL parser");
+parser::~parser()
+{
+ if (m_parser)
+ ::ucl_parser_free(m_parser);
}
-parser::parser()
- : parser(0)
+parser::parser(parser &&other) noexcept
+ : m_parser(std::exchange(other.m_parser, nullptr))
+ , m_macros(std::move(other.m_macros))
{
}
-parser::~parser()
+auto parser::operator=(this parser &self, parser &&other) noexcept
+ -> parser &
{
- if (_parser)
- ::ucl_parser_free(_parser);
+ if (&self != &other) {
+ if (self.m_parser)
+ ::ucl_parser_free(self.m_parser);
+
+ self.m_parser = std::exchange(other.m_parser, nullptr);
+ self.m_macros = std::move(other.m_macros);
+ }
+
+ return self;
}
auto parser::register_value(
this parser &self,
std::string_view variable,
std::string_view value)
--> void
+ -> void
{
::ucl_parser_register_variable(
- self._parser,
+ self.get_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.get_parser());
+ if (obj != nullptr)
+ // ucl_parser_get_object() refs the object for us.
+ return {noref, obj};
- auto obj = ::ucl_parser_get_object(self._parser);
- if (obj == nullptr)
- throw error("attempt to call top() on an empty parser");
+ throw std::logic_error(
+ "attempt to call top() on an invalid ucl::parser");
+}
- // ucl_parser_get_objects() refs the object for us.
- return {noref, obj};
+auto parser::get_parser(this parser &self) -> ::ucl_parser *
+{
+ if (self.m_parser == nullptr)
+ throw std::logic_error("attempt to fetch a null ucl::parser");
+
+ return self.m_parser;
}
} // namespace nihil::ucl