#ifndef	USL_H
#define	USL_H

#include "estring.h"

/*
 * This is a realization of USL ver. 0.02.
 * USL currently stands for Ugly Scripting Language.
 */

/*
 * USL supports three scalar types: 'real' (vec_t), 'int' (C int) and 'string'.
 * For real and int, one- and two-dimensional arrays is also supported.
 * Access to arrays implemented as unary and binary operations; e.g., for
 *		real arr[10][20];
 * access (or assignment) to a[i][j] has to be written in RPN notation as
 *		(i,j,a).
 * It also important to realize that there are _no_ implicit type conversions;
 * they must be explicitly coded in expressions. For example, to compute
 * the sum Pi + i (assuming 'i' declared as integer), it is neccessary to write
 * (Pi,i,real,+) (the expression (Pi,int,i,+) evaluates to 'int' value 3+i).
 */

/* -------------------------------------------------------------------- *\
                             Built-in types
\* -------------------------------------------------------------------- */

#define	USL_INT			int
#define	USL_REAL		vec_t
#define	USL_STRING		estr_p

#define	TYPEID_NULL		0 /* _must_ be zero */
#define	TYPEID_INT		1
#define	TYPEID_REAL		2
#define	TYPEID_STRING	3

#define	MAX_TYPES		4

/* -------------------------------------------------------------------- *\
                           Evaluation context
\* -------------------------------------------------------------------- */

typedef struct etree_context_s
{
	/*
	 * Memory pools for variables and arrays. The 1st element of each
	 * pool reserved for exit code.
	 * Note: 'STRING_EXIT' is valid only after TYPEID_STRING operation,
	 * and should be cleared properly (either in string_to_scalar
	 * operations, or after the last usage of the evaluation result).
	 */
	void_p		pools[MAX_TYPES];
	/* == true if conversion error occurs in last expression / operator */
	vboolean	conversion_error;
}	etree_context_t, *etree_context_p;

#define	EVAL_CONTEXT_DEFAULT_STATE(ctx) \
	(ctx)->conversion_error = false;

#define	INT_POOL(ctx)		((USL_INT*)((ctx)->pools[TYPEID_INT]))
#define	REAL_POOL(ctx)		((USL_REAL*)((ctx)->pools[TYPEID_REAL]))
#define	STRING_POOL(ctx)	((USL_STRING*)((ctx)->pools[TYPEID_STRING]))

#define	INT_EXIT(ctx)		(*INT_POOL(ctx))
#define	REAL_EXIT(ctx)		(*REAL_POOL(ctx))
#define	STRING_EXIT(ctx)	(*STRING_POOL(ctx))

/* -------------------------------------------------------------------- *\
                        Node of the evaluation tree
\* -------------------------------------------------------------------- */

struct etree_node_s;

typedef void (V_CALL *etree_op_t)(struct etree_node_s *self,etree_context_p ctx);
typedef void (V_CALL *etree_done_t)(struct etree_node_s *self);

#define	USL_MAX_CONSTANT	8

typedef struct etree_node_s
{
	u32_t		typeid;
	u32_t		dimension;
	u32_t		dim1, dim2;
	/* reference to identifier; always NULL for constants and operations */
	struct etree_operand_s *var_ptr;
	/*
	 * For constants, the value stored directly in node.
	 */
	union
	{
		USL_REAL	real_const;
		USL_INT		int_const;
		USL_STRING	string_const;
		void_p		base_const;
		u8_t		const_data[USL_MAX_CONSTANT];
	}	constant;
	/*
	 * Relocated position of operand in one of the context's pools
	 */
	void			*base;
	/*
	 * Flag to indicate that this node requires relocation.
	 */
	vboolean		relocated;
	/*
	 * Operation
	 */
	etree_op_t	op_ptr;
	/*
	 * Children
	 */
	struct      etree_node_s *left, *right;
}   etree_node_t, *etree_node_p;

#define	ETREE_CONST(node)		(!(node)->left && !(node)->var_ptr)

#define	NODAL_INT(node)			((USL_INT*)((node)->base))
#define	NODAL_REAL(node)		((USL_REAL*)((node)->base))
#define	NODAL_STRING(node)		((USL_STRING*)((node)->base))

#define ET_EVAL(node,ctx)  		((node)->op_ptr(node,ctx))

/* -------------------------------------------------------------------- *\
                        Description of the type
\* -------------------------------------------------------------------- */

/*
 * Access operations have to copy contents of the _node_ to the
 * first elements of ctx->pools[<typeid>]. Assignment operations
 * have to do the reverse.
 *
 * The 'destruct' routine have to clear the node (but must _not_
 * memFree() it).
 */

typedef struct typeinfo_s
{
	u32_t	typeid;		/* unsigned integer constant */
	u32_t	size_of;	/* size in bytes */
	struct
	{
		etree_done_t	destruct;
		/* access of constant of given type */
		etree_op_t		op_const;
		/* access of variables, 1D and 2D array elements */
		etree_op_t		op_access_scalar, op_access_1d, op_access_2d;
		/* assignment to variables, 1D and 2D array elements */
		etree_op_t		op_assign_scalar, op_assign_1d, op_assign_2d;
	} specific;
	char	*type_name;	/* keyword: 'int', 'real', etc. */
}	typeinfo_t, *typeinfo_p;

/*
 * Full descriprion of operation
 */
typedef struct nodal_operation_s
{
	char		*op_name;
	etree_op_t	op_func;
	u32_t		typeid_self, typeid_left, typeid_right;
	char		*op_desc;
}	nodal_operation_t, *nodal_operation_p;

#endif	/* USL_H */