65 lines
1.9 KiB
C++
65 lines
1.9 KiB
C++
#ifndef PRESULT_H
|
|
#define PRESULT_H
|
|
|
|
#include "expected.h"
|
|
#include "sourceerror.h"
|
|
|
|
#include <optional>
|
|
|
|
/// Returns from the CURRENT function, the one this macro is used in,
|
|
/// if PResult contains an error
|
|
#define RETURN_IF_ERR(presult) \
|
|
do { \
|
|
auto&& return_if_err_temp_ = (presult); \
|
|
if (!return_if_err_temp_) { \
|
|
return PError(return_if_err_temp_.error()); \
|
|
} \
|
|
} while (0)
|
|
|
|
/// Works the same as RETURN_IF_ERR but can also assign the unwrapped result
|
|
/// to a variable if successful
|
|
#define ASSIGN_OR_RETURN_IF_ERR(var, presult) \
|
|
do { \
|
|
auto&& assign_or_return_if_err_temp_ = (presult); \
|
|
if (!assign_or_return_if_err_temp_) { \
|
|
return PError(assign_or_return_if_err_temp_.error()); \
|
|
} else { \
|
|
var = *assign_or_return_if_err_temp_; \
|
|
} \
|
|
} while (0)
|
|
|
|
using PError = tl::unexpected<SourceError>;
|
|
|
|
/// Holds either an AST node or an error
|
|
/// The value MUST be checked before usage, e.g. using RETURN_IF_ERR
|
|
template <typename T>
|
|
struct PResult : tl::expected<T, SourceError> {
|
|
using tl::expected<T, SourceError>::expected;
|
|
|
|
/// Implicit conversion from PResult<U> to PResult<T>
|
|
/// if U is convertible to T
|
|
template <typename U, class V = std::enable_if_t<std::is_convertible<std::decay_t<U>, T>::value>>
|
|
PResult(PResult<U> presult) :
|
|
tl::expected<T, SourceError>(presult ? PResult<T>(*presult) : PError(presult.error()))
|
|
{}
|
|
};
|
|
|
|
/// Alternative to PResult that is returned from parse* functions
|
|
/// that only consume one token so they can fail without affecting
|
|
/// the parser state
|
|
template<typename T>
|
|
struct POptResult : public PResult<T> {
|
|
using PResult<T>::PResult;
|
|
|
|
std::optional<T> optional() {
|
|
if (*this) {
|
|
return **this;
|
|
} else {
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
#endif // PRESULT_H
|