/**
 * @file args.c
 * @brief Implements the shared positional-argument collector.
 */

#include <akerror.h>

#include <akbasic/args.h>
#include <akbasic/error.h>
#include <akbasic/runtime.h>

akerr_ErrorContext *akbasic_args_numbers(akbasic_Runtime *obj, akbasic_ASTLeaf *expr, const char *verb, double *values, int max, int *count)
{
    PREPARE_ERROR(errctx);
    akbasic_ASTLeaf *arg = NULL;
    akbasic_Value *value = NULL;

    FAIL_ZERO_RETURN(errctx, (obj != NULL && expr != NULL && values != NULL && count != NULL),
		     AKERR_NULLPOINTER, "NULL argument in args_numbers");
    *count = 0;
    arg = akbasic_leaf_first_argument(expr);
    /*
     * A loop, so CATCH and the _BREAK macros are banned in here -- they expand to
     * a C break and would leave the loop with an error still pending. PASS and
     * the _RETURN forms only.
     */
    while ( arg != NULL ) {
	FAIL_NONZERO_RETURN(errctx, (*count >= max), AKBASIC_ERR_SYNTAX,
			    "%s takes at most %d arguments", verb, max);
	PASS(errctx, akbasic_runtime_evaluate(obj, arg, &value));
	FAIL_NONZERO_RETURN(errctx, (value->valuetype == AKBASIC_TYPE_STRING),
			    AKBASIC_ERR_TYPE,
			    "%s expected a number in argument %d", verb, *count + 1);
	if ( value->valuetype == AKBASIC_TYPE_FLOAT ) {
	    values[*count] = value->floatval;
	} else {
	    values[*count] = (double)value->intval;
	}
	*count += 1;
	arg = arg->next;
    }
    SUCCEED_RETURN(errctx);
}
