/* opcodes.c: Information about opcodes. */

#define _POSIX_SOURCE

#include <ctype.h>
#include "x.tab.h"
#include "opcodes.h"
#include "operator.h"
#include "util.h"

#define NUM_OPERATORS (sizeof(op_info) / sizeof(*op_info))

Op_info op_table[LAST_TOKEN];

static int first_function;

static Op_info op_info[] = {

    /* Opcodes generated by language syntax (syntaxop.c). */
    { COMMENT,		"COMMENT",		op_comment, STRING },
    { POP,		"POP",			op_pop },
    { SET_LOCAL,	"SET_LOCAL",		op_set_local, VAR },
    { SET_OBJ_VAR,	"SET_OBJ_VAR",		op_set_obj_var, IDENT },
    { IF,		"IF",			op_if, JUMP },
    { IF_ELSE,		"IF_ELSE",		op_if, JUMP },
    { ELSE,		"ELSE",			op_else, JUMP },
    { FOR_RANGE,	"FOR_RANGE",		op_for_range, JUMP, INTEGER },
    { FOR_LIST,		"FOR_LIST",		op_for_list, JUMP, INTEGER },
    { WHILE,		"WHILE",		op_while, JUMP, JUMP },
    { SWITCH,		"SWITCH",		op_switch, JUMP },
    { CASE_VALUE,	"CASE_VALUE",		op_case_value, JUMP },
    { CASE_RANGE,	"CASE_RANGE",		op_case_range, JUMP },
    { LAST_CASE_VALUE,	"LAST_CASE_VALUE",	op_last_case_value, JUMP },
    { LAST_CASE_RANGE,	"LAST_CASE_RANGE",	op_last_case_range, JUMP },
    { END_CASE,		"END_CASE",		op_end_case, JUMP },
    { DEFAULT,		"DEFAULT",		op_default },
    { END,		"END",			op_end, JUMP },
    { BREAK,		"BREAK",		op_break, JUMP, INTEGER },
    { CONTINUE,		"CONTINUE",		op_continue, JUMP, INTEGER },
    { RETURN,		"RETURN",		op_return },
    { RETURN_EXPR,	"RETURN_EXPR",		op_return_expr },
    { CATCH,		"CATCH",		op_catch, JUMP, ERROR },
    { CATCH_END,	"CATCH_END",		op_catch_end, JUMP },
    { HANDLER_END,	"HANDLER_END",		op_handler_end },

    { ZERO,		"ZERO",			op_zero },
    { ONE,		"ONE",			op_one },
    { INTEGER,		"INTEGER",		op_integer, INTEGER },
    { STRING,		"STRING",		op_string, STRING },
    { DBREF,		"DBREF",		op_dbref, INTEGER },
    { SYMBOL,		"SYMBOL",		op_symbol, IDENT },
    { ERROR,		"ERROR",		op_error, IDENT },
    { NAME,		"NAME",			op_name, IDENT },
    { GET_LOCAL,	"GET_LOCAL",		op_get_local, VAR },
    { GET_OBJ_VAR,	"GET_OBJ_VAR",		op_get_obj_var,	IDENT },
    { START_ARGS,	"START_ARGS",		op_start_args },
    { PASS,		"PASS",			op_pass },
    { MESSAGE,		"MESSAGE",		op_message, IDENT },
    { EXPR_MESSAGE,	"EXPR_MESSAGE",		op_expr_message },
    { LIST,		"LIST",			op_list },
    { DICT,		"DICT",			op_dict },
    { BUFFER,		"BUFFER",		op_buffer },
    { FROB,		"FROB",			op_frob },
    { INDEX,		"INDEX",		op_index },
    { AND,		"AND",			op_and, JUMP },
    { OR,		"OR",			op_or, JUMP },
    { CONDITIONAL,	"CONDITIONAL",		op_if, JUMP },
    { SPLICE,		"SPLICE",		op_splice },
    { CRITICAL,		"CRITICAL",		op_critical, JUMP },
    { CRITICAL_END,	"CRITICAL_END", 	op_critical_end },
    { PROPAGATE,	"PROPAGATE",		op_propagate, JUMP },
    { PROPAGATE_END,	"PROPAGATE_END",	op_propagate_end },

    /* Arithmetic and relational operators (arithop.c). */
    { '!',		"!",			op_not },
    { NEG,		"NEG",			op_negate },
    { '*',		"*",			op_multiply },
    { '/',		"/",			op_divide },
    { '%',		"%",			op_modulo },
    { '+',		"+",			op_add },
    { SPLICE_ADD,	"SPLICE_ADD",		op_splice_add },
    { '-',		"-",			op_subtract },
    { EQ,		"EQ",			op_equal },
    { NE,		"NE",			op_not_equal },
    { '>',		">",			op_greater },
    { GE,		">=",			op_greater_or_equal },
    { '<',		"<",			op_less },
    { LE,		"<=",			op_less_or_equal },
    { IN,		"IN",			op_in },

    /* Generic data manipulation (dataop.c). */
    { TYPE,		"type",			op_type },
    { CLASS,		"class",		op_class },
    { TOINT,		"toint",		op_toint },
    { TOSTR,		"tostr",		op_tostr },
    { TOLITERAL,	"toliteral",		op_toliteral },
    { TODBREF,		"todbref",		op_todbref },
    { TOSYM,		"tosym",		op_tosym },
    { TOERR,		"toerr",		op_toerr },
    { VALID,		"valid",		op_valid },

    /* Operations on strings (stringop.c). */
    { STRLEN,		"strlen",		op_strlen },
    { SUBSTR,		"substr",		op_substr },
    { EXPLODE,		"explode",		op_explode },
    { STRSUB,		"strsub",		op_strsub },
    { PAD,		"pad",			op_pad },
    { MATCH_BEGIN,	"match_begin",		op_match_begin },
    { MATCH_TEMPLATE,	"match_template",	op_match_template },
    { MATCH_PATTERN,	"match_pattern",	op_match_pattern },
    { MATCH_REGEXP,	"match_regexp",		op_match_regexp },
    { CRYPT,		"crypt",		op_crypt },
    { UPPERCASE,	"uppercase",		op_uppercase },
    { LOWERCASE,	"lowercase",		op_lowercase },
    { STRCMP,		"strcmp",		op_strcmp },

    /* List manipulation (listop.c). */
    { LISTLEN,		"listlen",		op_listlen },
    { SUBLIST,		"sublist",		op_sublist },
    { INSERT,		"insert",		op_insert },
    { REPLACE,		"replace",		op_replace },
    { DELETE,		"delete",		op_delete },
    { SETADD,		"setadd",		op_setadd },
    { SETREMOVE,	"setremove",		op_setremove },
    { UNION,		"union",		op_union },

    /* Dictionary manipulation (dictop.c). */
    { DICT_KEYS,	"dict_keys",		op_dict_keys },
    { DICT_ADD,		"dict_add",		op_dict_add },
    { DICT_DEL,		"dict_del",		op_dict_del },
    { DICT_CONTAINS,	"dict_contains",	op_dict_contains },

    /* Buffer manipulation (bufferop.c). */
    { BUFFER_LEN,	"buffer_len",		op_buffer_len },
    { BUFFER_RETRIEVE,	"buffer_retrieve",	op_buffer_retrieve },
    { BUFFER_APPEND,	"buffer_append",	op_buffer_append },
    { BUFFER_REPLACE,	"buffer_replace",	op_buffer_replace },
    { BUFFER_ADD,	"buffer_add",		op_buffer_add },
    { BUFFER_TRUNCATE,	"buffer_truncate",	op_buffer_truncate },
    { BUFFER_TO_STRINGS,"buffer_to_strings",	op_buffer_to_strings },
    { BUFFER_FROM_STRINGS,"buffer_from_strings",op_buffer_from_strings },

    /* Miscellaneous operations (miscop.c). */
    { VERSION,		"version",		op_version },
    { RANDOM,		"random",		op_random },
    { TIME,		"time",			op_time },
    { CTIME,		"ctime",		op_ctime },
    { MIN,		"min",			op_min },
    { MAX,		"max",			op_max },
    { ABS,		"abs",			op_abs },
    { GET_NAME,		"get_name",		op_get_name },
    { TICKS_LEFT,       "ticks_left",           op_ticks_left },

    /* Current method information operations (methodop.c). */
    { THIS,		"this",			op_this },
    { DEFINER,		"definer",		op_definer },
    { SENDER,		"sender",		op_sender },
    { CALLER,		"caller",		op_caller },
    { TASK_ID,		"task_id",		op_task_id },

    /* Error handling operations (errorop.c). */
    { ERROR_FUNC,	"error",		op_error_func },
    { TRACEBACK,	"traceback",		op_traceback },
    { THROW,		"throw",		op_throw },
    { RETHROW,		"rethrow",		op_rethrow },

    /* Input and output (ioop.c). */
    { ECHO_FUNC,	"echo",			op_echo },
    { ECHO_FILE,	"echo_file",		op_echo_file },
    { DISCONNECT,	"disconnect",		op_disconnect },

    /* Operations on the current object (objectop.c). */
    { ADD_PARAMETER,	"add_parameter",	op_add_parameter },
    { PARAMETERS,	"parameters",		op_parameters },
    { DEL_PARAMETER,	"del_parameter",	op_del_parameter },
    { SET_VAR,		"set_var",		op_set_var },
    { GET_VAR,		"get_var",		op_get_var },
    { COMPILE,		"compile",		op_compile },
    { METHODS,		"methods",		op_methods },
    { FIND_METHOD,	"find_method",		op_find_method },
    { FIND_NEXT_METHOD,	"find_next_method",	op_find_next_method },
    { LIST_METHOD,	"list_method",		op_list_method },
    { DEL_METHOD,	"del_method",		op_del_method },
    { PARENTS,		"parents",		op_parents },
    { CHILDREN,		"children",		op_children },
    { ANCESTORS,	"ancestors",		op_ancestors },
    { HAS_ANCESTOR,	"has_ancestor",		op_has_ancestor },
    { SIZE,		"size",			op_size },

    /* Administrative operations (adminop.c). */
    { CREATE,		"create",		op_create },
    { CHPARENTS,	"chparents",		op_chparents },
    { DESTROY,		"destroy",		op_destroy },
    { LOG,		"log",			op_log },
    { CONN_ASSIGN,	"conn_assign",		op_conn_assign },
    { BINARY_DUMP,	"binary_dump",		op_binary_dump },
    { TEXT_DUMP,	"text_dump",		op_text_dump },
    { RUN_SCRIPT,	"run_script",		op_run_script },
    { SHUTDOWN,		"shutdown",		op_shutdown },
    { BIND,		"bind",			op_bind },
    { UNBIND,		"unbind",		op_unbind },
    { CONNECT,		"connect",		op_connect },
    { SET_HEARTBEAT_FREQ, "set_heartbeat_freq", op_set_heartbeat_freq },
    { DATA,		"data",			op_data },
    { SET_NAME,		"set_name",		op_set_name },
    { DEL_NAME,		"del_name",		op_del_name },
    { TICK,		"tick",			op_tick },
    { HOSTNAME,		"hostname",		op_hostname },
    { IP,		"ip",			op_ip },
    { DB_TOP,		"db_top",		op_db_top },
    { RESUME,           "resume",               op_resume },
    { SUSPEND,          "suspend",              op_suspend },
    { TASKS,            "tasks",                op_tasks },
    { CANCEL,           "cancel",               op_cancel },
    { PAUSE,            "pause",                op_pause },
    { CALLERS,          "callers",              op_callers }
};

void init_op_table(void)
{
    int i;

    for (i = 0; i < NUM_OPERATORS; i++) {
	op_info[i].symbol = ident_get(op_info[i].name);
	op_table[op_info[i].opcode] = op_info[i];
    }

    /* Look for first opcode with a lowercase name to find the first
     * function. */
    for (i = 0; i < NUM_OPERATORS; i++) {
	if (islower(*op_info[i].name))
	    break;
    }
    first_function = i;
}

int find_function(char *name)
{
    int i;

    for (i = first_function; i < NUM_OPERATORS; i++) {
	if (strcmp(op_info[i].name, name) == 0)
	    return op_info[i].opcode;
    }

    return -1;
}