#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "lib/mlr_globals.h"
#include "lib/mlrutil.h"
#include "lib/mlrregex.h"
#include "lib/mtrand.h"
#include "mapping/mapper.h"
#include "dsl/context_flags.h"
#include "dsl/rxval_evaluators.h"

// ----------------------------------------------------------------
typedef struct _rxval_evaluator_variadic_state_t {
	xv_variadic_func_t*  pfunc;
	rxval_evaluator_t**  pargs;
	boxed_xval_t*        pbxvals;
	int                  nargs;
} rxval_evaluator_variadic_state_t;

static boxed_xval_t rxval_evaluator_variadic_func(void* pvstate, variables_t* pvars) {
	rxval_evaluator_variadic_state_t* pstate = pvstate;
	int nargs = pstate->nargs;

	for (int i = 0; i < nargs; i++) {
		rxval_evaluator_t* parg = pstate->pargs[i];
		boxed_xval_t* pbxval = &pstate->pbxvals[i];
		*pbxval = parg->pprocess_func(parg->pvstate, pvars);
	}

	boxed_xval_t bxrv = pstate->pfunc(pstate->pbxvals, nargs);

	for (int i = 0; i < nargs; i++) {
		boxed_xval_t* pbxval = &pstate->pbxvals[i];
		if (pbxval->is_ephemeral) {
			mlhmmv_xvalue_free(&pbxval->xval);
		}
	}
	return bxrv;
}

static void rxval_evaluator_variadic_free(rxval_evaluator_t* pxevaluator) {
	rxval_evaluator_variadic_state_t* pstate = pxevaluator->pvstate;

	for (int i = 0; i < pstate->nargs; i++)
		pstate->pargs[i]->pfree_func(pstate->pargs[i]);
	free(pstate->pargs);

	for (int i = 0; i < pstate->nargs; i++) {
		if (pstate->pbxvals[i].is_ephemeral) {
			mlhmmv_xvalue_free(&pstate->pbxvals[i].xval);
		}
	}
	free(pstate->pbxvals);

	free(pstate);

	free(pxevaluator);
}

rxval_evaluator_t* rxval_evaluator_alloc_from_variadic_func(
	xv_variadic_func_t*  pfunc,
	sllv_t*              parg_nodes,
	fmgr_t*              pfmgr,
	int                  type_inferencing,
	int                  context_flags)
{
	rxval_evaluator_variadic_state_t* pstate = mlr_malloc_or_die(sizeof(rxval_evaluator_variadic_state_t));
	pstate->pfunc = pfunc;

	int nargs = parg_nodes->length;
	rxval_evaluator_t** pargs = mlr_malloc_or_die(nargs * sizeof(rxval_evaluator_t*));
	int i = 0;
	for (sllve_t* pe = parg_nodes->phead; pe != NULL; pe = pe->pnext, i++) {
		mlr_dsl_ast_node_t* pnode = pe->pvvalue;
		pargs[i] = rxval_evaluator_alloc_from_ast(pnode, pfmgr, type_inferencing, context_flags);
	}

	pstate->pargs = pargs;
	pstate->nargs = nargs;
	pstate->pbxvals  = mlr_malloc_or_die(nargs * sizeof(boxed_xval_t));

	rxval_evaluator_t* pxevaluator = mlr_malloc_or_die(sizeof(rxval_evaluator_t));
	pxevaluator->pvstate       = pstate;
	pxevaluator->pprocess_func = rxval_evaluator_variadic_func;
	pxevaluator->pfree_func    = rxval_evaluator_variadic_free;

	return pxevaluator;
}

// ----------------------------------------------------------------
typedef struct _rxval_evaluator_x_x_state_t {
	xv_unary_func_t*  pfunc;
	rxval_evaluator_t* parg1;
} rxval_evaluator_x_x_state_t;

static boxed_xval_t rxval_evaluator_x_x_func(void* pvstate, variables_t* pvars) {
	rxval_evaluator_x_x_state_t* pstate = pvstate;
	boxed_xval_t bxval1 = pstate->parg1->pprocess_func(pstate->parg1->pvstate, pvars);

	boxed_xval_t bxrv = pstate->pfunc(&bxval1);

	if (bxval1.is_ephemeral) {
		mlhmmv_xvalue_free(&bxval1.xval);
	}

	return bxrv;
}

static void rxval_evaluator_x_x_free(rxval_evaluator_t* pxevaluator) {
	rxval_evaluator_x_x_state_t* pstate = pxevaluator->pvstate;
	pstate->parg1->pfree_func(pstate->parg1);
	free(pstate);
	free(pxevaluator);
}

rxval_evaluator_t* rxval_evaluator_alloc_from_x_x_func(
	xv_unary_func_t*    pfunc,
	mlr_dsl_ast_node_t* parg1_node,
	fmgr_t*             pfmgr,
	int                 type_inferencing,
	int                 context_flags)
{
	rxval_evaluator_x_x_state_t* pstate = mlr_malloc_or_die(sizeof(rxval_evaluator_x_x_state_t));
	pstate->pfunc = pfunc;
	pstate->parg1 = rxval_evaluator_alloc_from_ast(parg1_node, pfmgr, type_inferencing, context_flags);

	rxval_evaluator_t* pxevaluator = mlr_malloc_or_die(sizeof(rxval_evaluator_t));
	pxevaluator->pvstate       = pstate;
	pxevaluator->pprocess_func = rxval_evaluator_x_x_func;
	pxevaluator->pfree_func    = rxval_evaluator_x_x_free;

	return pxevaluator;
}

// ----------------------------------------------------------------
typedef struct _rxval_evaluator_x_m_state_t {
	xv_unary_func_t*  pfunc;
	rxval_evaluator_t* parg1;
} rxval_evaluator_x_m_state_t;

static boxed_xval_t rxval_evaluator_x_m_func(void* pvstate, variables_t* pvars) {
	rxval_evaluator_x_m_state_t* pstate = pvstate;
	boxed_xval_t bxval1 = pstate->parg1->pprocess_func(pstate->parg1->pvstate, pvars);

	if (bxval1.xval.is_terminal) {
		return box_ephemeral_val(mv_error());
	}

	boxed_xval_t bxrv = pstate->pfunc(&bxval1);

	if (bxval1.is_ephemeral) {
		mlhmmv_xvalue_free(&bxval1.xval);
	}
	return bxrv;
}

static void rxval_evaluator_x_m_free(rxval_evaluator_t* pxevaluator) {
	rxval_evaluator_x_m_state_t* pstate = pxevaluator->pvstate;
	pstate->parg1->pfree_func(pstate->parg1);
	free(pstate);
	free(pxevaluator);
}

rxval_evaluator_t* rxval_evaluator_alloc_from_x_m_func(
	xv_unary_func_t*    pfunc,
	mlr_dsl_ast_node_t* parg1_node,
	fmgr_t*             pfmgr,
	int                 type_inferencing,
	int                 context_flags)
{
	rxval_evaluator_x_m_state_t* pstate = mlr_malloc_or_die(sizeof(rxval_evaluator_x_m_state_t));
	pstate->pfunc = pfunc;
	pstate->parg1 = rxval_evaluator_alloc_from_ast(parg1_node, pfmgr, type_inferencing, context_flags);

	rxval_evaluator_t* pxevaluator = mlr_malloc_or_die(sizeof(rxval_evaluator_t));
	pxevaluator->pvstate       = pstate;
	pxevaluator->pprocess_func = rxval_evaluator_x_m_func;
	pxevaluator->pfree_func    = rxval_evaluator_x_m_free;

	return pxevaluator;
}

// ----------------------------------------------------------------
typedef struct _rxval_evaluator_x_mx_state_t {
	xv_binary_func_t*  pfunc;
	rxval_evaluator_t* parg1;
	rxval_evaluator_t* parg2;
} rxval_evaluator_x_mx_state_t;

static boxed_xval_t rxval_evaluator_x_mx_func(void* pvstate, variables_t* pvars) {
	rxval_evaluator_x_mx_state_t* pstate = pvstate;
	boxed_xval_t bxval1 = pstate->parg1->pprocess_func(pstate->parg1->pvstate, pvars);
	boxed_xval_t bxval2 = pstate->parg2->pprocess_func(pstate->parg2->pvstate, pvars);

	if (bxval1.xval.is_terminal) {
		return box_ephemeral_val(mv_error());
	}

	if (!bxval2.xval.is_terminal) {
		return box_ephemeral_val(mv_error());
	}

	boxed_xval_t bxrv = pstate->pfunc(&bxval1, &bxval2);

	if (bxval1.is_ephemeral) {
		mlhmmv_xvalue_free(&bxval1.xval);
	}
	if (bxval2.is_ephemeral) {
		mlhmmv_xvalue_free(&bxval2.xval);
	}
	return bxrv;
}

static void rxval_evaluator_x_mx_free(rxval_evaluator_t* pxevaluator) {
	rxval_evaluator_x_mx_state_t* pstate = pxevaluator->pvstate;
	pstate->parg1->pfree_func(pstate->parg1);
	pstate->parg2->pfree_func(pstate->parg2);
	free(pstate);
	free(pxevaluator);
}

rxval_evaluator_t* rxval_evaluator_alloc_from_x_mx_func(
	xv_binary_func_t*   pfunc,
	mlr_dsl_ast_node_t* parg1_node,
	mlr_dsl_ast_node_t* parg2_node,
	fmgr_t*             pfmgr,
	int                 type_inferencing,
	int                 context_flags)
{
	rxval_evaluator_x_mx_state_t* pstate = mlr_malloc_or_die(sizeof(rxval_evaluator_x_mx_state_t));
	pstate->pfunc = pfunc;
	pstate->parg1 = rxval_evaluator_alloc_from_ast(parg1_node, pfmgr, type_inferencing, context_flags);
	pstate->parg2 = rxval_evaluator_alloc_from_ast(parg2_node, pfmgr, type_inferencing, context_flags);

	rxval_evaluator_t* pxevaluator = mlr_malloc_or_die(sizeof(rxval_evaluator_t));
	pxevaluator->pvstate       = pstate;
	pxevaluator->pprocess_func = rxval_evaluator_x_mx_func;
	pxevaluator->pfree_func    = rxval_evaluator_x_mx_free;

	return pxevaluator;
}

// ----------------------------------------------------------------
typedef struct _rxval_evaluator_x_ms_state_t {
	xv_binary_func_t*  pfunc;
	rxval_evaluator_t* parg1;
	rxval_evaluator_t* parg2;
} rxval_evaluator_x_ms_state_t;

static boxed_xval_t rxval_evaluator_x_ms_func(void* pvstate, variables_t* pvars) {
	rxval_evaluator_x_ms_state_t* pstate = pvstate;
	boxed_xval_t bxval1 = pstate->parg1->pprocess_func(pstate->parg1->pvstate, pvars);
	boxed_xval_t bxval2 = pstate->parg2->pprocess_func(pstate->parg2->pvstate, pvars);

	if (bxval1.xval.is_terminal) {
		return box_ephemeral_val(mv_error());
	}

	if (!bxval2.xval.is_terminal) {
		return box_ephemeral_val(mv_error());
	}
	if (!mv_is_string_or_empty(&bxval2.xval.terminal_mlrval)) {
		mv_free(&bxval2.xval.terminal_mlrval);
		return box_ephemeral_val(mv_error());
	}

	boxed_xval_t bxrv = pstate->pfunc(&bxval1, &bxval2);

	if (bxval1.is_ephemeral) {
		mlhmmv_xvalue_free(&bxval1.xval);
	}
	if (bxval2.is_ephemeral) {
		mlhmmv_xvalue_free(&bxval2.xval);
	}
	return bxrv;
}

static void rxval_evaluator_x_ms_free(rxval_evaluator_t* pxevaluator) {
	rxval_evaluator_x_ms_state_t* pstate = pxevaluator->pvstate;
	pstate->parg1->pfree_func(pstate->parg1);
	pstate->parg2->pfree_func(pstate->parg2);
	free(pstate);
	free(pxevaluator);
}

rxval_evaluator_t* rxval_evaluator_alloc_from_x_ms_func(
	xv_binary_func_t*   pfunc,
	mlr_dsl_ast_node_t* parg1_node,
	mlr_dsl_ast_node_t* parg2_node,
	fmgr_t*             pfmgr,
	int                 type_inferencing,
	int                 context_flags)
{
	rxval_evaluator_x_ms_state_t* pstate = mlr_malloc_or_die(sizeof(rxval_evaluator_x_ms_state_t));
	pstate->pfunc = pfunc;
	pstate->parg1 = rxval_evaluator_alloc_from_ast(parg1_node, pfmgr, type_inferencing, context_flags);
	pstate->parg2 = rxval_evaluator_alloc_from_ast(parg2_node, pfmgr, type_inferencing, context_flags);

	rxval_evaluator_t* pxevaluator = mlr_malloc_or_die(sizeof(rxval_evaluator_t));
	pxevaluator->pvstate       = pstate;
	pxevaluator->pprocess_func = rxval_evaluator_x_ms_func;
	pxevaluator->pfree_func    = rxval_evaluator_x_ms_free;

	return pxevaluator;
}

// ----------------------------------------------------------------
typedef struct _rxval_evaluator_x_ss_state_t {
	xv_binary_func_t*  pfunc;
	rxval_evaluator_t* parg1;
	rxval_evaluator_t* parg2;
} rxval_evaluator_x_ss_state_t;

static boxed_xval_t rxval_evaluator_x_ss_func(void* pvstate, variables_t* pvars) {
	rxval_evaluator_x_ss_state_t* pstate = pvstate;
	boxed_xval_t bxval1 = pstate->parg1->pprocess_func(pstate->parg1->pvstate, pvars);
	boxed_xval_t bxval2 = pstate->parg2->pprocess_func(pstate->parg2->pvstate, pvars);

	if (!bxval1.xval.is_terminal) {
		mv_free(&bxval1.xval.terminal_mlrval);
		return box_ephemeral_val(mv_error());
	}
	if (!mv_is_string_or_empty(&bxval1.xval.terminal_mlrval)) {
		mv_free(&bxval1.xval.terminal_mlrval);
		return box_ephemeral_val(mv_error());
	}

	if (!bxval2.xval.is_terminal) {
		mv_free(&bxval2.xval.terminal_mlrval);
		return box_ephemeral_val(mv_error());
	}
	if (!mv_is_string_or_empty(&bxval2.xval.terminal_mlrval)) {
		mv_free(&bxval2.xval.terminal_mlrval);
		return box_ephemeral_val(mv_error());
	}

	boxed_xval_t bxrv = pstate->pfunc(&bxval1, &bxval2);

	if (bxval1.is_ephemeral) {
		mlhmmv_xvalue_free(&bxval1.xval);
	}
	if (bxval2.is_ephemeral) {
		mlhmmv_xvalue_free(&bxval2.xval);
	}
	return bxrv;
}

static void rxval_evaluator_x_ss_free(rxval_evaluator_t* pxevaluator) {
	rxval_evaluator_x_ss_state_t* pstate = pxevaluator->pvstate;
	pstate->parg1->pfree_func(pstate->parg1);
	pstate->parg2->pfree_func(pstate->parg2);
	free(pstate);
	free(pxevaluator);
}

rxval_evaluator_t* rxval_evaluator_alloc_from_x_ss_func(
	xv_binary_func_t*   pfunc,
	mlr_dsl_ast_node_t* parg1_node,
	mlr_dsl_ast_node_t* parg2_node,
	fmgr_t*             pfmgr,
	int                 type_inferencing,
	int                 context_flags)
{
	rxval_evaluator_x_ss_state_t* pstate = mlr_malloc_or_die(sizeof(rxval_evaluator_x_ss_state_t));
	pstate->pfunc = pfunc;
	pstate->parg1 = rxval_evaluator_alloc_from_ast(parg1_node, pfmgr, type_inferencing, context_flags);
	pstate->parg2 = rxval_evaluator_alloc_from_ast(parg2_node, pfmgr, type_inferencing, context_flags);

	rxval_evaluator_t* pxevaluator = mlr_malloc_or_die(sizeof(rxval_evaluator_t));
	pxevaluator->pvstate       = pstate;
	pxevaluator->pprocess_func = rxval_evaluator_x_ss_func;
	pxevaluator->pfree_func    = rxval_evaluator_x_ss_free;

	return pxevaluator;
}

// ----------------------------------------------------------------
typedef struct _rxval_evaluator_x_mss_state_t {
	xv_ternary_func_t*  pfunc;
	rxval_evaluator_t* parg1;
	rxval_evaluator_t* parg2;
	rxval_evaluator_t* parg3;
} rxval_evaluator_x_mss_state_t;

static boxed_xval_t rxval_evaluator_x_mss_func(void* pvstate, variables_t* pvars) {
	rxval_evaluator_x_mss_state_t* pstate = pvstate;
	boxed_xval_t bxval1 = pstate->parg1->pprocess_func(pstate->parg1->pvstate, pvars);
	boxed_xval_t bxval2 = pstate->parg2->pprocess_func(pstate->parg2->pvstate, pvars);
	boxed_xval_t bxval3 = pstate->parg3->pprocess_func(pstate->parg3->pvstate, pvars);

	if (bxval1.xval.is_terminal) {
		return box_ephemeral_val(mv_error());
	}

	if (!bxval2.xval.is_terminal) {
		return box_ephemeral_val(mv_error());
	}
	if (!mv_is_string_or_empty(&bxval2.xval.terminal_mlrval)) {
		mv_free(&bxval2.xval.terminal_mlrval);
		return box_ephemeral_val(mv_error());
	}

	if (!bxval3.xval.is_terminal) {
		return box_ephemeral_val(mv_error());
	}
	if (!mv_is_string_or_empty(&bxval3.xval.terminal_mlrval)) {
		mv_free(&bxval3.xval.terminal_mlrval);
		return box_ephemeral_val(mv_error());
	}

	boxed_xval_t bxrv = pstate->pfunc(&bxval1, &bxval2, &bxval3);

	if (bxval1.is_ephemeral) {
		mlhmmv_xvalue_free(&bxval1.xval);
	}
	if (bxval2.is_ephemeral) {
		mlhmmv_xvalue_free(&bxval2.xval);
	}
	return bxrv;
}

static void rxval_evaluator_x_mss_free(rxval_evaluator_t* pxevaluator) {
	rxval_evaluator_x_mss_state_t* pstate = pxevaluator->pvstate;
	pstate->parg1->pfree_func(pstate->parg1);
	pstate->parg2->pfree_func(pstate->parg2);
	pstate->parg3->pfree_func(pstate->parg3);
	free(pstate);
	free(pxevaluator);
}

rxval_evaluator_t* rxval_evaluator_alloc_from_x_mss_func(
	xv_ternary_func_t*  pfunc,
	mlr_dsl_ast_node_t* parg1_node,
	mlr_dsl_ast_node_t* parg2_node,
	mlr_dsl_ast_node_t* parg3_node,
	fmgr_t*             pfmgr,
	int                 type_inferencing,
	int                 context_flags)
{
	rxval_evaluator_x_mss_state_t* pstate = mlr_malloc_or_die(sizeof(rxval_evaluator_x_mss_state_t));
	pstate->pfunc = pfunc;
	pstate->parg1 = rxval_evaluator_alloc_from_ast(parg1_node, pfmgr, type_inferencing, context_flags);
	pstate->parg2 = rxval_evaluator_alloc_from_ast(parg2_node, pfmgr, type_inferencing, context_flags);
	pstate->parg3 = rxval_evaluator_alloc_from_ast(parg3_node, pfmgr, type_inferencing, context_flags);

	rxval_evaluator_t* pxevaluator = mlr_malloc_or_die(sizeof(rxval_evaluator_t));
	pxevaluator->pvstate       = pstate;
	pxevaluator->pprocess_func = rxval_evaluator_x_mss_func;
	pxevaluator->pfree_func    = rxval_evaluator_x_mss_free;

	return pxevaluator;
}

// ----------------------------------------------------------------
typedef struct _rxval_evaluator_x_sss_state_t {
	xv_ternary_func_t*  pfunc;
	rxval_evaluator_t* parg1;
	rxval_evaluator_t* parg2;
	rxval_evaluator_t* parg3;
} rxval_evaluator_x_sss_state_t;

static boxed_xval_t rxval_evaluator_x_sss_func(void* pvstate, variables_t* pvars) {
	rxval_evaluator_x_sss_state_t* pstate = pvstate;
	boxed_xval_t bxval1 = pstate->parg1->pprocess_func(pstate->parg1->pvstate, pvars);
	boxed_xval_t bxval2 = pstate->parg2->pprocess_func(pstate->parg2->pvstate, pvars);
	boxed_xval_t bxval3 = pstate->parg3->pprocess_func(pstate->parg3->pvstate, pvars);

	if (!bxval1.xval.is_terminal) {
		return box_ephemeral_val(mv_error());
	}
	if (!mv_is_string_or_empty(&bxval1.xval.terminal_mlrval)) {
		mv_free(&bxval1.xval.terminal_mlrval);
		return box_ephemeral_val(mv_error());
	}

	if (!bxval2.xval.is_terminal) {
		return box_ephemeral_val(mv_error());
	}
	if (!mv_is_string_or_empty(&bxval2.xval.terminal_mlrval)) {
		mv_free(&bxval2.xval.terminal_mlrval);
		return box_ephemeral_val(mv_error());
	}

	if (!bxval3.xval.is_terminal) {
		return box_ephemeral_val(mv_error());
	}
	if (!mv_is_string_or_empty(&bxval3.xval.terminal_mlrval)) {
		mv_free(&bxval3.xval.terminal_mlrval);
		return box_ephemeral_val(mv_error());
	}

	boxed_xval_t bxrv = pstate->pfunc(&bxval1, &bxval2, &bxval3);

	if (bxval1.is_ephemeral) {
		mlhmmv_xvalue_free(&bxval1.xval);
	}
	if (bxval2.is_ephemeral) {
		mlhmmv_xvalue_free(&bxval2.xval);
	}
	if (bxval3.is_ephemeral) {
		mlhmmv_xvalue_free(&bxval3.xval);
	}
	return bxrv;
}

static void rxval_evaluator_x_sss_free(rxval_evaluator_t* pxevaluator) {
	rxval_evaluator_x_sss_state_t* pstate = pxevaluator->pvstate;
	pstate->parg1->pfree_func(pstate->parg1);
	pstate->parg2->pfree_func(pstate->parg2);
	pstate->parg3->pfree_func(pstate->parg3);
	free(pstate);
	free(pxevaluator);
}

rxval_evaluator_t* rxval_evaluator_alloc_from_x_sss_func(
	xv_ternary_func_t*  pfunc,
	mlr_dsl_ast_node_t* parg1_node,
	mlr_dsl_ast_node_t* parg2_node,
	mlr_dsl_ast_node_t* parg3_node,
	fmgr_t*             pfmgr,
	int                 type_inferencing,
	int                 context_flags)
{
	rxval_evaluator_x_sss_state_t* pstate = mlr_malloc_or_die(sizeof(rxval_evaluator_x_sss_state_t));
	pstate->pfunc = pfunc;
	pstate->parg1 = rxval_evaluator_alloc_from_ast(parg1_node, pfmgr, type_inferencing, context_flags);
	pstate->parg2 = rxval_evaluator_alloc_from_ast(parg2_node, pfmgr, type_inferencing, context_flags);
	pstate->parg3 = rxval_evaluator_alloc_from_ast(parg3_node, pfmgr, type_inferencing, context_flags);

	rxval_evaluator_t* pxevaluator = mlr_malloc_or_die(sizeof(rxval_evaluator_t));
	pxevaluator->pvstate       = pstate;
	pxevaluator->pprocess_func = rxval_evaluator_x_sss_func;
	pxevaluator->pfree_func    = rxval_evaluator_x_sss_free;

	return pxevaluator;
}

// ----------------------------------------------------------------
// Does type-check assertion on the argument and returns it unmodified if the
// test passes.  Else throws an error.
typedef struct _rxval_evaluator_A_x_state_t {
	xv_unary_func_t*   pfunc;
	rxval_evaluator_t* parg1;
	char*              desc;
} rxval_evaluator_A_x_state_t;

static boxed_xval_t rxval_evaluator_A_x_func(void* pvstate, variables_t* pvars) {
	rxval_evaluator_A_x_state_t* pstate = pvstate;
	boxed_xval_t val1 = pstate->parg1->pprocess_func(pstate->parg1->pvstate, pvars);

	boxed_xval_t ok = pstate->pfunc(&val1);

	if (!ok.xval.terminal_mlrval.u.boolv) {
		fprintf(stderr, "%s: %s type-assertion failed at NR=%lld FNR=%lld FILENAME=%s\n",
			MLR_GLOBALS.bargv0, pstate->desc, pvars->pctx->nr, pvars->pctx->fnr, pvars->pctx->filename);
		exit(1);
	}

	return val1;
}
static void rxval_evaluator_A_x_free(rxval_evaluator_t* pevaluator) {
	rxval_evaluator_A_x_state_t* pstate = pevaluator->pvstate;
	pstate->parg1->pfree_func(pstate->parg1);
	free(pstate->desc);
	free(pstate);
	free(pevaluator);
}

rxval_evaluator_t* rxval_evaluator_alloc_from_A_x_func(
	xv_unary_func_t*    pfunc,
	mlr_dsl_ast_node_t* parg1_node,
	fmgr_t*             pfmgr,
	int                 type_inferencing,
	int                 context_flags,
	char*               desc)
{

	rxval_evaluator_A_x_state_t* pstate = mlr_malloc_or_die(sizeof(rxval_evaluator_A_x_state_t));
	pstate->pfunc = pfunc;
	pstate->parg1 = rxval_evaluator_alloc_from_ast(parg1_node, pfmgr, type_inferencing, context_flags);
	pstate->desc  = mlr_strdup_or_die(desc);

	rxval_evaluator_t* pevaluator = mlr_malloc_or_die(sizeof(rxval_evaluator_t));
	pevaluator->pvstate = pstate;
	pevaluator->pprocess_func = rxval_evaluator_A_x_func;
	pevaluator->pfree_func = rxval_evaluator_A_x_free;

	return pevaluator;
}
