/**
 * @file include/evalfn.h
 * @brief Define data types for evaluationg expressions in real number mode
 */

#pragma once
#include "rtconf.h"

constexpr char arg_n = 8;

#define OP_CASE_ELEM(tok, op) \
  case *#op: \
    while (rbp + 1 < rsp) elem##tok(rbp + 1, rsp--); \
    break;
#define OVERWRITE(cas, var, fn) \
  case cas: \
    var = fn(var); \
    break;
// overwrite the top of the stack with the function in the parameter
#define OVERWRITE_REAL(cas, fn) OVERWRITE(cas, m->s.rsp->elem.real, fn)
#define OVERWRITE_COMP(cas, fn) OVERWRITE(cas, rsp->elem.comp, fn)

typedef struct {
  real_t payload[buf_size];
  real_t *rbp, *rsp;
} stack_t;

typedef struct {
  rrtinfo_t info;
  real_t *args;
  bool iscontinue;
} env_t;

typedef struct {
  char const *expr;
  char const *rip;
} ctrl_t;

typedef struct {
  // stack pointer index
  unsigned spi;
  // to restore argv
  // register the list of args
  real_t *callstack[buf_size];
  // to restore rsp
  // register the number of args used
  char argc[buf_size];
  ctrl_t exprs[buf_size];
} dump_t;

/**
 * @brief Based on SECD machine
 */
typedef struct {
  stack_t s;
  env_t e;
  ctrl_t c;
  dump_t d;
} machine_t;

[[gnu::nonnull]] stack_t evalExprRealStack(char const *);
[[gnu::nonnull]] elem_t evalExprReal(char const *);
[[gnu::nonnull]] elem_t evalExprComplex(char const *);
[[gnu::nonnull]] void rpxEval(machine_t *);
[[gnu::nonnull]] void initEvalinfo(machine_t *);