/*
 *  SPL - The SPL Programming Language
 *  Copyright (C) 2004, 2005  Clifford Wolf <clifford@clifford.at>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  spl.h: Everything you need to embed SPL in your programs is here.
 */

#ifndef SPL_H
#define SPL_H

#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>

#ifdef  __cplusplus
extern "C" {
#endif

/* Signature for SPL bytecode and dump files */
// ---------------------- 0123456789abcdef
#define SPL_SIGNATURE "\374SPL-BytecodeV2"

/* Checksum of this header for ABI checksum */
#define SPL_ABICKSUM 766347257
#define SPL_ABI(sym) (SPL_ABI_766347257_ ## sym)

struct spl_string {
	struct spl_string *left, *right;
	unsigned int left_offset, left_len;
	unsigned int right_offset, right_len;
	struct spl_code *code;
	char *text;
	int ref_counter, flags;
	unsigned int text_len, total_len;
};

#define SPL_STRING_STATIC	0x0001
#define SPL_STRING_DOTCAT	0x0002
#define SPL_STRING_UTF8		0x0004

#define SPL_STRING_NOAUTOGET	0x0100

struct spl_node {
	struct spl_node *ctx, *cls;
	struct spl_node *gc_left, *gc_right;
	struct spl_node_sub *subs_begin;
	struct spl_node_sub *subs_end;
	struct spl_node_sub **subs_hash;
	int subs_counter;
	int subs_hash_size;
	int subs_next_idx;
	struct spl_code *code;
	int code_ip;
	int ctx_type;
	int ref_counter;
	int dump_tag;
	int value;
	struct spl_string *value_string;
	int value_int;
	double value_float;
	char *hnode_name;
	void *hnode_data;
	char *hnode_dump;
	int flags;
	char *path;
	int path_metric;
	struct spl_node *path_parent;
};

#define SPL_VALUE_STRING	0x01
#define SPL_VALUE_INT		0x02
#define SPL_VALUE_FLOAT		0x04

struct spl_node_sub {
	struct spl_node_sub *last;
	struct spl_node_sub *next;
	struct spl_node_sub *hash_next;
	struct spl_node *node;
	char *module, *key;
};

/* There are three different context types in SPL. */
/* Don't think about it - usually it just does what you would expect. */

/* Lookups go thru, Creates only stop here if new or declared local */
#define SPL_CTX_FUNCTION 1
#define SPL_CTX_OBJECT 2

/* Only stop if keyword is already defined or declared local */
#define SPL_CTX_LOCAL 3

/* Always stop here (automatically, because there is no next ctx) */
#define SPL_CTX_ROOT 4

#define SPL_NODE_FLAG_FUNCTION	0x00001
#define SPL_NODE_FLAG_METHOD	0x00002
#define SPL_NODE_FLAG_RETINFO	0x00004
#define SPL_NODE_FLAG_STATIC	0x00008
#define SPL_NODE_FLAG_CLASS	0x00010
#define SPL_NODE_FLAG_CLNULL	0x00020
#define SPL_NODE_FLAG_CLEXCEPT	0x00040
#define SPL_NODE_FLAG_EXCEPTION	0x00080
#define SPL_NODE_FLAG_TRY	0x00100
#define SPL_NODE_FLAG_CATCH	0x00200
#define SPL_NODE_FLAG_RERES	0x00400
#define SPL_NODE_FLAG_ARGC	0x00800
#define SPL_NODE_FLAG_IS_INT	0x01000
#define SPL_NODE_FLAG_IS_FLOAT	0x02000

#define SPL_NODE_FLAG_GC	0x10000

struct spl_node_stack {
	struct spl_node *node;
	struct spl_node_stack *next;
};

struct spl_task {
	char *id;
	struct spl_task *next;
	struct spl_node_stack *stack;
	struct spl_node_stack *cleanup;
	struct spl_node *ctx;
	struct spl_code *code;
	struct spl_vm *vm;
	char *debug_str;
	char *module;
	int code_ip;
	int debug;
	int dump_tag;
	int flags;
	int goterr;
};

#define SPL_TASK_FLAG_SYSTEM	0x0001
#define SPL_TASK_FLAG_PAUSED	0x0002
#define SPL_TASK_FLAG_ZOMBIE	0x0004
#define SPL_TASK_FLAG_PUBLIC	0x0008
#define SPL_TASK_FLAG_BUSY	0x0010

typedef int spl_runloop_function(struct spl_vm *vm, struct spl_task *wait_task);

typedef struct spl_node *spl_clib_function(struct spl_task *task, void *data);

struct spl_clib {
	struct spl_clib *next;
	spl_clib_function *handler;
	void *data;
	char *name;
};

struct spl_hnode_args {
	int action;
	const char *key;
	int flags;
	struct spl_node *value;
};

#define SPL_HNODE_ACTION_LOOKUP	0x1
#define SPL_HNODE_ACTION_CREATE	0x2
#define SPL_HNODE_ACTION_DELETE	0x3
#define SPL_HNODE_ACTION_NEXT	0x4
#define SPL_HNODE_ACTION_PREV	0x5
#define SPL_HNODE_ACTION_COPY	0x6
#define SPL_HNODE_ACTION_PUT	0x7
#define SPL_HNODE_ACTION_DUMP	0x8

typedef void spl_hnode_function(struct spl_task *task, struct spl_vm *vm,
		struct spl_node *node, struct spl_hnode_args *args, void *data);

struct spl_hnode {
	struct spl_hnode *next;
	spl_hnode_function *handler;
	void *data;
	char *name;
};

struct spl_module;
typedef void spl_module_init_func(struct spl_vm *vm, struct spl_module *mod, int restore);
typedef void spl_module_done_func(struct spl_vm *vm, struct spl_module *mod);

struct spl_module {
	struct spl_module *next;
	spl_module_done_func *donefunc;
	void *dlhandle;
	void *data;
	char *name;
};

struct spl_builtin_module {
	struct spl_builtin_module *next;
	spl_module_init_func *initfunc;
	spl_module_done_func *donefunc;
	char *name;
};

extern struct spl_builtin_module *spl_builtin_module_list;

#define SPL_REGISTER_BUILTIN_MODULE(mod)				\
	do {								\
		extern spl_module_init_func SPL_ABI(spl_mod_ ## mod ## _init);	\
		extern spl_module_done_func SPL_ABI(spl_mod_ ## mod ## _done);	\
		struct spl_builtin_module *m =				\
			malloc(sizeof(struct spl_builtin_module));	\
		m->next = spl_builtin_module_list;			\
		m->initfunc = SPL_ABI(spl_mod_ ## mod ## _init);	\
		m->donefunc = SPL_ABI(spl_mod_ ## mod ## _done);	\
		m->name = #mod;						\
		spl_builtin_module_list = m;				\
	} while (0)

#define SPL_FREE_BUILTIN_MODULES()					\
	do {								\
		struct spl_builtin_module *m;				\
		while (spl_builtin_module_list) {			\
			m = spl_builtin_module_list->next;		\
			free(spl_builtin_module_list);			\
			spl_builtin_module_list = m;			\
		}							\
	} while (0)

struct spl_vm {
	struct spl_node *root;
	struct spl_node *gc_list;
	struct spl_task *task_list;
	struct spl_clib **clib_hash;
	int clib_hash_size;
	int clib_hash_count;
	struct spl_hnode *hnode_list;
	struct spl_module *module_list;
	int gc_last_ic, ic;
	int gc_last_treesize;
	int gc_last_allsize;
	struct spl_node_stack *free_node_stack_elements;

	spl_runloop_function *runloop;
	int destroy_in_progress;

	int undumpable;
	const char *undumpable_info;
	int undumpable_info_counter;

	/* the following stuff must be provided by the
	 * host application but is free'd automatically
	 * by spl_vm_destroy().
	 */
	char *current_dir_name;
	char *codecache_dir;
	char *path;

	/* the following stuff must be provided and
	 * managed by the host application or modules
	 */
	struct cgi_context *cgi_ctx;
	struct sql_backend *sql_backends;
	int sdl_initialized;
};

struct spl_code {
	char *id, *sha1;
	int size;
	unsigned char *code;
	int code_type;
	int ref_counter;
	int dump_tag;
};

#define SPL_CODE_STATIC   1
#define SPL_CODE_MALLOCED 2
#define SPL_CODE_MAPPED   3

struct spl_asm_label {
	struct spl_asm_label *next;
	int ref[1024], refc;
	int position;
	char *name;
};

struct spl_asm {
	unsigned char *text;
	char *data;
	int text_size_roof, text_size;
	int data_size_roof, data_size;
	struct spl_asm_label *labels;
	struct spl_vm *vm;
};

/* state.c functions */

extern struct spl_vm *spl_vm_create(void);
extern void spl_vm_destroy(struct spl_vm *vm);
extern struct spl_node_stack *spl_vm_malloc_node_stack_element(struct spl_vm *vm);
extern void spl_vm_free_node_stack_element(struct spl_vm *vm, struct spl_node_stack * const n);

extern void spl_undumpable_inc(struct spl_vm *vm, const char *info);
extern void spl_undumpable_dec(struct spl_vm *vm, const char *info);

extern struct spl_code *spl_code_get(struct spl_code *code);
extern void spl_code_put(struct spl_code *code);
extern const char *spl_code_sha1(struct spl_code *code);

unsigned int spl_subs_hash(const char *key, int max_hash);

extern struct spl_task *spl_task_lookup(struct spl_vm *vm, const char *id);
extern struct spl_task *spl_task_create(struct spl_vm *vm, const char *id);
extern void spl_task_destroy(struct spl_vm *vm, struct spl_task *task);
extern void spl_task_setcode(struct spl_task *task, struct spl_code *code);

extern void spl_subs_hash_check(struct spl_node *node);
extern struct spl_node_sub *spl_sub_lookup(struct spl_node *node, const char *key);

extern struct spl_node *spl_lookup(struct spl_task *task, struct spl_node *node, const char *key, int flags);
extern struct spl_node *spl_create(struct spl_task *task, struct spl_node *node, const char *key, struct spl_node *newnode, int flags);
extern void spl_delete(struct spl_task *task, struct spl_node *node, const char *key);

#define SPL_LOOKUP_TEST		0x0001
#define SPL_LOOKUP_NOCTX	0x0002
#define SPL_LOOKUP_CLS		0x0004
#define SPL_LOOKUP_NOSTATIC	0x0010

#define SPL_CREATE_LOCAL	0x0100
#define SPL_CREATE_BEGIN	0x0200
#define SPL_CREATE_NOSTATIC	0x0400
#define SPL_CREATE_FUNCLOCAL	0x1000

#define SPL_TYPE_NONE	0x00
#define SPL_TYPE_INT	0x01
#define SPL_TYPE_FLOAT	0x02
#define SPL_TYPE_OBJ	0x03

extern int spl_get_int(struct spl_node *node);
extern double spl_get_float(struct spl_node *node);
extern char *spl_get_string(struct spl_node *node);
extern struct spl_string *spl_get_spl_string(struct spl_node *node);
extern char *spl_get_value(struct spl_node *node);
extern int spl_get_type(struct spl_node *node);

extern struct spl_node *spl_set_int(struct spl_node *node, int value);
extern struct spl_node *spl_set_float(struct spl_node *node, double value);
extern struct spl_node *spl_set_string(struct spl_node *node, char *value);
extern struct spl_node *spl_set_spl_string(struct spl_node *node, struct spl_string *value);

extern struct spl_node *spl_push(struct spl_task *task, struct spl_node *node);
extern struct spl_node *spl_pop(struct spl_task *task);
extern struct spl_node *spl_tos(struct spl_task *task);

extern struct spl_node *spl_get(struct spl_node *node);
extern void spl_put(struct spl_vm *vm, struct spl_node *node);
extern struct spl_node *spl_cleanup(struct spl_task *task, struct spl_node *node);
extern struct spl_node *spl_copy(struct spl_vm *vm, struct spl_node *node, struct spl_node *cls);

extern char *spl_hash_encode(const char *source);
extern char *spl_hash_decode(const char *source);

/* state.c gc debugging counter */

extern int spl_state_counter_malloc;
extern int spl_state_counter_free;

/* report.c functions */

typedef void spl_report_func(int type, void *desc, const char *fmt, ...)
	__attribute__ ((format (printf, 3, 4)));

extern spl_report_func *spl_report;

#define SPL_REPORT_HOST		0x0001	// desc = spl_vm
#define SPL_REPORT_ASSEMBLER	0x0002  // desc = spl_asm
#define SPL_REPORT_COMPILER	0x0003	// desc = spl_asm
#define SPL_REPORT_LEXER	0x0004	// desc = spl_asm
#define SPL_REPORT_RUNTIME	0x0005	// desc = spl_task
#define SPL_REPORT_RESTORE	0x0006	// desc = spl_vm

#define SPL_REPORT_WARNING	0x0010
#define SPL_REPORT_DEBUG	0x0020

extern char *spl_report_type2txt(int type);

extern void spl_report_file(FILE *f, int type, void *desc, const char *fmt, va_list ap)
	__attribute__ ((format (printf, 4, 0)));

extern char *spl_report_string(int type, void *desc, const char *fmt, va_list ap)
	__attribute__ ((format (printf, 3, 0)));

extern void spl_report_func_stderr(int type, void *desc, const char *fmt, ...)
	__attribute__ ((format (printf, 3, 4)));
extern void spl_report_func_stdout(int type, void *desc, const char *fmt, ...)
	__attribute__ ((format (printf, 3, 4)));

/* some macros and inline functions */
#define SPL_NEW_INT(__v)        spl_set_int(spl_get(0), (__v))
#define SPL_NEW_FLOAT(__v)      spl_set_float(spl_get(0), (__v))
#define SPL_NEW_SPL_STRING(__v) spl_set_spl_string(spl_get(0), (__v))
#define SPL_NEW_STRING(__v)     spl_set_string(spl_get(0), (__v))
#define SPL_NEW_STRING_DUP(__v) spl_set_string(spl_get(0), strdup(__v))

#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
#  define SPL_NEW_PRINTF(...) \
	(SPL_NEW_SPL_STRING(spl_string_printf(0, 0, 0, ## __VA_ARGS__)))
#endif

#define SPL_POP_CLEANUP(__t) \
	spl_cleanup(__t, spl_pop(__t))

/* exec.c function */

extern int spl_exec(struct spl_task *task);

/* gc.c function */

extern int spl_gc(struct spl_vm *vm);
extern int spl_gc_maybe(struct spl_vm *vm);

/* spl_op.c functions */

struct spl_asm_op {
	const char * const name;
	const unsigned char op;
	const char          optype;
};
extern const struct spl_asm_op spl_ops[];

/* asm.c functions */

static inline void spl_int_to_bytes(int value, int c, unsigned char *pos)
{
	while (c-->0) {
		*(pos+c) = value & 0xff;
		value = value >> 8;
	}
}

static inline int spl_bytes_to_int(int c, const unsigned char *pos)
{
	int value = *pos >= 0x80 ? ~0 : 0;
	while (c-->0)
		value = value << 8 | *(pos++);
	return value;
}

extern struct spl_asm *spl_asm_create(void);
extern void spl_asm_destroy(struct spl_asm *as);
extern int spl_asm_newdata(struct spl_asm *as, const char *arg);
extern int spl_asm_add(struct spl_asm *as, unsigned char op, const char *arg);
extern void spl_asm_setaddr(struct spl_asm *as, int pos, int32_t addr);
extern int spl_asm_write(struct spl_asm *as, int fd);
extern struct spl_code *spl_asm_dump(struct spl_asm *as);

extern const char *spl_asm_op2txt(int op);
extern int spl_asm_txt2op(const char *txt);
extern void spl_asm_print(struct spl_asm *as, int print_data_seg);

/* va_args: [ int size, int from_pos, int to_pos, [...] ], -1 */
extern void spl_asm_shuffle(struct spl_asm *as, ...);

extern int spl_asm_setlabel(struct spl_asm *as, char *label, int pos);
extern void spl_asm_reflabel(struct spl_asm *as, char *label, int pos);
extern int spl_asm_resolve_labels(struct spl_asm *as);

extern int spl_asm_parse_line(struct spl_asm *as, const char *line);

/* optimizer.c function */

extern int spl_optype(int opcode);
extern void spl_optimizer(struct spl_asm *as);

/* compiler.y function */

extern int spl_yydebug;
extern int spl_dump_translatable_strings;

typedef void *spl_malloc_file_function(const char *filename, int *size);
extern int spl_compiler(struct spl_asm *a, const char *prog, const char *name, spl_malloc_file_function *malloc_file_func, int gen_debug_info);

/* treedump.c functions */

extern void spl_treedump(struct spl_vm *vm, FILE *file, int flags, const char *prefix);
extern char *spl_treedump_string(struct spl_vm *vm, int flags, const char *prefix);

#define SPL_TREEDUMP_FLAG_ALL ~0

#define SPL_TREEDUMP_FLAG_ADDR		0x0001
#define SPL_TREEDUMP_FLAG_VALUE		0x0002
#define SPL_TREEDUMP_FLAG_CTX		0x0004
#define SPL_TREEDUMP_FLAG_CLS		0x0008
#define SPL_TREEDUMP_FLAG_LINK		0x0010
#define SPL_TREEDUMP_FLAG_MODS		0x0020
#define SPL_TREEDUMP_FLAG_TASKS		0x0040
#define SPL_TREEDUMP_FLAG_FLAGS		0x0080
#define SPL_TREEDUMP_FLAG_CTXTYPE	0x0100
#define SPL_TREEDUMP_FLAG_HNODE		0x0200

extern void spl_backtrace(struct spl_task *task, FILE *file);
extern char *spl_backtrace_string(struct spl_task *task);

/* debug.c function */

extern void spl_debug_reset(void);
extern int spl_debug_exec(struct spl_task *task);

/* rccheck.c function */

extern void spl_rccheck(struct spl_vm *vm);

/* dump.c function */

extern int spl_dump_ascii(struct spl_vm *vm, FILE *file);

/* restore.c function */

extern struct spl_vm* spl_restore_ascii(struct spl_vm*, FILE *file);

/* clib.c functions */

extern void spl_clib_reg(struct spl_vm *vm, const char *name, spl_clib_function *handler, void *data);
extern int spl_clib_call(struct spl_task *task, const char *name);

extern int spl_clib_get_argc(struct spl_task *task);
extern struct spl_node *spl_clib_get_hargs(struct spl_task *task);
extern struct spl_node *spl_clib_get_node(struct spl_task *task);
extern int spl_clib_get_int(struct spl_task *task);
extern double spl_clib_get_float(struct spl_task *task);
extern char *spl_clib_get_string(struct spl_task *task);

// vaargs: [ const char *member_name, struct spl_node *member, [ .. ] ], NULL
extern struct spl_node *spl_clib_new(struct spl_task *task, const char *classname, ...);
extern void spl_clib_exception(struct spl_task *task, const char *classname, ...);

extern struct spl_task *spl_clib_callback_task(struct spl_vm *vm);
extern int spl_clib_callback_run(struct spl_task *task);

extern int spl_module_load(struct spl_vm *vm, const char *name, int restore);
extern void spl_module_unload_all(struct spl_vm *vm);

/* hnode.c functions */

void spl_hnode_reg(struct spl_vm *vm, const char *name, spl_hnode_function *handler, void *data);
void spl_hnode(struct spl_vm *vm, struct spl_node *node, const char *key, const char *handler, struct spl_module *mod);

void spl_hnode_call(struct spl_task *task, struct spl_vm *vm, struct spl_node *node, struct spl_hnode_args *args);

struct spl_node *spl_hnode_lookup(struct spl_task *task, struct spl_node *node, const char *key, int flags);
struct spl_node *spl_hnode_create(struct spl_task *task, struct spl_node *node, const char *key, struct spl_node *newnode, int flags);
void spl_hnode_delete(struct spl_task *task, struct spl_node *node, const char *key);
struct spl_node *spl_hnode_next(struct spl_task *task, struct spl_node *node, const char *key);
struct spl_node *spl_hnode_prev(struct spl_task *task, struct spl_node *node, const char *key);
struct spl_node *spl_hnode_copy(struct spl_vm *vm, struct spl_node *node);
void spl_hnode_put(struct spl_vm *vm, struct spl_node *node);
void spl_hnode_dump(struct spl_vm *vm, struct spl_node *node);

/* string.c functions */

extern struct spl_string *spl_string_new(int flags, struct spl_string *left, struct spl_string *right, char *text, struct spl_code *code);

extern struct spl_string *spl_string_printf(int flags, struct spl_string *left, struct spl_string *right, const char *fmt, ...) __attribute__ ((format (printf, 4, 5)));

extern struct spl_string *spl_string_split(struct spl_string *s, unsigned int offset, unsigned int len);

extern struct spl_string *spl_string_get(struct spl_string *s);
extern void spl_string_put(struct spl_string *s);

extern char *spl_string(struct spl_string *s);

/* util.c functions */

extern int spl_eval(struct spl_vm *vm, struct spl_node *ctx, char *module, const char *program);
extern int spl_eval_bytecode(struct spl_vm *vm, struct spl_node *ctx, char *module, struct spl_code *bytecode);

extern struct spl_task *spl_schedule(struct spl_task *task);
extern int spl_simple_runloop(struct spl_vm *vm, struct spl_task *wait_task);

extern void *spl_mmap_file(const char *filename, int *size);
extern void *spl_malloc_file(const char *filename, int *size);

/* utf8.c functions */

const char *spl_utf8_check(const char *text);
char *spl_utf8_import(const char *text, const char *charset);
char *spl_utf8_export(const char *text, const char *charset);

/* builtins.c functions */

extern struct spl_node *spl_builtin_write(struct spl_task *task, void *data);
extern struct spl_node *spl_builtin_read(struct spl_task *task, void *data);

extern struct spl_node *spl_builtin_chr(struct spl_task *task, void *data);
extern struct spl_node *spl_builtin_ord(struct spl_task *task, void *data);

extern struct spl_node *spl_builtin_hex(struct spl_task *task, void *data);
extern struct spl_node *spl_builtin_oct(struct spl_task *task, void *data);
extern struct spl_node *spl_builtin_bin(struct spl_task *task, void *data);
extern struct spl_node *spl_builtin_fmt(struct spl_task *task, void *data);

extern struct spl_node *spl_builtin_math1_wrapper(struct spl_task *task, void *data);
extern struct spl_node *spl_builtin_math2_wrapper(struct spl_task *task, void *data);

extern void spl_builtin_register_all(struct spl_vm *vm);

/* sha1.c function */

extern void spl_sha1(unsigned char *buffer, unsigned int buffer_len, unsigned char *digest);

/* moddir.c function */

extern const char *spl_system_modules_dir(void);

/**** instruction opcodes with addr argument (0x00 - 0x1f) ****/

#define SPL_OP_JUMP		0x00		// JUMP
#define SPL_OP_REGF		0x04		// BRANCH
#define SPL_OP_REGM		0x08		// BRANCH
#define SPL_OP_ENTER		0x0c		// BRANCH

#define SPL_OP_GOTO		0x10		// JUMP
#define SPL_OP_CATCH		0x14		// BRANCH

// 2 free opcodes with addr argument

/**** instruction opcodes with string argument (0x20 - 0x5f) ****/

#define SPL_OP_PUSH		0x20
#define SPL_OP_PUSHC		0x24		// STATICOP
#define SPL_OP_POP		0x28

// 1 free opcode with string argument

#define SPL_OP_PUSHA		0x30
#define SPL_OP_PUSHAC		0x34
#define SPL_OP_POPA		0x38

// 1 free opcode with string argument

#define SPL_OP_CLIB		0x40
#define SPL_OP_DCALL		0x44

#define SPL_OP_DBGSYM		0x48

#define SPL_OP_OBJOP		0x4c

// 4 free opcodes with string argument

/**** instruction opcodes without argument (0x60 - 0xff) ****/

// 16 free opcodes

#define SPL_OP_ZERO		0x70		// STATICOP
#define SPL_OP_ONE		0x71		// STATICOP
#define SPL_OP_UNDEF		0x72		// STATICOP

// 1 free opcode

#define SPL_OP_REMATCH		0x74
#define SPL_OP_RESUBST		0x75

// 2 free opcodes

#define SPL_OP_DEFINED		0x78
#define SPL_OP_DECLARED		0x79

// 2 free opcodes

#define SPL_OP_NEXT		0x7c
#define SPL_OP_PREV		0x7d

#define SPL_OP_HGETA		0x7e
#define SPL_OP_HSETA		0x7f

#define SPL_OP_CALL		0x80
#define SPL_OP_BEGIN		0x81
#define SPL_OP_END		0x82
#define SPL_OP_RETURN		0x83		// ENDBRANCH
#define SPL_OP_OBJECT		0x84
#define SPL_OP_ENDOBJ		0x85
#define SPL_OP_IMPORT		0x86
#define SPL_OP_LIFTCALL		0x87

#define SPL_OP_IF		0x88		// CONDIT
#define SPL_OP_UNLESS		0x89		// CONDIT

#define SPL_OP_TRY		0x8a
#define SPL_OP_THROW		0x8b		// ENDBRANCH

#define SPL_OP_NEW		0x8c
#define SPL_OP_SETCTX		0x8d

// 2 free opcodes

#define SPL_OP_GETVAL		0x90
#define SPL_OP_COPY		0x91
#define SPL_OP_DROP		0x92

// 1 free opcode

#define SPL_OP_POPI		0x94
#define SPL_OP_POPIC		0x95
#define SPL_OP_POPL		0x96
#define SPL_OP_POPLC		0x97
#define SPL_OP_POPS		0x98
#define SPL_OP_POPSC		0x99
#define SPL_OP_POPU		0x9a
#define SPL_OP_POPUC		0x9b

#define SPL_OP_PUSHAV		0x9c
#define SPL_OP_CLEARA		0x9d

#define SPL_OP_APUSHA		0x9e
#define SPL_OP_APOPA		0x9f

#define SPL_OP_HENC		0xa0		// UNARYOP
#define SPL_OP_HDEC		0xa1		// UNARYOP
#define SPL_OP_CAT		0xa2		// BINARYOP
#define SPL_OP_DOTCAT		0xa3		// BINARYOP

#define SPL_OP_APOP		0xa4
#define SPL_OP_ASHIFT		0xa5

#define SPL_OP_APUSH		0xa6
#define SPL_OP_AUNSHIFT		0xa7

#define SPL_OP_APUSHREF		0xa8
#define SPL_OP_APUSHREFID	0xa9

#define SPL_OP_LENGTH		0xaa		// UNARYOP
#define SPL_OP_ELEMENTS		0xab

#define SPL_OP_LAND		0xac		// BINARYOP
#define SPL_OP_LOR		0xad		// BINARYOP
#define SPL_OP_LNOT		0xae		// UNARYOP
#define SPL_OP_NEG		0xaf		// UNARYOP

#define SPL_OP_EQ		0xb0		// BINARYOP
#define SPL_OP_NE		0xb1		// BINARYOP
#define SPL_OP_LT		0xb2		// BINARYOP
#define SPL_OP_GT		0xb3		// BINARYOP
#define SPL_OP_LE		0xb4		// BINARYOP
#define SPL_OP_GE		0xb5		// BINARYOP

// 2 free opcodes

#define SPL_OP_ADD		0xb8		// BINARYOP
#define SPL_OP_SUB		0xb9		// BINARYOP
#define SPL_OP_MUL		0xba		// BINARYOP
#define SPL_OP_DIV		0xbb		// BINARYOP
#define SPL_OP_MOD		0xbc		// BINARYOP
#define SPL_OP_POW		0xbd		// BINARYOP

// 2 free opcodes

#define SPL_OP_IEQ		0xc0		// BINARYOP
#define SPL_OP_INE		0xc1		// BINARYOP
#define SPL_OP_ILT		0xc2		// BINARYOP
#define SPL_OP_IGT		0xc3		// BINARYOP
#define SPL_OP_ILE		0xc4		// BINARYOP
#define SPL_OP_IGE		0xc5		// BINARYOP

// 2 free opcodes

#define SPL_OP_IADD		0xc8		// BINARYOP
#define SPL_OP_ISUB		0xc9		// BINARYOP
#define SPL_OP_IMUL		0xca		// BINARYOP
#define SPL_OP_IDIV		0xcb		// BINARYOP
#define SPL_OP_IMOD		0xcc		// BINARYOP
#define SPL_OP_IPOW		0xcd		// BINARYOP

// 2 free opcodes

#define SPL_OP_FEQ		0xd0		// BINARYOP
#define SPL_OP_FNE		0xd1		// BINARYOP
#define SPL_OP_FLT		0xd2		// BINARYOP
#define SPL_OP_FGT		0xd3		// BINARYOP
#define SPL_OP_FLE		0xd4		// BINARYOP
#define SPL_OP_FGE		0xd5		// BINARYOP

// 2 free opcodes

#define SPL_OP_FADD		0xd8		// BINARYOP
#define SPL_OP_FSUB		0xd9		// BINARYOP
#define SPL_OP_FMUL		0xda		// BINARYOP
#define SPL_OP_FDIV		0xdb		// BINARYOP
#define SPL_OP_FMOD		0xdc		// BINARYOP
#define SPL_OP_FPOW		0xdd		// BINARYOP

// 2 free opcodes

#define SPL_OP_SEQ		0xe0		// BINARYOP
#define SPL_OP_SNE		0xe1		// BINARYOP
#define SPL_OP_SLT		0xe2		// BINARYOP
#define SPL_OP_SGT		0xe3		// BINARYOP
#define SPL_OP_SLE		0xe4		// BINARYOP
#define SPL_OP_SGE		0xe5		// BINARYOP

#define SPL_OP_PEQ		0xe6

// 1 free opcode

#define SPL_OP_POSTINC		0xe8
#define SPL_OP_POSTDEC		0xe9
#define SPL_OP_PREINC		0xea
#define SPL_OP_PREDEC		0xeb

#define SPL_OP_TOINT		0xec
#define SPL_OP_TOFLOAT		0xed

// 2 free opcodes

#define SPL_OP_NOP		0xf0
#define SPL_OP_DELETE		0xf1
#define SPL_OP_RLRET		0xf2
#define SPL_OP_CHECKP		0xf3
#define SPL_OP_LOAD		0xf4
#define SPL_OP_XCHG		0xf5
#define SPL_OP_EVAL		0xf6
#define SPL_OP_LXCHG		0xf7

#define SPL_OP_DEBUG		0xf8
#define SPL_OP_WARNING		0xf9
#define SPL_OP_ERROR		0xfa

// 1 free opcode

#define SPL_OP_SIG		0xfc

// 3 free opcodes

#define SPL_OP_HALT		0xff		// ENDBRANCH

#ifdef __cplusplus
}
#endif

#endif

