#ifndef failloop_h
#define failloop_h

/*
 * This header file and its corresponding implementation file (failloop.c)
 * form an embedded bytecode compiler for the primitive recursive driven
 * programming language called FAIL (https://prequel-lang.org/failloop/).
 *
 * Software acknowledgments:
 * - Jere Sanisalo and Petri Kero's fixed-point library:
 *    https://github.com/XMunkki/FixPointCS/blob/master/LICENSE.txt
 * - Mutsuo Saito and Makoto Matsumoto's pseudo random number generator:
 *    https://github.com/MersenneTwister-Lab/TinyMT/blob/master/LICENSE.txt
 *
 * Copyright (c) 2026 Hugo Simoes
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

/* fail version converges to the principal square root of 2 */
const char *failloop_get_version(void);

#include <stddef.h>                                                /* size_t */

typedef struct failloop failloop;

typedef void *(*failloop_reallocate_fn)(
  void *memory,
  size_t new_size,
  void *user_data
);
typedef void (*failloop_print_fn)(
  const char *message,
  size_t message_length,
  void *user_data
);
typedef void (*failloop_hook_fn)(
  int is_running,
  void *user_data
);

typedef void (*failloop_function_fn)(
  size_t function_index,
  void *user_data
);

typedef struct {
  failloop_reallocate_fn reallocate_fn;
  failloop_print_fn print_fn;
  failloop_hook_fn hook_fn;
  void *user_data;
} failloop_config;

int failloop_init_config(
  failloop_config *config
);

failloop *failloop_new(
  failloop_config *config
);

int failloop_get_errno(
  failloop *p
);
int failloop_get_errmsg(
  failloop *p,
  int errno,
  const char **ret_error_msg,
  size_t *ret_error_line
);

int failloop_reset(
  failloop *p
);

int failloop_compile(
  failloop *p,
  const char *source_code
);
int failloop_compile_reset(
  failloop *p
);

int failloop_execute(
  failloop *p
);
int failloop_execute_reset(
  failloop *p
);

int failloop_free(
  failloop *p
);

int failloop_set_random_seed(
  failloop *p,
  unsigned char seed_bits_31_24,
  unsigned char seed_bits_23_16,
  unsigned char seed_bits_15_08,
  unsigned char seed_bits_07_00
);

int failloop_define_function(
  failloop *p,
  const char *name,
  size_t len,
  failloop_function_fn function,
  size_t *ret_function_index
);

int failloop_stackop_empty(
  failloop *p
);
int failloop_stackop_count(
  failloop *p,
  size_t *ret_count
);
int failloop_stackop_mktop(
  failloop *p,
  size_t stackop_index
);
int failloop_stackop_isnum(
  failloop *p,
  size_t stackop_index,
  int *ret_isnum
);
int failloop_stackop_islist(
  failloop *p,
  size_t stackop_index,
  int *ret_islist
);
int failloop_stackop_isstr(
  failloop *p,
  size_t stackop_index,
  int *ret_isstr
);
int failloop_stackop_maxstrlen(
  failloop *p,
  size_t stackop_index,
  size_t *ret_maxstrlen
);
int failloop_stackop_extract(
  failloop *p,
  size_t stackop_index,
  char *ret_value,
  size_t *ret_len
);
int failloop_stackop_queue(
  failloop *p,
  const char *value,
  size_t len
);
int failloop_stackop_assign(
  failloop *p,
  const char *varname,
  size_t len,
  size_t *ret_input_var_index
);

int failloop_exec_suspend(
  failloop *p
);
int failloop_exec_error(
  failloop *p,
  const char *error_msg
);
int failloop_exec_halt(
  failloop *p
);
int failloop_exec_restart(
  failloop *p
);

/* these next functions should not be needed */
/*  except when building a fail debugger  */

int failloop_get_modules_memory_cur(
  failloop *p,
  size_t *ret_memory
);
int failloop_get_modules_memory_max(
  failloop *p,
  size_t *ret_memory
);

int failloop_get_input_vars_count(
  failloop *p,
  size_t *ret_count
);
int failloop_get_input_var_name_len(
  failloop *p,
  size_t input_var_index,
  size_t *ret_len
);
int failloop_get_input_var_name(
  failloop *p,
  size_t input_var_index,
  char *ret_name
);

int failloop_get_functions_count(
  failloop *p,
  size_t *ret_count
);
int failloop_get_function_name_len(
  failloop *p,
  size_t function_index,
  size_t *ret_len
);
int failloop_get_function_name(
  failloop *p,
  size_t function_index,
  char *ret_name
);

int failloop_get_module_entry(
  failloop *p,
  size_t *ret_module_index
);

int failloop_get_modules_count(
  failloop *p,
  size_t *ret_count
);
int failloop_get_module_name_len(
  failloop *p,
  size_t module_index,
  size_t *ret_len
);
int failloop_get_module_name(
  failloop *p,
  size_t module_index,
  char *ret_name
);
int failloop_get_module_line_range(
  failloop *p,
  size_t module_index,
  size_t *ret_line_declared,
  size_t *ret_line_from,
  size_t *ret_line_to
);

int failloop_get_module_vars_count(
  failloop *p,
  size_t module_index,
  size_t *ret_count
);
int failloop_get_module_var_name_len(
  failloop *p,
  size_t module_index,
  size_t var_index,
  size_t *ret_len
);
int failloop_get_module_var_name(
  failloop *p,
  size_t module_index,
  size_t var_index,
  char *ret_name
);

int failloop_get_instruction_current(
  failloop *p,
  size_t *ret_line
);

int failloop_get_module_current(
  failloop *p,
  size_t *ret_module_index
);
int failloop_get_callstack_modules_count(
  failloop *p,
  size_t *ret_count
);
int failloop_get_callstack_module(
  failloop *p,
  size_t callstack_index,
  size_t *ret_module_index
);
int failloop_get_callstack_instruction(
  failloop *p,
  size_t callstack_index,
  size_t *ret_line_from,
  size_t *ret_line_to
);

int failloop_get_var_value_maxstrlen(
  failloop *p,
  size_t module_index,
  size_t var_index,
  size_t *ret_maxstrlen
);
int failloop_get_var_value(
  failloop *p,
  size_t module_index,
  size_t var_index,
  char *ret_var_value,
  size_t *ret_len
);
int failloop_was_var_last_updated(
  failloop *p,
  size_t module_index,
  size_t var_index,
  int *ret_was_var_last_updated
);

typedef enum {
  failloop_token_spaces,
  failloop_token_comment,
  failloop_token_newline,
  failloop_token_symbol,
  failloop_token_string,
  failloop_token_number,
  failloop_token_keyword,
  failloop_token_variable,
  failloop_token_module,
  failloop_token_inputvar,
  failloop_token_function,
  failloop_token_suffix,
  failloop_token_eof
} failloop_token_type_t;

int failloop_get_tokens_count(
  failloop *p,
  size_t *ret_count
);
int failloop_get_token(
  failloop *p,
  size_t index,
  failloop_token_type_t *ret_type,
  size_t *ret_line,
  size_t *ret_column,
  const char **ret_token,
  size_t *ret_len
);

int failloop_get_standardized_len(
  failloop *p,
  size_t *ret_len
);
int failloop_get_standardized(
  failloop *p,
  char *ret_standardized
);

#endif
