/**
 * @file verbs.h
 * @brief Declares the one dispatch table that replaces the reference's reflection.
 *
 * The Go runtime resolves a verb with reflect.MethodByName("Command" + NAME), a
 * function with "Function" + NAME, and a special parse path with "ParseCommand" +
 * NAME. C has no reflection and none is being added. All three collapse into the
 * table in src/verbs.c: sorted by name, searched with bsearch, one row per verb.
 *
 * Adding a verb is adding one row and up to two functions. A NULL parse handler
 * means "parse the rval as a plain expression", which is exactly what
 * commandByReflection returning (nil, nil) means in the reference. A NULL exec
 * handler means the token is consumed by another verb's parser and never
 * evaluated on its own -- THEN, ELSE, TO and STEP are all like that.
 */

#ifndef _AKBASIC_VERBS_H_
#define _AKBASIC_VERBS_H_

#include <akerror.h>

#include <akbasic/grammar.h>
#include <akbasic/types.h>

struct akbasic_Parser;
struct akbasic_Runtime;

typedef akerr_ErrorContext AKERR_NOIGNORE *(*akbasic_ParseHandler)(struct akbasic_Parser *parser, akbasic_ASTLeaf **dest);
typedef akerr_ErrorContext AKERR_NOIGNORE *(*akbasic_ExecHandler)(struct akbasic_Runtime *obj, akbasic_ASTLeaf *expr, akbasic_Value *lval, akbasic_Value *rval, akbasic_Value **dest);

typedef struct
{
    const char *name;
    akbasic_TokenType tokentype;
    int arity;			/** Argument count for a function; -1 when not applicable */
    akbasic_ParseHandler parse;
    akbasic_ExecHandler exec;
} akbasic_Verb;

/**
 * @brief Find a verb, function or reserved word by name, case-insensitively.
 *
 * Verbs and function names are case-insensitive in this dialect; variable names
 * are not. That asymmetry lives here.
 *
 * @param name Name to look up; matched without regard to case.
 * @param dest Output destination populated by the function; set to NULL on a miss.
 * @return `NULL` on success, otherwise an error context owned by the caller.
 * @throws AKERR_NULLPOINTER When `name` or `dest` is NULL.
 */
akerr_ErrorContext AKERR_NOIGNORE *akbasic_verb_lookup(const char *name, const akbasic_Verb **dest);

/** @brief The table itself, exposed so tests can assert it is sorted. */
const akbasic_Verb *akbasic_verb_table(int *count);

#endif // _AKBASIC_VERBS_H_
