// IWYU pragma: private; include "rlang.h"

#ifndef RLANG_CND_H
#define RLANG_CND_H

#include "rlang-types.h"
#include "obj.h"


void r_inform(const char* fmt, ...);
void r_warn(const char* fmt, ...);
void r_interrupt(void);
void r_no_return r_abort(const char* fmt, ...);
void r_no_return r_abort_n(const struct r_pair* args, int n);
void r_no_return r_abort_call(r_obj* call, const char* fmt, ...);

// Formats input as an argument, using cli if available. Returns a
// vmax-protected string.
extern
const char* (*r_format_error_arg)(r_obj* arg);

const char* r_format_lazy_error_arg(struct r_lazy arg);

// Return vmax-protected strings
extern
const char* (*r_obj_type_friendly_full)(r_obj* x, bool value, bool length);

static inline
const char* r_obj_type_friendly(r_obj* x) {
  return r_obj_type_friendly_full(x, true, false);
}


extern
r_no_return
void (*r_stop_internal)(const char* file,
                        int line,
                        r_obj* call,
                        const char* fmt,
                        ...);

r_obj* r_peek_frame(void);

#define r_stop_internal(...)                            \
  (r_stop_internal)(__FILE__, __LINE__, r_peek_frame(), \
                    __VA_ARGS__)

#define r_stop_unreachable()                            \
  (r_stop_internal)(__FILE__, __LINE__, r_peek_frame(), \
                    "Reached the unreachable")

#define r_stop_unimplemented_type(TYPE)                                 \
  (r_stop_internal)(__FILE__, __LINE__, r_peek_frame(),                 \
                    "Unimplemented type `%s`.", Rf_type2char(TYPE))


#define r_stop_unexpected_type(TYPE)                                    \
  (r_stop_internal)(__FILE__, __LINE__, r_peek_frame(),                 \
                    "Unexpected type `%s`.", Rf_type2char(TYPE))


static inline
bool r_is_condition(r_obj* x) {
  return r_typeof(x) == R_TYPE_list && r_inherits(x, "condition");
}

void r_cnd_signal(r_obj* cnd);
void r_cnd_inform(r_obj* cnd, bool mufflable);
void r_cnd_warn(r_obj* cnd, bool mufflable);
void r_cnd_abort(r_obj* cnd, bool mufflable);

enum r_cnd_type {
  R_CND_TYPE_condition = 0,
  R_CND_TYPE_message = 1,
  R_CND_TYPE_warning = 2,
  R_CND_TYPE_error = 3,
  R_CND_TYPE_interrupt = 4
};

enum r_cnd_type r_cnd_type(r_obj* cnd);


#endif
