#ifndef WCRX_H
#define WCRX_H

#include <limits.h>
#include <setjmp.h>
#include <stdarg.h>
#include <uirx.h>

#define WCRX_OPC_BGROUP ('(')
#define WCRX_OPC_OR ('|')
#define WCRX_OPC_EGROUP (')')
#define WCRX_OPC_CLOSURE ('*')
#define WCRX_OPC_PCLOSURE ('+')
#define WCRX_OPC_0OR1 ('?')
#define WCRX_OPC_BCLASS ('[')
#define WCRX_OPC_NCLASS ('^')
#define WCRX_OPC_RANGE ('-')
#define WCRX_OPC_ECLASS (']')
#define WCRX_OPC_BOF ('^')
#define WCRX_OPC_EOF ('$')
#define WCRX_OPC_ESC ('\\')
#define WCRX_OPC_WILDCHAR ('.')
#define WCRX_OPC_LF ('\n')

typedef struct wcrx_wcl_st {
  struct wcrx_wcl_st *prev;
  uirx_wc_t beg, end;
} wcrx_wcl_t;

struct wcrx_parser_desc_st;

typedef void (*wcrx_compile_macro_func_t)(struct wcrx_parser_desc_st *, uirx_parse_stack_t *,
					  int, wcrx_wcl_t *, uirx_wc_t, void *);

typedef struct wcrx_compile_macro_st {
  union {
    void (*class)(struct wcrx_parser_desc_st *, uirx_parse_stack_t *, int, wcrx_wcl_t *, uirx_wc_t, void *);
    void (*expr)(struct wcrx_parser_desc_st *, uirx_parse_stack_t *, uirx_wc_t, void *);
  } func;
  void *arg;
} wcrx_compile_macro_t;

typedef struct wcrx_macro_item_st {
  uirx_wc_t c;
  wcrx_compile_macro_t *macro;
} wcrx_macro_item_t;

typedef struct wcrx_macro_tab_st {
  wcrx_macro_item_t *v;
  size_t n;
} wcrx_macro_tab_t;

#define WCRX_CLASS_RANGE (1U << 0)
#define WCRX_CLASS_COMPLEMENT (1U << 1)
#define WCRX_CLASS_INTERNAL (1U << 2)

typedef struct wcrx_parser_desc_core_st {
  uirx_wc_t (*reader)(void *);
  wcrx_macro_tab_t *class_macro_tab;
  wcrx_macro_tab_t *expr_macro_tab;
  uirx_wc_t bof_char, eof_char;
  uirx_special_callback_t group_beg_func, group_end_func;
  void (*evprintf)(void *, const char *, va_list);
  int error_status;
} wcrx_parser_desc_core_t;

typedef struct wcrx_parser_desc_st {
  wcrx_parser_desc_core_t *core;
  void *reader_arg;
  uirx_wc_t (*alpha_filter)(uirx_wc_t, struct wcrx_parser_desc_st *);
  uirx_wc_t group_nth;
  void *evprintf_arg;
  jmp_buf *continuation;
} wcrx_parser_desc_t;

#define wcrx_read_alpha(desc) ((desc)->core->reader((desc)->reader_arg))
extern void wcrx_ethrow(wcrx_parser_desc_t *desc, const char *frmt, ...);
extern void wcrx_eprintf(wcrx_parser_desc_t *desc, const char *frmt, ...);
extern wcrx_wcl_t *wcrx_compile_class_sort(wcrx_wcl_t *wcl);
extern void wcrx_compile_class_alpha(wcrx_parser_desc_t *desc, uirx_parse_stack_t *csp, int status, wcrx_wcl_t *wcl);
extern void wcrx_compile_class_end(wcrx_parser_desc_t *desc, uirx_parse_stack_t *sp, int status, wcrx_wcl_t *wcl);
extern void wcrx_compile_class(wcrx_parser_desc_t *desc, uirx_parse_stack_t *sp, int status, wcrx_wcl_t *wcl, uirx_wc_t beg);
extern void wcrx_compile_group(wcrx_parser_desc_t *desc, uirx_parse_stack_t *sup);
extern uirx_nfa_t *wcrx_compile(wcrx_parser_desc_t *desc);
extern void wcrx_compile_class_macro_class_body(wcrx_parser_desc_t *desc, uirx_parse_stack_t *sp,
						int status, wcrx_wcl_t *dst, wcrx_wcl_t *src);
extern void wcrx_compile_class_macro_class(wcrx_parser_desc_t *desc, uirx_parse_stack_t *sp,
					   int status, wcrx_wcl_t *dst, uirx_wc_t wc, void *arg);
extern void wcrx_compile_expr_macro_class(wcrx_parser_desc_t *desc, uirx_parse_stack_t *sp, uirx_wc_t wc, void *arg);
extern void wcrx_compile_class_macro_complement_body(wcrx_parser_desc_t *desc, uirx_parse_stack_t *sp, int status,
						     wcrx_wcl_t *wcl, wcrx_wcl_t *dst, wcrx_wcl_t *src);
extern void wcrx_compile_class_macro_complement(wcrx_parser_desc_t *desc, uirx_parse_stack_t *sp, int status,
						wcrx_wcl_t *dst, uirx_wc_t wc, void *arg);
extern void wcrx_compile_expr_macro_complement(wcrx_parser_desc_t *desc, uirx_parse_stack_t *sp, uirx_wc_t wc, void *arg);

#endif
