10197 lines
		
	
	
		
			261 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			10197 lines
		
	
	
		
			261 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
    Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
						|
 | 
						|
    Redistribution and use in source and binary forms, with or without
 | 
						|
    modification, are permitted provided that the following conditions
 | 
						|
    are met:
 | 
						|
    1. Redistributions of source code must retain the above copyright
 | 
						|
       notice, this list of conditions and the following disclaimer.
 | 
						|
    2. Redistributions in binary form must reproduce the above copyright
 | 
						|
       notice, this list of conditions and the following disclaimer in the
 | 
						|
       documentation and/or other materials provided with the distribution.
 | 
						|
 | 
						|
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | 
						|
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
						|
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
						|
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
						|
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
						|
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
						|
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
						|
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
						|
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
						|
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
#include "hawk-prv.h"
 | 
						|
 | 
						|
#define PRINT_IOERR -99
 | 
						|
 | 
						|
#define CMP_ERROR -99
 | 
						|
#define DEF_BUF_CAPA 256
 | 
						|
#define HAWK_RTX_STACK_INCREMENT 512
 | 
						|
 | 
						|
enum exit_level_t
 | 
						|
{
 | 
						|
	EXIT_NONE,
 | 
						|
	EXIT_BREAK,
 | 
						|
	EXIT_CONTINUE,
 | 
						|
	EXIT_FUNCTION,
 | 
						|
	EXIT_NEXT,
 | 
						|
	EXIT_GLOBAL,
 | 
						|
	EXIT_ABORT
 | 
						|
};
 | 
						|
 | 
						|
struct pafv_t
 | 
						|
{
 | 
						|
	hawk_val_t**       args;
 | 
						|
	hawk_oow_t         nargs;
 | 
						|
	const hawk_ooch_t* argspec;
 | 
						|
	hawk_oow_t         argspeclen;
 | 
						|
};
 | 
						|
 | 
						|
#define DEFAULT_CONVFMT  HAWK_T("%.6g")
 | 
						|
#define DEFAULT_OFMT     HAWK_T("%.6g")
 | 
						|
#define DEFAULT_FS       HAWK_T(" ")
 | 
						|
#define DEFAULT_OFS      HAWK_T(" ")
 | 
						|
#define DEFAULT_ORS      HAWK_T("\n")
 | 
						|
#define DEFAULT_ORS_CRLF HAWK_T("\r\n")
 | 
						|
#define DEFAULT_SUBSEP   HAWK_T("\034")
 | 
						|
 | 
						|
/* the index of a positional variable should be a positive interger
 | 
						|
 * equal to or less than the maximum value of the type by which
 | 
						|
 * the index is represented. but it has an extra check against the
 | 
						|
 * maximum value of hawk_oow_t as the reference is represented
 | 
						|
 * in a pointer variable of hawk_val_ref_t and sizeof(void*) is
 | 
						|
 * equal to sizeof(hawk_oow_t). */
 | 
						|
#define IS_VALID_POSIDX(idx) \
 | 
						|
	((idx) >= 0 && \
 | 
						|
	 (idx) <= HAWK_TYPE_MAX(hawk_int_t) && \
 | 
						|
	 (idx) <= HAWK_TYPE_MAX(hawk_oow_t))
 | 
						|
 | 
						|
#define CLRERR(rtx) hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_ENOERR)
 | 
						|
#define ADJERR_LOC(rtx,l) do { (rtx)->_gem.errloc = *(l); } while (0)
 | 
						|
 | 
						|
static hawk_oow_t push_arg_from_vals (hawk_rtx_t* rtx, hawk_nde_fncall_t* call, void* data);
 | 
						|
static hawk_oow_t push_arg_from_nde (hawk_rtx_t* rtx, hawk_nde_fncall_t* call, void* data);
 | 
						|
 | 
						|
static int init_rtx (hawk_rtx_t* rtx, hawk_t* hawk, hawk_rio_cbs_t* rio);
 | 
						|
static void fini_rtx (hawk_rtx_t* rtx, int fini_globals);
 | 
						|
 | 
						|
static int init_globals (hawk_rtx_t* rtx);
 | 
						|
static void refdown_globals (hawk_rtx_t* rtx, int pop);
 | 
						|
 | 
						|
static int run_pblocks (hawk_rtx_t* rtx);
 | 
						|
static int run_pblock_chain (hawk_rtx_t* rtx, hawk_chain_t* cha);
 | 
						|
static int run_pblock (hawk_rtx_t* rtx, hawk_chain_t* cha, hawk_oow_t bno);
 | 
						|
static int run_block (hawk_rtx_t* rtx, hawk_nde_blk_t* nde);
 | 
						|
static int run_statement (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static int run_if (hawk_rtx_t* rtx, hawk_nde_if_t* nde);
 | 
						|
static int run_switch (hawk_rtx_t* rtx, hawk_nde_switch_t* nde);
 | 
						|
static int run_while (hawk_rtx_t* rtx, hawk_nde_while_t* nde);
 | 
						|
static int run_for (hawk_rtx_t* rtx, hawk_nde_for_t* nde);
 | 
						|
static int run_forin (hawk_rtx_t* rtx, hawk_nde_forin_t* nde);
 | 
						|
static int run_break (hawk_rtx_t* rtx, hawk_nde_break_t* nde);
 | 
						|
static int run_continue (hawk_rtx_t* rtx, hawk_nde_continue_t* nde);
 | 
						|
static int run_return (hawk_rtx_t* rtx, hawk_nde_return_t* nde);
 | 
						|
static int run_exit (hawk_rtx_t* rtx, hawk_nde_exit_t* nde);
 | 
						|
static int run_next (hawk_rtx_t* rtx, hawk_nde_next_t* nde);
 | 
						|
static int run_nextfile (hawk_rtx_t* rtx, hawk_nde_nextfile_t* nde);
 | 
						|
static int run_delete (hawk_rtx_t* rtx, hawk_nde_delete_t* nde);
 | 
						|
static int run_reset (hawk_rtx_t* rtx, hawk_nde_reset_t* nde);
 | 
						|
static int run_print (hawk_rtx_t* rtx, hawk_nde_print_t* nde);
 | 
						|
static int run_printf (hawk_rtx_t* rtx, hawk_nde_print_t* nde);
 | 
						|
 | 
						|
static int output_formatted (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_ooch_t* dst, const hawk_ooch_t* fmt, hawk_oow_t fmt_len, hawk_nde_t* args);
 | 
						|
static int output_formatted_bytes (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_ooch_t* dst, const hawk_bch_t* fmt, hawk_oow_t fmt_len, hawk_nde_t* args);
 | 
						|
 | 
						|
static hawk_val_t* eval_expression (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_expression0 (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
 | 
						|
static hawk_val_t* eval_group (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
 | 
						|
static hawk_val_t* eval_assignment (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* do_assignment (hawk_rtx_t* rtx, hawk_nde_t* var, hawk_val_t* val);
 | 
						|
static hawk_val_t* do_assignment_nonindexed (hawk_rtx_t* rtx, hawk_nde_var_t* var, hawk_val_t* val);
 | 
						|
static hawk_val_t* do_assignment_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var, hawk_val_t* val);
 | 
						|
static hawk_val_t* do_assignment_positional (hawk_rtx_t* rtx, hawk_nde_pos_t* pos, hawk_val_t* val);
 | 
						|
 | 
						|
static hawk_val_t* eval_binary (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_binop_lor (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* right);
 | 
						|
static hawk_val_t* eval_binop_land (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* right);
 | 
						|
static hawk_val_t* eval_binop_in (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* right);
 | 
						|
static hawk_val_t* eval_binop_bor (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_bxor (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_band (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_teq (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_tne (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_eq (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_ne (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_gt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_ge (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_lt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_le (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_lshift (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_rshift (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_plus (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_minus (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_mul (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_div (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_idiv (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_mod (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_exp (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_concat (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
static hawk_val_t* eval_binop_ma (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* right);
 | 
						|
static hawk_val_t* eval_binop_nm (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* right);
 | 
						|
 | 
						|
static hawk_val_t* eval_unary (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_incpre (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_incpst (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_cnd (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
 | 
						|
static hawk_val_t* eval_fncall_fnc (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_fncall_fun (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_fncall_var (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
 | 
						|
static int get_reference (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_val_t*** ref);
 | 
						|
static hawk_val_t** get_reference_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var);
 | 
						|
 | 
						|
static hawk_val_t* eval_char (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_bchr (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_int (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_flt (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_str (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_mbs (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_rex (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_xnil (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_xargc (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_xargv (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_xargvidx (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_fun (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_named (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_gbl (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_lcl (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_arg (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_namedidx (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_gblidx (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_lclidx (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_argidx (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_pos (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_getline (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_print (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
static hawk_val_t* eval_printf (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
 | 
						|
static int read_record (hawk_rtx_t* rtx);
 | 
						|
 | 
						|
static hawk_ooch_t* idxnde_to_str (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_ooch_t* buf, hawk_oow_t* len, hawk_nde_t** remidx, hawk_int_t* firstidxint);
 | 
						|
static hawk_ooi_t idxnde_to_int (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_nde_t** remidx);
 | 
						|
 | 
						|
typedef hawk_val_t* (*binop_func_t) (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right);
 | 
						|
typedef hawk_val_t* (*eval_expr_t) (hawk_rtx_t* rtx, hawk_nde_t* nde);
 | 
						|
 | 
						|
#define POS_VAL(rtx, idx) \
 | 
						|
	(((idx) == 0)? (rtx)->inrec.d0: \
 | 
						|
	 ((idx) > 0 && (idx) <= (hawk_int_t)(rtx)->inrec.nflds)? (rtx)->inrec.flds[(idx) - 1].val: \
 | 
						|
	 hawk_val_zls)
 | 
						|
 | 
						|
HAWK_INLINE hawk_oow_t hawk_rtx_getnargs (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	return (hawk_oow_t)HAWK_RTX_STACK_NARGS(rtx);
 | 
						|
}
 | 
						|
 | 
						|
HAWK_INLINE hawk_val_t* hawk_rtx_getarg (hawk_rtx_t* rtx, hawk_oow_t idx)
 | 
						|
{
 | 
						|
	return HAWK_RTX_STACK_ARG(rtx, idx);
 | 
						|
}
 | 
						|
 | 
						|
HAWK_INLINE hawk_val_t* hawk_rtx_getgbl (hawk_rtx_t* rtx, int id)
 | 
						|
{
 | 
						|
	HAWK_ASSERT(id >= 0 && id < (int)HAWK_ARR_SIZE(rtx->hawk->parse.gbls));
 | 
						|
	return HAWK_RTX_STACK_GBL(rtx, id);
 | 
						|
}
 | 
						|
 | 
						|
const hawk_oocs_t* hawk_rtx_getsubsep (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	return &rtx->gbl.subsep;
 | 
						|
}
 | 
						|
 | 
						|
/* internal function to set a value to a global variable.
 | 
						|
 * this function can handle a few special global variables that
 | 
						|
 * require special treatment. */
 | 
						|
static int set_global (hawk_rtx_t* rtx, int idx, hawk_nde_var_t* var, hawk_val_t* val, int assign)
 | 
						|
{
 | 
						|
	hawk_val_t* old;
 | 
						|
	hawk_rtx_ecb_t* ecb, * ecb_next;
 | 
						|
	hawk_val_type_t vtype, old_vtype;
 | 
						|
 | 
						|
	old = HAWK_RTX_STACK_GBL(rtx, idx);
 | 
						|
 | 
						|
	vtype = HAWK_RTX_GETVALTYPE(rtx, val);
 | 
						|
	old_vtype = HAWK_RTX_GETVALTYPE(rtx, old);
 | 
						|
 | 
						|
	if (!(rtx->hawk->opt.trait & HAWK_FLEXMAP))
 | 
						|
	{
 | 
						|
		hawk_errnum_t errnum = HAWK_ENOERR;
 | 
						|
		const hawk_ooch_t* errfmt;
 | 
						|
 | 
						|
		if (vtype == HAWK_VAL_MAP || vtype == HAWK_VAL_ARR)
 | 
						|
		{
 | 
						|
			if (old_vtype == HAWK_VAL_NIL)
 | 
						|
			{
 | 
						|
				/* a nil valul can be overridden with any values */
 | 
						|
				/* ok. no error */
 | 
						|
			}
 | 
						|
			else if (!assign && old_vtype == vtype)
 | 
						|
			{
 | 
						|
				/* when both are maps, how should this operation be
 | 
						|
				 * interpreted?
 | 
						|
				 *
 | 
						|
				 * is it an assignment?
 | 
						|
				 *    old = new
 | 
						|
				 *
 | 
						|
				 * or is it to delete all elements in the array
 | 
						|
				 * and add new items?
 | 
						|
				 *    for (i in old) delete old[i];
 | 
						|
				 *    for (i in new) old[i] = new[i];
 | 
						|
				 *
 | 
						|
				 * i interpret this operation as the latter.
 | 
						|
				 */
 | 
						|
 | 
						|
				/* ok. no error */
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				errnum = HAWK_ESCALARTONONSCA;
 | 
						|
				errfmt = HAWK_T("not allowed to change a scalar value in '%.*js' to a nonscalar value");
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (old_vtype == HAWK_VAL_MAP || old_vtype == HAWK_VAL_ARR)
 | 
						|
			{
 | 
						|
				errnum = HAWK_ENONSCATOSCALAR;
 | 
						|
				errfmt = HAWK_T("not allowed to change a nonscalar value in '%.*js' to a scalar value");
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (errnum != HAWK_ENOERR)
 | 
						|
		{
 | 
						|
			/* once a variable becomes a map, it cannot be assigned
 | 
						|
			 * others value than another map. you can only add a member
 | 
						|
			 * using indexing. */
 | 
						|
			if (var)
 | 
						|
			{
 | 
						|
				/* global variable */
 | 
						|
				hawk_rtx_seterrfmt(rtx, &var->loc, errnum, errfmt, var->id.name.len, var->id.name.ptr);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				/* hawk_rtx_setgbl() has been called */
 | 
						|
				hawk_oocs_t ea;
 | 
						|
				ea.ptr = (hawk_ooch_t*)hawk_getgblname(hawk_rtx_gethawk(rtx), idx, &ea.len);
 | 
						|
				hawk_rtx_seterrfmt(rtx, HAWK_NULL, errnum, errfmt, ea.len, ea.ptr);
 | 
						|
			}
 | 
						|
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (vtype == HAWK_VAL_MAP || vtype == HAWK_VAL_ARR)
 | 
						|
	{
 | 
						|
		if (idx >= HAWK_MIN_GBL_ID && idx <= HAWK_MAX_GBL_ID)
 | 
						|
		{
 | 
						|
			/* short-circuit check block to prevent the basic built-in
 | 
						|
			 * variables from being assigned a map. if you happen to add
 | 
						|
			 * one and if that's allowed to be a map, you may have to
 | 
						|
			 * change the condition here. */
 | 
						|
 | 
						|
/* TODO: use global variable attribute. can it be a map? can it be a scalar? is it read-only???? */
 | 
						|
 | 
						|
			hawk_oocs_t ea;
 | 
						|
			ea.ptr = (hawk_ooch_t*)hawk_getgblname(hawk_rtx_gethawk(rtx), idx, &ea.len);
 | 
						|
			hawk_rtx_seterrfmt(rtx, HAWK_NULL, HAWK_ESCALARTONONSCA, HAWK_T("not allowed to change a scalar value in '%.*js' to a nonscalar value"), ea.len, ea.ptr);
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (old == val && idx != HAWK_GBL_NF) /* read the comment in the case block for HAWK_GBL_NF below */
 | 
						|
	{
 | 
						|
		/* if the old value is the same as the new value, don't take any actions.
 | 
						|
		 * note that several inspections have been performed before this check,
 | 
						|
		 * mainly for consistency. anyway, this condition can be met if you execute
 | 
						|
		 * a statement like 'ARGV=ARGV'. */
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* perform actual assignment or assignment-like operation */
 | 
						|
	switch (idx)
 | 
						|
	{
 | 
						|
		case HAWK_GBL_CONVFMT:
 | 
						|
		{
 | 
						|
			hawk_oow_t i;
 | 
						|
			hawk_oocs_t str;
 | 
						|
 | 
						|
			str.ptr = hawk_rtx_valtooocstrdup(rtx, val, &str.len);
 | 
						|
			if (HAWK_UNLIKELY(!str.ptr)) return -1;
 | 
						|
 | 
						|
			for (i = 0; i < str.len; i++)
 | 
						|
			{
 | 
						|
				if (str.ptr[i] == '\0')
 | 
						|
				{
 | 
						|
					/* '\0' is included in the value */
 | 
						|
					hawk_rtx_freemem(rtx, str.ptr);
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_ECONVFMTCHR);
 | 
						|
					return -1;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (rtx->gbl.convfmt.ptr) hawk_rtx_freemem(rtx, rtx->gbl.convfmt.ptr);
 | 
						|
			rtx->gbl.convfmt.ptr = str.ptr;
 | 
						|
			rtx->gbl.convfmt.len = str.len;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_GBL_FNR:
 | 
						|
		{
 | 
						|
			int n;
 | 
						|
			hawk_int_t lv;
 | 
						|
 | 
						|
			n = hawk_rtx_valtoint(rtx, val, &lv);
 | 
						|
			if (HAWK_UNLIKELY(n <= -1)) return -1;
 | 
						|
 | 
						|
			rtx->gbl.fnr = lv;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_GBL_FS:
 | 
						|
		{
 | 
						|
			hawk_ooch_t* fs_ptr;
 | 
						|
			hawk_oow_t fs_len;
 | 
						|
 | 
						|
			/* due to the expression evaluation rule, the
 | 
						|
			 * regular expression can not be an assigned value */
 | 
						|
			HAWK_ASSERT(vtype != HAWK_VAL_REX);
 | 
						|
 | 
						|
			fs_ptr = hawk_rtx_getvaloocstr(rtx, val, &fs_len);
 | 
						|
			if (HAWK_UNLIKELY(!fs_ptr)) return -1;
 | 
						|
 | 
						|
			if (fs_len > 1 && !(fs_len == 5 && fs_ptr[0] == '?'))
 | 
						|
			{
 | 
						|
				/* it's a regular expression if FS contains multiple characters.
 | 
						|
				 * however, it's not a regular expression if it's 5 character
 | 
						|
				 * string beginning with a question mark. */
 | 
						|
				hawk_tre_t* rex, * irex;
 | 
						|
 | 
						|
				if (hawk_rtx_buildrex(rtx, fs_ptr, fs_len, &rex, &irex) <= -1)
 | 
						|
				{
 | 
						|
					hawk_rtx_freevaloocstr(rtx, val, fs_ptr);
 | 
						|
					return -1;
 | 
						|
				}
 | 
						|
 | 
						|
				if (rtx->gbl.fs[0]) hawk_rtx_freerex(rtx, rtx->gbl.fs[0], rtx->gbl.fs[1]);
 | 
						|
 | 
						|
				rtx->gbl.fs[0] = rex;
 | 
						|
				rtx->gbl.fs[1] = irex;
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_freevaloocstr(rtx, val, fs_ptr);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_GBL_IGNORECASE:
 | 
						|
		{
 | 
						|
			hawk_int_t l;
 | 
						|
			hawk_flt_t r;
 | 
						|
			int vt;
 | 
						|
 | 
						|
			vt = hawk_rtx_valtonum(rtx, val, &l, &r);
 | 
						|
			if (vt <= -1) return -1;
 | 
						|
 | 
						|
			if (vt == 0)
 | 
						|
				rtx->gbl.ignorecase = ((l > 0)? 1: (l < 0)? -1: 0);
 | 
						|
			else
 | 
						|
				rtx->gbl.ignorecase = ((r > 0.0)? 1: (r < 0.0)? -1: 0);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_GBL_NF:
 | 
						|
		{
 | 
						|
			int n;
 | 
						|
			hawk_int_t lv;
 | 
						|
 | 
						|
			n = hawk_rtx_valtoint(rtx, val, &lv);
 | 
						|
			if (n <= -1) return -1;
 | 
						|
 | 
						|
			if (lv < 0)
 | 
						|
			{
 | 
						|
				hawk_rtx_seterrfmt(rtx, HAWK_NULL, HAWK_EINVAL, HAWK_T("negative value into NF"));
 | 
						|
				return -1;
 | 
						|
			}
 | 
						|
 | 
						|
			if (lv < (hawk_int_t)rtx->inrec.nflds || (assign && lv == (hawk_int_t)rtx->inrec.nflds))
 | 
						|
			{
 | 
						|
				/* when NF is assigned a value, it should rebuild $X values.
 | 
						|
				 * even when there is no change in the value like NF = NF,
 | 
						|
				 * it has to rebuil $X values with the current OFS value.
 | 
						|
				 *  { OFS=":"; NF=NF; print $0; }
 | 
						|
				 * the NF=value assignment is indicated by a non-zero value in the 'assign' variable.
 | 
						|
				 * 'assign' is 0 if this function is called from a different context such as
 | 
						|
				 * explicit call to hawk_rtx_setgbl().
 | 
						|
				 */
 | 
						|
 | 
						|
				if (hawk_rtx_truncrec(rtx, (hawk_oow_t)lv) <= -1)
 | 
						|
				{
 | 
						|
					/* adjust the error line */
 | 
						|
					/*if (var) ADJERR_LOC(rtx, &var->loc);*/
 | 
						|
					return -1;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else if (lv > (hawk_int_t)rtx->inrec.nflds)
 | 
						|
			{
 | 
						|
				hawk_oocs_t cs;
 | 
						|
				cs.ptr = HAWK_T("");
 | 
						|
				cs.len = 0;
 | 
						|
				if (hawk_rtx_setrec(rtx, lv, &cs, 0) <= -1) return -1;
 | 
						|
			}
 | 
						|
 | 
						|
			/* for all other globals, it returns before this switch/case block is reached
 | 
						|
			 * if the same value is assigned. but NF change requires extra action to take
 | 
						|
			 * as coded before this switch/case block. */
 | 
						|
			if (old == val) return 0;
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		case HAWK_GBL_NR:
 | 
						|
		{
 | 
						|
			int n;
 | 
						|
			hawk_int_t lv;
 | 
						|
 | 
						|
			n = hawk_rtx_valtoint(rtx, val, &lv);
 | 
						|
			if (n <= -1) return -1;
 | 
						|
 | 
						|
			rtx->gbl.nr = lv;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_GBL_NUMSTRDETECT:
 | 
						|
		{
 | 
						|
			hawk_int_t l;
 | 
						|
			hawk_flt_t r;
 | 
						|
			int vt;
 | 
						|
 | 
						|
			vt = hawk_rtx_valtonum(rtx, val, &l, &r);
 | 
						|
			if (vt <= -1) return -1;
 | 
						|
 | 
						|
			if (vt == 0)
 | 
						|
				rtx->gbl.numstrdetect = ((l > 0)? 1: (l < 0)? -1: 0);
 | 
						|
			else
 | 
						|
				rtx->gbl.numstrdetect = ((r > 0.0)? 1: (r < 0.0)? -1: 0);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_GBL_OFMT:
 | 
						|
		{
 | 
						|
			hawk_oow_t i;
 | 
						|
			hawk_oocs_t str;
 | 
						|
 | 
						|
			str.ptr = hawk_rtx_valtooocstrdup(rtx, val, &str.len);
 | 
						|
			if (HAWK_UNLIKELY(!str.ptr)) return -1;
 | 
						|
 | 
						|
			for (i = 0; i < str.len; i++)
 | 
						|
			{
 | 
						|
				if (str.ptr[i] == '\0')
 | 
						|
				{
 | 
						|
					/* '\0' is included in the value */
 | 
						|
					hawk_rtx_freemem(rtx, str.ptr);
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_ECONVFMTCHR);
 | 
						|
					return -1;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (rtx->gbl.ofmt.ptr) hawk_rtx_freemem(rtx, rtx->gbl.ofmt.ptr);
 | 
						|
			rtx->gbl.ofmt.ptr = str.ptr;
 | 
						|
			rtx->gbl.ofmt.len = str.len;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_GBL_OFS:
 | 
						|
		{
 | 
						|
			hawk_oocs_t str;
 | 
						|
 | 
						|
			str.ptr = hawk_rtx_valtooocstrdup(rtx, val, &str.len);
 | 
						|
			if (HAWK_UNLIKELY(!str.ptr)) return -1;
 | 
						|
 | 
						|
			if (rtx->gbl.ofs.ptr) hawk_rtx_freemem(rtx, rtx->gbl.ofs.ptr);
 | 
						|
			rtx->gbl.ofs.ptr = str.ptr;
 | 
						|
			rtx->gbl.ofs.len = str.len;
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_GBL_ORS:
 | 
						|
		{
 | 
						|
			hawk_oocs_t str;
 | 
						|
 | 
						|
			str.ptr = hawk_rtx_valtooocstrdup(rtx, val, &str.len);
 | 
						|
			if (HAWK_UNLIKELY(!str.ptr)) return -1;
 | 
						|
 | 
						|
			if (rtx->gbl.ors.ptr) hawk_rtx_freemem(rtx, rtx->gbl.ors.ptr);
 | 
						|
			rtx->gbl.ors.ptr = str.ptr;
 | 
						|
			rtx->gbl.ors.len = str.len;
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_GBL_RS:
 | 
						|
		{
 | 
						|
			hawk_oocs_t rss;
 | 
						|
 | 
						|
			/* due to the expression evaluation rule, the
 | 
						|
			 * regular expression can not be an assigned
 | 
						|
			 * value */
 | 
						|
			HAWK_ASSERT(vtype != HAWK_VAL_REX);
 | 
						|
 | 
						|
			rss.ptr = hawk_rtx_getvaloocstr(rtx, val, &rss.len);
 | 
						|
			if (!rss.ptr) return -1;
 | 
						|
 | 
						|
			if (rtx->gbl.rs[0])
 | 
						|
			{
 | 
						|
				hawk_rtx_freerex(rtx, rtx->gbl.rs[0], rtx->gbl.rs[1]);
 | 
						|
				rtx->gbl.rs[0] = HAWK_NULL;
 | 
						|
				rtx->gbl.rs[1] = HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			if (rss.len > 1)
 | 
						|
			{
 | 
						|
				hawk_tre_t* rex, * irex;
 | 
						|
 | 
						|
				/* compile the regular expression */
 | 
						|
				if (hawk_rtx_buildrex(rtx, rss.ptr, rss.len, &rex, &irex) <= -1)
 | 
						|
				{
 | 
						|
					hawk_rtx_freevaloocstr(rtx, val, rss.ptr);
 | 
						|
					return -1;
 | 
						|
				}
 | 
						|
 | 
						|
				rtx->gbl.rs[0] = rex;
 | 
						|
				rtx->gbl.rs[1] = irex;
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_freevaloocstr(rtx, val, rss.ptr);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_GBL_STRIPRECSPC:
 | 
						|
		{
 | 
						|
			hawk_int_t l;
 | 
						|
			hawk_flt_t r;
 | 
						|
			int vt;
 | 
						|
 | 
						|
			vt = hawk_rtx_valtonum(rtx, val, &l, &r);
 | 
						|
			if (vt <= -1) return -1;
 | 
						|
 | 
						|
			if (vt == 0)
 | 
						|
				rtx->gbl.striprecspc = ((l > 0)? 1: (l < 0)? -1: 0);
 | 
						|
			else
 | 
						|
				rtx->gbl.striprecspc = ((r > 0.0)? 1: (r < 0.0)? -1: 0);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_GBL_STRIPSTRSPC:
 | 
						|
		{
 | 
						|
			hawk_int_t l;
 | 
						|
			hawk_flt_t r;
 | 
						|
			int vt;
 | 
						|
 | 
						|
			vt = hawk_rtx_valtonum(rtx, val, &l, &r);
 | 
						|
			if (vt <= -1) return -1;
 | 
						|
 | 
						|
			if (vt == 0)
 | 
						|
				rtx->gbl.stripstrspc = ((l > 0)? 1: (l < 0)? -1: 0);
 | 
						|
			else
 | 
						|
				rtx->gbl.stripstrspc = ((r > 0.0)? 1: (r < 0.0)? -1: 0);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_GBL_SUBSEP:
 | 
						|
		{
 | 
						|
			hawk_oocs_t str;
 | 
						|
 | 
						|
			str.ptr = hawk_rtx_valtooocstrdup(rtx, val, &str.len);
 | 
						|
			if (HAWK_UNLIKELY(!str.ptr)) return -1;
 | 
						|
 | 
						|
			if (rtx->gbl.subsep.ptr) hawk_rtx_freemem(rtx, rtx->gbl.subsep.ptr);
 | 
						|
			rtx->gbl.subsep.ptr = str.ptr;
 | 
						|
			rtx->gbl.subsep.len = str.len;
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	hawk_rtx_refdownval(rtx, old);
 | 
						|
	HAWK_RTX_STACK_GBL(rtx,idx) = val;
 | 
						|
	hawk_rtx_refupval(rtx, val);
 | 
						|
 | 
						|
	for (ecb = rtx->ecb; ecb != (hawk_rtx_ecb_t*)rtx; ecb = ecb_next)
 | 
						|
	{
 | 
						|
		ecb_next = ecb->next;
 | 
						|
		if (ecb->gblset) ecb->gblset(rtx, idx, val, ecb->ctx);
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
HAWK_INLINE void hawk_rtx_setretval (hawk_rtx_t* rtx, hawk_val_t* val)
 | 
						|
{
 | 
						|
	hawk_rtx_refdownval(rtx, HAWK_RTX_STACK_RETVAL(rtx));
 | 
						|
	HAWK_RTX_STACK_RETVAL(rtx) = val;
 | 
						|
	/* should use the same trick as run_return */
 | 
						|
	hawk_rtx_refupval(rtx, val);
 | 
						|
}
 | 
						|
 | 
						|
HAWK_INLINE int hawk_rtx_setgbl (hawk_rtx_t* rtx, int id, hawk_val_t* val)
 | 
						|
{
 | 
						|
	HAWK_ASSERT(id >= 0 && id < (int)HAWK_ARR_SIZE(rtx->hawk->parse.gbls));
 | 
						|
	return set_global(rtx, id, HAWK_NULL, val, 0);
 | 
						|
}
 | 
						|
 | 
						|
int hawk_rtx_setgbltostrbyname (hawk_rtx_t* rtx, const hawk_ooch_t* name, const hawk_ooch_t* val)
 | 
						|
{
 | 
						|
	int id, n;
 | 
						|
	hawk_val_t* v;
 | 
						|
 | 
						|
	HAWK_ASSERT(hawk_isvalidident(hawk_rtx_gethawk(rtx), name));
 | 
						|
 | 
						|
	id = hawk_findgblwithoocstr(hawk_rtx_gethawk(rtx), name, 1);
 | 
						|
	v = hawk_rtx_makestrvalwithoocstr(rtx, val);
 | 
						|
	if (!v) return -1;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, v);
 | 
						|
	if (id <= -1)
 | 
						|
	{
 | 
						|
		/* not found. it's not a builtin/declared global variable */
 | 
						|
		hawk_nde_var_t var;
 | 
						|
 | 
						|
		/* make a fake variable node for assignment and use it */
 | 
						|
		HAWK_MEMSET (&var, 0, HAWK_SIZEOF(var));
 | 
						|
		var.type = HAWK_NDE_NAMED;
 | 
						|
		var.id.name.ptr = (hawk_ooch_t*)name;
 | 
						|
		var.id.name.len = hawk_count_oocstr(name);
 | 
						|
		var.id.idxa = (hawk_oow_t)-1;
 | 
						|
		var.idx = HAWK_NULL;
 | 
						|
 | 
						|
		n = do_assignment_nonindexed(rtx, &var, v)? 0: -1;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		n = set_global(rtx, id, HAWK_NULL, v, 0);
 | 
						|
	}
 | 
						|
	hawk_rtx_refdownval(rtx, v);
 | 
						|
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
int hawk_rtx_setscriptnamewithuchars (hawk_rtx_t* rtx, const hawk_uch_t* name, hawk_oow_t len)
 | 
						|
{
 | 
						|
	hawk_val_t* tmp;
 | 
						|
	int n;
 | 
						|
 | 
						|
	tmp = hawk_rtx_makestrvalwithuchars(rtx, name, len);
 | 
						|
	if (tmp == HAWK_NULL) return -1;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, tmp);
 | 
						|
	n = hawk_rtx_setgbl(rtx, HAWK_GBL_SCRIPTNAME, tmp);
 | 
						|
	hawk_rtx_refdownval(rtx, tmp);
 | 
						|
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
int hawk_rtx_setscriptnamewithbchars (hawk_rtx_t* rtx, const hawk_bch_t* name, hawk_oow_t len)
 | 
						|
{
 | 
						|
	hawk_val_t* tmp;
 | 
						|
	int n;
 | 
						|
 | 
						|
	tmp = hawk_rtx_makestrvalwithbchars(rtx, name, len);
 | 
						|
	if (tmp == HAWK_NULL) return -1;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, tmp);
 | 
						|
	n = hawk_rtx_setgbl(rtx, HAWK_GBL_SCRIPTNAME, tmp);
 | 
						|
	hawk_rtx_refdownval(rtx, tmp);
 | 
						|
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
int hawk_rtx_setfilenamewithuchars (hawk_rtx_t* rtx, const hawk_uch_t* name, hawk_oow_t len)
 | 
						|
{
 | 
						|
	hawk_val_t* tmp;
 | 
						|
	int n;
 | 
						|
 | 
						|
	tmp = hawk_rtx_makestrvalwithuchars(rtx, name, len);
 | 
						|
	if (HAWK_UNLIKELY(!tmp)) return -1;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, tmp);
 | 
						|
	n = hawk_rtx_setgbl(rtx, HAWK_GBL_FILENAME, tmp);
 | 
						|
	hawk_rtx_refdownval(rtx, tmp);
 | 
						|
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
int hawk_rtx_setfilenamewithbchars (hawk_rtx_t* rtx, const hawk_bch_t* name, hawk_oow_t len)
 | 
						|
{
 | 
						|
	hawk_val_t* tmp;
 | 
						|
	int n;
 | 
						|
 | 
						|
	tmp = hawk_rtx_makestrvalwithbchars(rtx, name, len);
 | 
						|
	if (HAWK_UNLIKELY(!tmp)) return -1;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, tmp);
 | 
						|
	n = hawk_rtx_setgbl(rtx, HAWK_GBL_FILENAME, tmp);
 | 
						|
	hawk_rtx_refdownval(rtx, tmp);
 | 
						|
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int hawk_rtx_setofilenamewithuchars (hawk_rtx_t* rtx, const hawk_uch_t* name, hawk_oow_t len)
 | 
						|
{
 | 
						|
	hawk_val_t* tmp;
 | 
						|
	int n;
 | 
						|
 | 
						|
	if (rtx->hawk->opt.trait & HAWK_NEXTOFILE)
 | 
						|
	{
 | 
						|
		tmp = hawk_rtx_makestrvalwithuchars(rtx, name, len);
 | 
						|
		if (HAWK_UNLIKELY(!tmp)) return -1;
 | 
						|
 | 
						|
		hawk_rtx_refupval(rtx, tmp);
 | 
						|
		n = hawk_rtx_setgbl(rtx, HAWK_GBL_OFILENAME, tmp);
 | 
						|
		hawk_rtx_refdownval(rtx, tmp);
 | 
						|
	}
 | 
						|
	else n = 0;
 | 
						|
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
int hawk_rtx_setofilenamewithbchars (hawk_rtx_t* rtx, const hawk_bch_t* name, hawk_oow_t len)
 | 
						|
{
 | 
						|
	hawk_val_t* tmp;
 | 
						|
	int n;
 | 
						|
 | 
						|
	if (rtx->hawk->opt.trait & HAWK_NEXTOFILE)
 | 
						|
	{
 | 
						|
		tmp = hawk_rtx_makestrvalwithbchars(rtx, name, len);
 | 
						|
		if (HAWK_UNLIKELY(!tmp)) return -1;
 | 
						|
 | 
						|
		hawk_rtx_refupval(rtx, tmp);
 | 
						|
		n = hawk_rtx_setgbl(rtx, HAWK_GBL_OFILENAME, tmp);
 | 
						|
		hawk_rtx_refdownval(rtx, tmp);
 | 
						|
	}
 | 
						|
	else n = 0;
 | 
						|
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
hawk_htb_t* hawk_rtx_getnvmap (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	return rtx->named;
 | 
						|
}
 | 
						|
 | 
						|
struct module_init_ctx_t
 | 
						|
{
 | 
						|
	hawk_oow_t count;
 | 
						|
	hawk_rtx_t* rtx;
 | 
						|
};
 | 
						|
 | 
						|
struct module_fini_ctx_t
 | 
						|
{
 | 
						|
	hawk_oow_t limit;
 | 
						|
	hawk_oow_t count;
 | 
						|
	hawk_rtx_t* rtx;
 | 
						|
};
 | 
						|
 | 
						|
static hawk_rbt_walk_t init_module (hawk_rbt_t* rbt, hawk_rbt_pair_t* pair, void* ctx)
 | 
						|
{
 | 
						|
	hawk_mod_data_t* md;
 | 
						|
	struct module_init_ctx_t* mic;
 | 
						|
 | 
						|
	mic = (struct module_init_ctx_t*)ctx;
 | 
						|
 | 
						|
	md = (hawk_mod_data_t*)HAWK_RBT_VPTR(pair);
 | 
						|
	if (md->mod.init && md->mod.init(&md->mod, mic->rtx) <= -1)
 | 
						|
		return HAWK_RBT_WALK_STOP;
 | 
						|
 | 
						|
	mic->count++;
 | 
						|
	return HAWK_RBT_WALK_FORWARD;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_rbt_walk_t fini_module (hawk_rbt_t* rbt, hawk_rbt_pair_t* pair, void* ctx)
 | 
						|
{
 | 
						|
	hawk_mod_data_t* md;
 | 
						|
	struct module_fini_ctx_t* mfc;
 | 
						|
 | 
						|
	mfc = (struct module_fini_ctx_t*)ctx;
 | 
						|
 | 
						|
	if (mfc->limit > 0 && mfc->count >= mfc->limit)
 | 
						|
		return HAWK_RBT_WALK_STOP;
 | 
						|
 | 
						|
	md = (hawk_mod_data_t*)HAWK_RBT_VPTR(pair);
 | 
						|
	if (md->mod.fini) md->mod.fini(&md->mod, mfc->rtx);
 | 
						|
 | 
						|
	mfc->count++;
 | 
						|
	return HAWK_RBT_WALK_FORWARD;
 | 
						|
}
 | 
						|
 | 
						|
hawk_rtx_t* hawk_rtx_open (hawk_t* hawk, hawk_oow_t xtnsize, hawk_rio_cbs_t* rio)
 | 
						|
{
 | 
						|
	hawk_rtx_t* rtx;
 | 
						|
	struct module_init_ctx_t mic;
 | 
						|
	hawk_oow_t i;
 | 
						|
 | 
						|
	/* clear the hawk error code */
 | 
						|
	hawk_seterrnum(hawk, HAWK_NULL, HAWK_ENOERR);
 | 
						|
 | 
						|
	/* check if the code has ever been parsed */
 | 
						|
	if (hawk->tree.ngbls == 0 &&
 | 
						|
	    hawk->tree.begin == HAWK_NULL &&
 | 
						|
	    hawk->tree.end == HAWK_NULL &&
 | 
						|
	    hawk->tree.chain_size == 0 &&
 | 
						|
	    hawk_htb_getsize(hawk->tree.funs) == 0)
 | 
						|
	{
 | 
						|
		hawk_seterrnum(hawk, HAWK_NULL, HAWK_EPERM);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	/* allocate the storage for the rtx object */
 | 
						|
	rtx = (hawk_rtx_t*)hawk_allocmem(hawk, HAWK_SIZEOF(hawk_rtx_t) + xtnsize);
 | 
						|
	if (HAWK_UNLIKELY(!rtx))
 | 
						|
	{
 | 
						|
		/* if it fails, the failure is reported thru the hawk object */
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	/* initialize the rtx object */
 | 
						|
	HAWK_MEMSET(rtx, 0, HAWK_SIZEOF(hawk_rtx_t) + xtnsize);
 | 
						|
	rtx->_instsize = HAWK_SIZEOF(hawk_rtx_t);
 | 
						|
	if (HAWK_UNLIKELY(init_rtx(rtx, hawk, rio) <= -1))
 | 
						|
	{
 | 
						|
		/* because the error information is in the gem part,
 | 
						|
		 * it should be ok to copy over rtx error to hawk even if
 | 
						|
		 * rtx initialization fails. */
 | 
						|
		hawk_rtx_errortohawk(rtx, hawk);
 | 
						|
		hawk_freemem(hawk, rtx);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	rtx->ecb = (hawk_rtx_ecb_t*)rtx; /* use this as a special sentinel node */
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(init_globals(rtx) <= -1))
 | 
						|
	{
 | 
						|
		hawk_rtx_errortohawk(rtx, hawk);
 | 
						|
		fini_rtx(rtx, 0);
 | 
						|
		hawk_freemem(hawk, rtx);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	mic.count = 0;
 | 
						|
	mic.rtx = rtx;
 | 
						|
	hawk_rbt_walk(rtx->hawk->modtab, init_module, &mic);
 | 
						|
	if (mic.count != HAWK_RBT_SIZE(rtx->hawk->modtab))
 | 
						|
	{
 | 
						|
		if (mic.count > 0)
 | 
						|
		{
 | 
						|
			struct module_fini_ctx_t mfc;
 | 
						|
			mfc.limit = mic.count;
 | 
						|
			mfc.count = 0;
 | 
						|
			hawk_rbt_walk(rtx->hawk->modtab, fini_module, &mfc);
 | 
						|
		}
 | 
						|
 | 
						|
		fini_rtx(rtx, 1);
 | 
						|
		hawk_freemem(hawk, rtx);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	/* chain the ctos slots */
 | 
						|
	rtx->ctos.fi = HAWK_COUNTOF(rtx->ctos.b) - 1;
 | 
						|
	for (i = HAWK_COUNTOF(rtx->ctos.b); i > 1;)
 | 
						|
	{
 | 
						|
		--i;
 | 
						|
		rtx->ctos.b[i].c[0] = i - 1;
 | 
						|
	}
 | 
						|
	/* rtx->ctos.b[0] is not used as the free index of 0 indicates the end of the list.
 | 
						|
	 * see hawk_rtx_getvaloocstr(). */
 | 
						|
 | 
						|
	/* chain the bctos slots */
 | 
						|
	rtx->bctos.fi = HAWK_COUNTOF(rtx->bctos.b) - 1;
 | 
						|
	for (i = HAWK_COUNTOF(rtx->bctos.b); i > 1;)
 | 
						|
	{
 | 
						|
		--i;
 | 
						|
		rtx->bctos.b[i].c[0] = i - 1;
 | 
						|
	}
 | 
						|
	/* rtx->bctos.b[0] is not used as the free index of 0 indicates the end of the list.
 | 
						|
	 * see hawk_rtx_getvaloocstr(). */
 | 
						|
 | 
						|
	return rtx;
 | 
						|
}
 | 
						|
 | 
						|
void hawk_rtx_close (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	hawk_rtx_ecb_t* ecb, * ecb_next;
 | 
						|
	struct module_fini_ctx_t mfc;
 | 
						|
 | 
						|
	mfc.limit = 0;
 | 
						|
	mfc.count = 0;
 | 
						|
	mfc.rtx = rtx;
 | 
						|
	hawk_rbt_walk(rtx->hawk->modtab, fini_module, &mfc);
 | 
						|
 | 
						|
	for (ecb = rtx->ecb; ecb != (hawk_rtx_ecb_t*)rtx; ecb = ecb_next)
 | 
						|
	{
 | 
						|
		ecb_next = ecb->next;
 | 
						|
		if (ecb->close) ecb->close(rtx, ecb->ctx);
 | 
						|
	}
 | 
						|
 | 
						|
	do { ecb = hawk_rtx_popecb(rtx); } while (ecb);
 | 
						|
	HAWK_ASSERT(rtx->ecb == (hawk_rtx_ecb_t*)rtx);
 | 
						|
 | 
						|
	/* NOTE:
 | 
						|
	 *  the close callbacks are called before data in rtx
 | 
						|
	 *  is destroyed. if the destruction count on any data
 | 
						|
	 *  destroyed by the close callback, something bad
 | 
						|
	 *  will happen.
 | 
						|
	 */
 | 
						|
	fini_rtx(rtx, 1);
 | 
						|
 | 
						|
	hawk_freemem(hawk_rtx_gethawk(rtx), rtx);
 | 
						|
}
 | 
						|
 | 
						|
void hawk_rtx_halt (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	rtx->exit_level = EXIT_ABORT;
 | 
						|
}
 | 
						|
 | 
						|
int hawk_rtx_ishalt (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	return (rtx->exit_level == EXIT_ABORT || rtx->hawk->haltall);
 | 
						|
}
 | 
						|
 | 
						|
void hawk_rtx_getrio (hawk_rtx_t* rtx, hawk_rio_cbs_t* rio)
 | 
						|
{
 | 
						|
	rio->pipe = rtx->rio.handler[HAWK_RIO_PIPE];
 | 
						|
	rio->file = rtx->rio.handler[HAWK_RIO_FILE];
 | 
						|
	rio->console = rtx->rio.handler[HAWK_RIO_CONSOLE];
 | 
						|
}
 | 
						|
 | 
						|
void hawk_rtx_setrio (hawk_rtx_t* rtx, const hawk_rio_cbs_t* rio)
 | 
						|
{
 | 
						|
	rtx->rio.handler[HAWK_RIO_PIPE] = rio->pipe;
 | 
						|
	rtx->rio.handler[HAWK_RIO_FILE] = rio->file;
 | 
						|
	rtx->rio.handler[HAWK_RIO_CONSOLE] = rio->console;
 | 
						|
}
 | 
						|
 | 
						|
void hawk_rtx_killecb (hawk_rtx_t* rtx, hawk_rtx_ecb_t* ecb)
 | 
						|
{
 | 
						|
	hawk_rtx_ecb_t* prev, * cur;
 | 
						|
	for (cur = rtx->ecb, prev = HAWK_NULL; cur != (hawk_rtx_ecb_t*)rtx; cur = cur->next)
 | 
						|
	{
 | 
						|
		if (cur == ecb)
 | 
						|
		{
 | 
						|
			if (prev) prev->next = cur->next;
 | 
						|
			else rtx->ecb = cur->next;
 | 
						|
			cur->next = HAWK_NULL;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
hawk_rtx_ecb_t* hawk_rtx_popecb (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	hawk_rtx_ecb_t* top = rtx->ecb;
 | 
						|
	if (top == (hawk_rtx_ecb_t*)rtx) return HAWK_NULL;
 | 
						|
	rtx->ecb = top->next;
 | 
						|
	top->next = HAWK_NULL;
 | 
						|
	return top;
 | 
						|
}
 | 
						|
 | 
						|
void hawk_rtx_pushecb (hawk_rtx_t* rtx, hawk_rtx_ecb_t* ecb)
 | 
						|
{
 | 
						|
	ecb->next = rtx->ecb;
 | 
						|
	rtx->ecb = ecb;
 | 
						|
}
 | 
						|
 | 
						|
static void free_namedval (hawk_htb_t* map, void* dptr, hawk_oow_t dlen)
 | 
						|
{
 | 
						|
	hawk_rtx_refdownval(*(hawk_rtx_t**)hawk_htb_getxtn(map), dptr);
 | 
						|
}
 | 
						|
 | 
						|
static void same_namedval (hawk_htb_t* map, void* dptr, hawk_oow_t dlen)
 | 
						|
{
 | 
						|
	hawk_rtx_refdownval_nofree(*(hawk_rtx_t**)hawk_htb_getxtn(map), dptr);
 | 
						|
}
 | 
						|
 | 
						|
static int init_rtx (hawk_rtx_t* rtx, hawk_t* hawk, hawk_rio_cbs_t* rio)
 | 
						|
{
 | 
						|
	static hawk_htb_style_t style_for_named =
 | 
						|
	{
 | 
						|
		{
 | 
						|
			HAWK_HTB_COPIER_INLINE,
 | 
						|
			HAWK_HTB_COPIER_DEFAULT
 | 
						|
		},
 | 
						|
		{
 | 
						|
			HAWK_HTB_FREEER_DEFAULT,
 | 
						|
			free_namedval
 | 
						|
		},
 | 
						|
		HAWK_HTB_COMPER_DEFAULT,
 | 
						|
		same_namedval,
 | 
						|
		HAWK_HTB_SIZER_DEFAULT,
 | 
						|
		HAWK_HTB_HASHER_DEFAULT
 | 
						|
	};
 | 
						|
	hawk_oow_t stack_limit, i;
 | 
						|
 | 
						|
	rtx->_gem = hawk->_gem;
 | 
						|
	rtx->hawk = hawk;
 | 
						|
 | 
						|
	CLRERR(rtx);
 | 
						|
 | 
						|
	stack_limit = hawk->parse.pragma.rtx_stack_limit > 0? hawk->parse.pragma.rtx_stack_limit: hawk->opt.rtx_stack_limit;
 | 
						|
	if (stack_limit < HAWK_MIN_RTX_STACK_LIMIT) stack_limit = HAWK_MIN_RTX_STACK_LIMIT;
 | 
						|
	rtx->stack = hawk_rtx_allocmem(rtx, stack_limit * HAWK_SIZEOF(void*));
 | 
						|
	if (HAWK_UNLIKELY(!rtx->stack)) goto oops_0;
 | 
						|
	rtx->stack_top = 0;
 | 
						|
	rtx->stack_base = 0;
 | 
						|
	rtx->stack_limit = stack_limit;
 | 
						|
 | 
						|
	rtx->exit_level = EXIT_NONE;
 | 
						|
 | 
						|
	rtx->vmgr.ichunk = HAWK_NULL;
 | 
						|
	rtx->vmgr.ifree = HAWK_NULL;
 | 
						|
	rtx->vmgr.rchunk = HAWK_NULL;
 | 
						|
	rtx->vmgr.rfree = HAWK_NULL;
 | 
						|
 | 
						|
	for (i = 0; i < HAWK_COUNTOF(rtx->gc.g); i++)
 | 
						|
	{
 | 
						|
		/* initialize circular doubly-linked list */
 | 
						|
		rtx->gc.g[i].gc_next = &rtx->gc.g[i];
 | 
						|
		rtx->gc.g[i].gc_prev = &rtx->gc.g[i];
 | 
						|
 | 
						|
		/* initialize some counters */
 | 
						|
		rtx->gc.pressure[i] = 0;
 | 
						|
		rtx->gc.threshold[i] = (HAWK_COUNTOF(rtx->gc.g) - i) * 10;
 | 
						|
		if (i == 0 && rtx->gc.threshold[i] < 100) rtx->gc.threshold[i] = 100; /* minimum threshold for gen 0 is 100 */
 | 
						|
	}
 | 
						|
 | 
						|
	rtx->gc.pressure[i] = 0; /* pressure is larger than other elements by 1 in size */
 | 
						|
 | 
						|
	rtx->inrec.buf_pos = 0;
 | 
						|
	rtx->inrec.buf_len = 0;
 | 
						|
	rtx->inrec.flds = HAWK_NULL;
 | 
						|
	rtx->inrec.nflds = 0;
 | 
						|
	rtx->inrec.maxflds = 0;
 | 
						|
	rtx->inrec.d0 = hawk_val_nil;
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(hawk_ooecs_init(&rtx->inrec.line, hawk_rtx_getgem(rtx), DEF_BUF_CAPA) <= -1)) goto oops_1;
 | 
						|
	if (HAWK_UNLIKELY(hawk_ooecs_init(&rtx->inrec.linew, hawk_rtx_getgem(rtx), DEF_BUF_CAPA) <= -1)) goto oops_2;
 | 
						|
	if (HAWK_UNLIKELY(hawk_ooecs_init(&rtx->inrec.lineg, hawk_rtx_getgem(rtx), DEF_BUF_CAPA) <= -1)) goto oops_3;
 | 
						|
	if (HAWK_UNLIKELY(hawk_becs_init(&rtx->inrec.linegb, hawk_rtx_getgem(rtx), DEF_BUF_CAPA) <= -1)) goto oops_4;
 | 
						|
	if (HAWK_UNLIKELY(hawk_ooecs_init(&rtx->format.out, hawk_rtx_getgem(rtx), 256) <= -1)) goto oops_5;
 | 
						|
	if (HAWK_UNLIKELY(hawk_ooecs_init(&rtx->format.fmt, hawk_rtx_getgem(rtx), 256) <= -1)) goto oops_6;
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(hawk_becs_init(&rtx->formatmbs.out, hawk_rtx_getgem(rtx), 256) <= -1)) goto oops_7;
 | 
						|
	if (HAWK_UNLIKELY(hawk_becs_init(&rtx->formatmbs.fmt, hawk_rtx_getgem(rtx), 256) <= -1)) goto oops_8;
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(hawk_becs_init(&rtx->fnc.bout, hawk_rtx_getgem(rtx), 256) <= -1)) goto oops_9;
 | 
						|
	if (HAWK_UNLIKELY(hawk_ooecs_init(&rtx->fnc.oout, hawk_rtx_getgem(rtx), 256) <= -1)) goto oops_10;
 | 
						|
 | 
						|
 | 
						|
	rtx->named = hawk_htb_open(hawk_rtx_getgem(rtx), HAWK_SIZEOF(rtx), 1024, 70, HAWK_SIZEOF(hawk_ooch_t), 1);
 | 
						|
	if (HAWK_UNLIKELY(!rtx->named)) goto oops_11;
 | 
						|
	*(hawk_rtx_t**)hawk_htb_getxtn(rtx->named) = rtx;
 | 
						|
	hawk_htb_setstyle (rtx->named, &style_for_named);
 | 
						|
 | 
						|
	rtx->format.tmp.ptr = (hawk_ooch_t*)hawk_rtx_allocmem(rtx, 4096 * HAWK_SIZEOF(hawk_ooch_t));
 | 
						|
	if (HAWK_UNLIKELY(!rtx->format.tmp.ptr)) goto oops_12; /* the error is set on the hawk object after this jump is made */
 | 
						|
	rtx->format.tmp.len = 4096;
 | 
						|
	rtx->format.tmp.inc = 4096 * 2;
 | 
						|
 | 
						|
	rtx->formatmbs.tmp.ptr = (hawk_bch_t*)hawk_rtx_allocmem(rtx, 4096 * HAWK_SIZEOF(hawk_bch_t));
 | 
						|
	if (HAWK_UNLIKELY(!rtx->formatmbs.tmp.ptr)) goto oops_13;
 | 
						|
	rtx->formatmbs.tmp.len = 4096;
 | 
						|
	rtx->formatmbs.tmp.inc = 4096 * 2;
 | 
						|
 | 
						|
	if (rtx->hawk->tree.chain_size > 0)
 | 
						|
	{
 | 
						|
		rtx->pattern_range_state = (hawk_oob_t*)hawk_rtx_allocmem(rtx, rtx->hawk->tree.chain_size * HAWK_SIZEOF(hawk_oob_t));
 | 
						|
		if (HAWK_UNLIKELY(!rtx->pattern_range_state)) goto oops_14;
 | 
						|
		HAWK_MEMSET (rtx->pattern_range_state, 0, rtx->hawk->tree.chain_size * HAWK_SIZEOF(hawk_oob_t));
 | 
						|
	}
 | 
						|
	else rtx->pattern_range_state = HAWK_NULL;
 | 
						|
 | 
						|
	if (rio)
 | 
						|
	{
 | 
						|
		rtx->rio.handler[HAWK_RIO_PIPE] = rio->pipe;
 | 
						|
		rtx->rio.handler[HAWK_RIO_FILE] = rio->file;
 | 
						|
		rtx->rio.handler[HAWK_RIO_CONSOLE] = rio->console;
 | 
						|
		rtx->rio.chain = HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	rtx->gbl.rs[0] = HAWK_NULL;
 | 
						|
	rtx->gbl.rs[1] = HAWK_NULL;
 | 
						|
	rtx->gbl.fs[0] = HAWK_NULL;
 | 
						|
	rtx->gbl.fs[1] = HAWK_NULL;
 | 
						|
	rtx->gbl.ignorecase = 0;
 | 
						|
	rtx->gbl.striprecspc = -1; /* means 'not set' */
 | 
						|
	rtx->gbl.stripstrspc = -1; /* means 'not set' */
 | 
						|
	rtx->gbl.numstrdetect = -1; /* means 'not set' */
 | 
						|
 | 
						|
	return 0;
 | 
						|
 | 
						|
oops_14:
 | 
						|
	hawk_rtx_freemem(rtx, rtx->formatmbs.tmp.ptr);
 | 
						|
oops_13:
 | 
						|
	hawk_rtx_freemem(rtx, rtx->format.tmp.ptr);
 | 
						|
oops_12:
 | 
						|
	hawk_htb_close(rtx->named);
 | 
						|
oops_11:
 | 
						|
	hawk_ooecs_fini(&rtx->fnc.oout);
 | 
						|
oops_10:
 | 
						|
	hawk_becs_fini(&rtx->fnc.bout);
 | 
						|
oops_9:
 | 
						|
	hawk_becs_fini(&rtx->formatmbs.fmt);
 | 
						|
oops_8:
 | 
						|
	hawk_becs_fini(&rtx->formatmbs.out);
 | 
						|
oops_7:
 | 
						|
	hawk_ooecs_fini(&rtx->format.fmt);
 | 
						|
oops_6:
 | 
						|
	hawk_ooecs_fini(&rtx->format.out);
 | 
						|
oops_5:
 | 
						|
	hawk_becs_fini(&rtx->inrec.linegb);
 | 
						|
oops_4:
 | 
						|
	hawk_ooecs_fini(&rtx->inrec.lineg);
 | 
						|
oops_3:
 | 
						|
	hawk_ooecs_fini(&rtx->inrec.linew);
 | 
						|
oops_2:
 | 
						|
	hawk_ooecs_fini(&rtx->inrec.line);
 | 
						|
oops_1:
 | 
						|
	hawk_rtx_freemem(rtx, rtx->stack);
 | 
						|
oops_0:
 | 
						|
	return -1;
 | 
						|
}
 | 
						|
 | 
						|
static void fini_rtx (hawk_rtx_t* rtx, int fini_globals)
 | 
						|
{
 | 
						|
	if (rtx->forin.ptr)
 | 
						|
	{
 | 
						|
		while (rtx->forin.size > 0)
 | 
						|
		{
 | 
						|
			hawk_rtx_refdownval(rtx, rtx->forin.ptr[--rtx->forin.size]);
 | 
						|
		}
 | 
						|
		hawk_rtx_freemem(rtx, rtx->forin.ptr);
 | 
						|
		rtx->forin.ptr = HAWK_NULL;
 | 
						|
		rtx->forin.capa = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if (rtx->pattern_range_state)
 | 
						|
		hawk_rtx_freemem(rtx, rtx->pattern_range_state);
 | 
						|
 | 
						|
	/* close all pending io's */
 | 
						|
	/* TODO: what if this operation fails? */
 | 
						|
	hawk_rtx_clearallios (rtx);
 | 
						|
	HAWK_ASSERT(rtx->rio.chain == HAWK_NULL);
 | 
						|
 | 
						|
	if (rtx->gbl.rs[0])
 | 
						|
	{
 | 
						|
		hawk_rtx_freerex(rtx, rtx->gbl.rs[0], rtx->gbl.rs[1]);
 | 
						|
		rtx->gbl.rs[0] = HAWK_NULL;
 | 
						|
		rtx->gbl.rs[1] = HAWK_NULL;
 | 
						|
	}
 | 
						|
	if (rtx->gbl.fs[0])
 | 
						|
	{
 | 
						|
		hawk_rtx_freerex(rtx, rtx->gbl.fs[0], rtx->gbl.fs[1]);
 | 
						|
		rtx->gbl.fs[0] = HAWK_NULL;
 | 
						|
		rtx->gbl.fs[1] = HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (rtx->gbl.convfmt.ptr != HAWK_NULL &&
 | 
						|
	    rtx->gbl.convfmt.ptr != DEFAULT_CONVFMT)
 | 
						|
	{
 | 
						|
		hawk_rtx_freemem(rtx, rtx->gbl.convfmt.ptr);
 | 
						|
		rtx->gbl.convfmt.ptr = HAWK_NULL;
 | 
						|
		rtx->gbl.convfmt.len = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if (rtx->gbl.ofmt.ptr != HAWK_NULL &&
 | 
						|
	    rtx->gbl.ofmt.ptr != DEFAULT_OFMT)
 | 
						|
	{
 | 
						|
		hawk_rtx_freemem(rtx, rtx->gbl.ofmt.ptr);
 | 
						|
		rtx->gbl.ofmt.ptr = HAWK_NULL;
 | 
						|
		rtx->gbl.ofmt.len = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if (rtx->gbl.ofs.ptr != HAWK_NULL &&
 | 
						|
	    rtx->gbl.ofs.ptr != DEFAULT_OFS)
 | 
						|
	{
 | 
						|
		hawk_rtx_freemem(rtx, rtx->gbl.ofs.ptr);
 | 
						|
		rtx->gbl.ofs.ptr = HAWK_NULL;
 | 
						|
		rtx->gbl.ofs.len = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if (rtx->gbl.ors.ptr != HAWK_NULL &&
 | 
						|
	    rtx->gbl.ors.ptr != DEFAULT_ORS &&
 | 
						|
	    rtx->gbl.ors.ptr != DEFAULT_ORS_CRLF)
 | 
						|
	{
 | 
						|
		hawk_rtx_freemem(rtx, rtx->gbl.ors.ptr);
 | 
						|
		rtx->gbl.ors.ptr = HAWK_NULL;
 | 
						|
		rtx->gbl.ors.len = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if (rtx->gbl.subsep.ptr != HAWK_NULL &&
 | 
						|
	    rtx->gbl.subsep.ptr != DEFAULT_SUBSEP)
 | 
						|
	{
 | 
						|
		hawk_rtx_freemem(rtx, rtx->gbl.subsep.ptr);
 | 
						|
		rtx->gbl.subsep.ptr = HAWK_NULL;
 | 
						|
		rtx->gbl.subsep.len = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	hawk_ooecs_fini(&rtx->fnc.oout);
 | 
						|
	hawk_becs_fini(&rtx->fnc.bout);
 | 
						|
 | 
						|
	hawk_rtx_freemem(rtx, rtx->formatmbs.tmp.ptr);
 | 
						|
	rtx->formatmbs.tmp.ptr = HAWK_NULL;
 | 
						|
	rtx->formatmbs.tmp.len = 0;
 | 
						|
	hawk_becs_fini(&rtx->formatmbs.fmt);
 | 
						|
	hawk_becs_fini(&rtx->formatmbs.out);
 | 
						|
 | 
						|
	hawk_rtx_freemem(rtx, rtx->format.tmp.ptr);
 | 
						|
	rtx->format.tmp.ptr = HAWK_NULL;
 | 
						|
	rtx->format.tmp.len = 0;
 | 
						|
	hawk_ooecs_fini(&rtx->format.fmt);
 | 
						|
	hawk_ooecs_fini(&rtx->format.out);
 | 
						|
 | 
						|
	/* destroy input record. hawk_rtx_clrrec() should be called
 | 
						|
	 * before the stack has been destroyed because it may try
 | 
						|
	 * to change the value to HAWK_GBL_NF. */
 | 
						|
	hawk_rtx_clrrec(rtx, 0);
 | 
						|
	if (rtx->inrec.flds)
 | 
						|
	{
 | 
						|
		hawk_rtx_freemem(rtx, rtx->inrec.flds);
 | 
						|
		rtx->inrec.flds = HAWK_NULL;
 | 
						|
		rtx->inrec.maxflds = 0;
 | 
						|
	}
 | 
						|
	hawk_becs_fini(&rtx->inrec.linegb);
 | 
						|
	hawk_ooecs_fini(&rtx->inrec.lineg);
 | 
						|
	hawk_ooecs_fini(&rtx->inrec.linew);
 | 
						|
	hawk_ooecs_fini(&rtx->inrec.line);
 | 
						|
 | 
						|
	if (fini_globals) refdown_globals(rtx, 1);
 | 
						|
 | 
						|
	/* destroy the stack if necessary */
 | 
						|
	if (rtx->stack)
 | 
						|
	{
 | 
						|
		HAWK_ASSERT(rtx->stack_top == 0);
 | 
						|
 | 
						|
		hawk_rtx_freemem(rtx, rtx->stack);
 | 
						|
		rtx->stack = HAWK_NULL;
 | 
						|
		rtx->stack_top = 0;
 | 
						|
		rtx->stack_base = 0;
 | 
						|
		rtx->stack_limit = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* destroy named variables */
 | 
						|
	hawk_htb_close (rtx->named);
 | 
						|
 | 
						|
#if defined(HAWK_ENABLE_GC)
 | 
						|
	/* collect garbage after having released global variables and named global variables */
 | 
						|
	hawk_rtx_gc(rtx, HAWK_RTX_GC_GEN_FULL);
 | 
						|
#endif
 | 
						|
 | 
						|
	/* destroy values in free list */
 | 
						|
	while (rtx->rcache_count > 0)
 | 
						|
	{
 | 
						|
		hawk_val_ref_t* tmp = rtx->rcache[--rtx->rcache_count];
 | 
						|
		hawk_rtx_freeval(rtx, (hawk_val_t*)tmp, 0);
 | 
						|
	}
 | 
						|
 | 
						|
#if defined(HAWK_ENABLE_STR_CACHE)
 | 
						|
	{
 | 
						|
		int i;
 | 
						|
		for (i = 0; i < HAWK_COUNTOF(rtx->str_cache_count); i++)
 | 
						|
		{
 | 
						|
			while (rtx->str_cache_count[i] > 0)
 | 
						|
			{
 | 
						|
				hawk_val_str_t* t = rtx->str_cache[i][--rtx->str_cache_count[i]];
 | 
						|
				hawk_rtx_freeval(rtx, (hawk_val_t*)t, 0);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(HAWK_ENABLE_MBS_CACHE)
 | 
						|
	{
 | 
						|
		int i;
 | 
						|
		for (i = 0; i < HAWK_COUNTOF(rtx->mbs_cache_count); i++)
 | 
						|
		{
 | 
						|
			while (rtx->mbs_cache_count[i] > 0)
 | 
						|
			{
 | 
						|
				hawk_val_mbs_t* t = rtx->mbs_cache[i][--rtx->mbs_cache_count[i]];
 | 
						|
				hawk_rtx_freeval(rtx, (hawk_val_t*)t, 0);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	hawk_rtx_freevalchunk(rtx, rtx->vmgr.ichunk);
 | 
						|
	hawk_rtx_freevalchunk(rtx, rtx->vmgr.rchunk);
 | 
						|
	rtx->vmgr.ichunk = HAWK_NULL;
 | 
						|
	rtx->vmgr.rchunk = HAWK_NULL;
 | 
						|
}
 | 
						|
 | 
						|
static int update_fnr (hawk_rtx_t* rtx, hawk_int_t fnr, hawk_int_t nr)
 | 
						|
{
 | 
						|
	hawk_val_t* tmp1, * tmp2;
 | 
						|
	int n;
 | 
						|
 | 
						|
	tmp1 = hawk_rtx_makeintval(rtx, fnr);
 | 
						|
	if (!tmp1) return -1;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, tmp1);
 | 
						|
 | 
						|
	if (nr == fnr) tmp2 = tmp1;
 | 
						|
	else
 | 
						|
	{
 | 
						|
		tmp2 = hawk_rtx_makeintval(rtx, nr);
 | 
						|
		if (HAWK_UNLIKELY(!tmp2)) { n = -1; goto oops; }
 | 
						|
		hawk_rtx_refupval(rtx, tmp2);
 | 
						|
	}
 | 
						|
 | 
						|
	n = (hawk_rtx_setgbl(rtx, HAWK_GBL_FNR, tmp1) <= -1 ||
 | 
						|
	     hawk_rtx_setgbl(rtx, HAWK_GBL_NR, tmp2) <= -1)? -1: 0;
 | 
						|
 | 
						|
	if (tmp2 != tmp1) hawk_rtx_refdownval(rtx, tmp2);
 | 
						|
 | 
						|
oops:
 | 
						|
	hawk_rtx_refdownval(rtx, tmp1);
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * create global variables into the runtime stack
 | 
						|
 * each variable is initialized to nil or zero.
 | 
						|
 */
 | 
						|
static int prepare_globals (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	hawk_oow_t saved_stack_top;
 | 
						|
	hawk_oow_t ngbls;
 | 
						|
 | 
						|
	ngbls = rtx->hawk->tree.ngbls;
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < ngbls))
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_ESTACK);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	saved_stack_top = rtx->stack_top;
 | 
						|
 | 
						|
	/* initialize all global variables to nil by push nils to the stack */
 | 
						|
	while (ngbls > 0)
 | 
						|
	{
 | 
						|
		--ngbls;
 | 
						|
		HAWK_RTX_STACK_PUSH(rtx, hawk_val_nil);
 | 
						|
	}
 | 
						|
 | 
						|
	/* override NF to zero */
 | 
						|
	if (hawk_rtx_setgbl(rtx, HAWK_GBL_NF, HAWK_VAL_ZERO) <= -1)
 | 
						|
	{
 | 
						|
		/* restore the stack_top this way instead of calling HAWK_RTX_STACK_POP()
 | 
						|
		 * as many times as successful HAWK_RTX_STACK_PUSH(). it is ok because
 | 
						|
		 * the values pushed so far are hawk_val_nils and HAWK_VAL_ZEROs.
 | 
						|
		 */
 | 
						|
		rtx->stack_top = saved_stack_top;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	/* return success */
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * assign initial values to the global variables whose desired initial
 | 
						|
 * values are not nil or zero. some are handled in prepare_globals () and
 | 
						|
 * update_fnr().
 | 
						|
 */
 | 
						|
static int defaultify_globals (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	struct gtab_t
 | 
						|
	{
 | 
						|
		int idx;
 | 
						|
		const hawk_ooch_t* str[2];
 | 
						|
	};
 | 
						|
	static struct gtab_t gtab[9] =
 | 
						|
	{
 | 
						|
		{ HAWK_GBL_CONVFMT,    { DEFAULT_CONVFMT, DEFAULT_CONVFMT  } },
 | 
						|
		{ HAWK_GBL_FILENAME,   { HAWK_NULL,       HAWK_NULL        } },
 | 
						|
		{ HAWK_GBL_FS,         { DEFAULT_FS,      DEFAULT_FS       } },
 | 
						|
		{ HAWK_GBL_OFILENAME,  { HAWK_NULL,       HAWK_NULL        } },
 | 
						|
		{ HAWK_GBL_OFMT,       { DEFAULT_OFMT,    DEFAULT_OFMT     } },
 | 
						|
		{ HAWK_GBL_OFS,        { DEFAULT_OFS,     DEFAULT_OFS      } },
 | 
						|
		{ HAWK_GBL_ORS,        { DEFAULT_ORS,     DEFAULT_ORS_CRLF } },
 | 
						|
		{ HAWK_GBL_SCRIPTNAME, { HAWK_NULL,       HAWK_NULL        } },
 | 
						|
		{ HAWK_GBL_SUBSEP,     { DEFAULT_SUBSEP,  DEFAULT_SUBSEP   } }
 | 
						|
	};
 | 
						|
 | 
						|
	hawk_val_t* tmp;
 | 
						|
	hawk_oow_t i, j;
 | 
						|
	int stridx;
 | 
						|
 | 
						|
	stridx = (rtx->hawk->opt.trait & HAWK_CRLF)? 1: 0;
 | 
						|
	for (i = 0; i < HAWK_COUNTOF(gtab); i++)
 | 
						|
	{
 | 
						|
		if (gtab[i].str[stridx] == HAWK_NULL || gtab[i].str[stridx][0] == HAWK_T('\0'))
 | 
						|
		{
 | 
						|
			tmp = hawk_val_zls;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			tmp = hawk_rtx_makestrvalwithoocstr(rtx, gtab[i].str[stridx]);
 | 
						|
			if (tmp == HAWK_NULL) return -1;
 | 
						|
		}
 | 
						|
 | 
						|
		hawk_rtx_refupval(rtx, tmp);
 | 
						|
 | 
						|
		HAWK_ASSERT(HAWK_RTX_STACK_GBL(rtx,gtab[i].idx) == hawk_val_nil);
 | 
						|
 | 
						|
		if (hawk_rtx_setgbl(rtx, gtab[i].idx, tmp) == -1)
 | 
						|
		{
 | 
						|
			for (j = 0; j < i; j++)
 | 
						|
			{
 | 
						|
				hawk_rtx_setgbl(rtx, gtab[i].idx, hawk_val_nil);
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refdownval(rtx, tmp);
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
 | 
						|
		hawk_rtx_refdownval(rtx, tmp);
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void refdown_globals (hawk_rtx_t* rtx, int pop)
 | 
						|
{
 | 
						|
	hawk_oow_t ngbls;
 | 
						|
 | 
						|
	ngbls = rtx->hawk->tree.ngbls;
 | 
						|
	while (ngbls > 0)
 | 
						|
	{
 | 
						|
		--ngbls;
 | 
						|
		hawk_rtx_refdownval(rtx, HAWK_RTX_STACK_GBL(rtx,ngbls));
 | 
						|
		if (pop) HAWK_RTX_STACK_POP (rtx);
 | 
						|
		else HAWK_RTX_STACK_GBL(rtx,ngbls) = hawk_val_nil;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int init_globals (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	/* the stack must be clean when this function is invoked */
 | 
						|
	HAWK_ASSERT(rtx->stack_base == 0);
 | 
						|
	HAWK_ASSERT(rtx->stack_top == 0);
 | 
						|
 | 
						|
	if (prepare_globals(rtx) <= -1) return -1;
 | 
						|
	if (update_fnr(rtx, 0, 0) <= -1 || defaultify_globals(rtx) <= -1) goto oops;
 | 
						|
	return 0;
 | 
						|
 | 
						|
oops:
 | 
						|
	refdown_globals(rtx, 1);
 | 
						|
	return -1;
 | 
						|
}
 | 
						|
 | 
						|
struct capture_retval_data_t
 | 
						|
{
 | 
						|
	hawk_rtx_t* rtx;
 | 
						|
	hawk_val_t* val;
 | 
						|
};
 | 
						|
 | 
						|
static void capture_retval_on_exit (void* arg)
 | 
						|
{
 | 
						|
	struct capture_retval_data_t* data;
 | 
						|
 | 
						|
	data = (struct capture_retval_data_t*)arg;
 | 
						|
	data->val = HAWK_RTX_STACK_RETVAL(data->rtx);
 | 
						|
	hawk_rtx_refupval(data->rtx, data->val);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* run_bpae_loop (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	hawk_nde_t* nde;
 | 
						|
	hawk_oow_t nargs, i;
 | 
						|
	hawk_val_t* retv;
 | 
						|
	int ret = 0;
 | 
						|
 | 
						|
	/* set nargs to zero */
 | 
						|
	nargs = 0;
 | 
						|
	HAWK_RTX_STACK_NARGS(rtx) = (void*)nargs;
 | 
						|
 | 
						|
	/* execute the BEGIN block */
 | 
						|
	for (nde = rtx->hawk->tree.begin;
 | 
						|
	     ret == 0 && nde != HAWK_NULL && rtx->exit_level < EXIT_GLOBAL;
 | 
						|
	     nde = nde->next)
 | 
						|
	{
 | 
						|
		hawk_nde_blk_t* blk;
 | 
						|
 | 
						|
		blk = (hawk_nde_blk_t*)nde;
 | 
						|
		HAWK_ASSERT(blk->type == HAWK_NDE_BLK);
 | 
						|
 | 
						|
		rtx->active_block = blk;
 | 
						|
		rtx->exit_level = EXIT_NONE;
 | 
						|
		if (run_block(rtx, blk) <= -1) ret = -1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (ret <= -1 && hawk_rtx_geterrnum(rtx) == HAWK_ENOERR)
 | 
						|
	{
 | 
						|
		/* an error is returned with no error number set.
 | 
						|
		 * this trait is used by eval_expression() to
 | 
						|
		 * abort the evaluation when exit() is executed
 | 
						|
		 * during function evaluation */
 | 
						|
		ret = 0;
 | 
						|
		CLRERR (rtx); /* clear it just in case */
 | 
						|
	}
 | 
						|
 | 
						|
	/* run pattern block loops */
 | 
						|
	if (ret == 0 &&
 | 
						|
	    (rtx->hawk->tree.chain != HAWK_NULL ||
 | 
						|
	     rtx->hawk->tree.end != HAWK_NULL) &&
 | 
						|
	     rtx->exit_level < EXIT_GLOBAL)
 | 
						|
	{
 | 
						|
		if (run_pblocks(rtx) <= -1) ret = -1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (ret <= -1 && hawk_rtx_geterrnum(rtx) == HAWK_ENOERR)
 | 
						|
	{
 | 
						|
		/* an error is returned with no error number set.
 | 
						|
		 * this trait is used by eval_expression() to
 | 
						|
		 * abort the evaluation when exit() is executed
 | 
						|
		 * during function evaluation */
 | 
						|
		ret = 0;
 | 
						|
		CLRERR (rtx); /* clear it just in case */
 | 
						|
	}
 | 
						|
 | 
						|
	/* execute END blocks. the first END block is executed if the
 | 
						|
	 * program is not explicitly aborted with hawk_rtx_halt().*/
 | 
						|
	for (nde = rtx->hawk->tree.end;
 | 
						|
	     ret == 0 && nde != HAWK_NULL && rtx->exit_level < EXIT_ABORT;
 | 
						|
	     nde = nde->next)
 | 
						|
	{
 | 
						|
		hawk_nde_blk_t* blk;
 | 
						|
 | 
						|
		blk = (hawk_nde_blk_t*)nde;
 | 
						|
		HAWK_ASSERT(blk->type == HAWK_NDE_BLK);
 | 
						|
 | 
						|
		rtx->active_block = blk;
 | 
						|
		rtx->exit_level = EXIT_NONE;
 | 
						|
		if (run_block(rtx, blk) <= -1) ret = -1;
 | 
						|
		else if (rtx->exit_level >= EXIT_GLOBAL)
 | 
						|
		{
 | 
						|
			/* once exit is called inside one of END blocks,
 | 
						|
			 * subsequent END blocks must not be executed */
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (ret <= -1 && hawk_rtx_geterrnum(rtx) == HAWK_ENOERR)
 | 
						|
	{
 | 
						|
		/* an error is returned with no error number set.
 | 
						|
		 * this trait is used by eval_expression() to
 | 
						|
		 * abort the evaluation when exit() is executed
 | 
						|
		 * during function evaluation */
 | 
						|
		ret = 0;
 | 
						|
		CLRERR (rtx); /* clear it just in case */
 | 
						|
	}
 | 
						|
 | 
						|
	/* derefrence all arguments. however, there should be no arguments
 | 
						|
	 * pushed to the stack as asserted below. we didn't push any arguments
 | 
						|
	 * for BEGIN/pattern action/END block execution.*/
 | 
						|
	nargs = (hawk_oow_t)HAWK_RTX_STACK_NARGS(rtx);
 | 
						|
	HAWK_ASSERT(nargs == 0);
 | 
						|
	for (i = 0; i < nargs; i++)
 | 
						|
		hawk_rtx_refdownval(rtx, HAWK_RTX_STACK_ARG(rtx,i));
 | 
						|
 | 
						|
	/* get the return value in the current stack frame */
 | 
						|
	retv = HAWK_RTX_STACK_RETVAL(rtx);
 | 
						|
 | 
						|
	if (ret <= -1)
 | 
						|
	{
 | 
						|
		/* end the life of the global return value upon error */
 | 
						|
		hawk_rtx_refdownval(rtx, retv);
 | 
						|
		retv = HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return retv;
 | 
						|
}
 | 
						|
 | 
						|
/* start the BEGIN-pattern block-END loop */
 | 
						|
hawk_val_t* hawk_rtx_loop (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	hawk_val_t* retv = HAWK_NULL;
 | 
						|
	hawk_oow_t saved_stack_top;
 | 
						|
 | 
						|
	rtx->exit_level = EXIT_NONE;
 | 
						|
 | 
						|
	/* make a new stack frame */
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < 4))
 | 
						|
	{
 | 
						|
		/* restore the stack top in a cheesy(?) way.
 | 
						|
		 * it is ok to do so as the values pushed are
 | 
						|
		 * nils and binary numbers. */
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_ESTACK);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	saved_stack_top = rtx->stack_top; 	/* remember the current stack top */
 | 
						|
	HAWK_RTX_STACK_PUSH(rtx, (void*)rtx->stack_base); /* push the current stack base */
 | 
						|
	HAWK_RTX_STACK_PUSH(rtx, (void*)saved_stack_top); /* push the current stack top before push the current stack base */
 | 
						|
	HAWK_RTX_STACK_PUSH(rtx, hawk_val_nil); /* secure space for a return value */
 | 
						|
	HAWK_RTX_STACK_PUSH(rtx, hawk_val_nil); /* secure space for HAWK_RTX_STACK_NARGS */
 | 
						|
 | 
						|
	/* enter the new stack frame */
 | 
						|
	rtx->stack_base = saved_stack_top; /* let the stack top remembered be the base of a new stack frame */
 | 
						|
 | 
						|
	/* run the BEGIN/pattern-action/END loop */
 | 
						|
	retv = run_bpae_loop(rtx);
 | 
						|
 | 
						|
	/* exit the stack frame */
 | 
						|
	HAWK_ASSERT((rtx->stack_top - rtx->stack_base) == 4); /* at this point, the current stack frame should have the 4 entries pushed above */
 | 
						|
	rtx->stack_top = (hawk_oow_t)rtx->stack[rtx->stack_base + 1];
 | 
						|
	rtx->stack_base = (hawk_oow_t)rtx->stack[rtx->stack_base + 0];
 | 
						|
 | 
						|
	/* reset the exit level */
 | 
						|
	rtx->exit_level = EXIT_NONE;
 | 
						|
 | 
						|
	/* flush all buffered io data */
 | 
						|
	hawk_rtx_flushallios (rtx);
 | 
						|
 | 
						|
	return retv;
 | 
						|
}
 | 
						|
 | 
						|
hawk_val_t* hawk_rtx_execwithucstrarr (hawk_rtx_t* rtx, const hawk_uch_t* args[], hawk_oow_t nargs)
 | 
						|
{
 | 
						|
	hawk_val_t* v;
 | 
						|
 | 
						|
	v = (rtx->hawk->parse.pragma.entry[0] != '\0')?
 | 
						|
		hawk_rtx_callwithooucstrarr(rtx, rtx->hawk->parse.pragma.entry, args, nargs):
 | 
						|
		hawk_rtx_loop(rtx);
 | 
						|
 | 
						|
#if defined(HAWK_ENABLE_GC)
 | 
						|
	/* i assume this function is a usual hawk program starter.
 | 
						|
	 * call garbage collection after a whole program finishes */
 | 
						|
	hawk_rtx_gc(rtx, HAWK_RTX_GC_GEN_FULL);
 | 
						|
#endif
 | 
						|
 | 
						|
	return v;
 | 
						|
}
 | 
						|
 | 
						|
hawk_val_t* hawk_rtx_execwithbcstrarr (hawk_rtx_t* rtx, const hawk_bch_t* args[], hawk_oow_t nargs)
 | 
						|
{
 | 
						|
	hawk_val_t* v;
 | 
						|
 | 
						|
	v = (rtx->hawk->parse.pragma.entry[0] != '\0')?
 | 
						|
		hawk_rtx_callwithoobcstrarr(rtx, rtx->hawk->parse.pragma.entry, args, nargs):
 | 
						|
		hawk_rtx_loop(rtx);
 | 
						|
 | 
						|
#if defined(HAWK_ENABLE_GC)
 | 
						|
	/* i assume this function is a usual hawk program starter.
 | 
						|
	 * call garbage collection after a whole program finishes */
 | 
						|
	hawk_rtx_gc(rtx, HAWK_RTX_GC_GEN_FULL);
 | 
						|
#endif
 | 
						|
 | 
						|
	return v;
 | 
						|
}
 | 
						|
 | 
						|
/* find an AWK function by name */
 | 
						|
static hawk_fun_t* find_fun (hawk_rtx_t* rtx, const hawk_ooch_t* name)
 | 
						|
{
 | 
						|
	hawk_htb_pair_t* pair;
 | 
						|
 | 
						|
	pair = hawk_htb_search(rtx->hawk->tree.funs, name, hawk_count_oocstr(name));
 | 
						|
	if (!pair)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrfmt(rtx, HAWK_NULL, HAWK_EFUNNF, HAWK_T("unable to find function '%js'"), name);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return (hawk_fun_t*)HAWK_HTB_VPTR(pair);
 | 
						|
}
 | 
						|
 | 
						|
hawk_fun_t* hawk_rtx_findfunwithbcstr (hawk_rtx_t* rtx, const hawk_bch_t* name)
 | 
						|
{
 | 
						|
#if defined(HAWK_OOCH_IS_BCH)
 | 
						|
	return find_fun(rtx, name);
 | 
						|
#else
 | 
						|
	hawk_ucs_t wcs;
 | 
						|
	hawk_fun_t* fun;
 | 
						|
	wcs.ptr = hawk_rtx_dupbtoucstr(rtx, name, &wcs.len, 0);
 | 
						|
	if (!wcs.ptr) return HAWK_NULL;
 | 
						|
	fun = find_fun(rtx, wcs.ptr);
 | 
						|
	hawk_rtx_freemem(rtx, wcs.ptr);
 | 
						|
	return fun;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
hawk_fun_t* hawk_rtx_findfunwithucstr (hawk_rtx_t* rtx, const hawk_uch_t* name)
 | 
						|
{
 | 
						|
#if defined(HAWK_OOCH_IS_BCH)
 | 
						|
	hawk_bcs_t mbs;
 | 
						|
	hawk_fun_t* fun;
 | 
						|
	mbs.ptr = hawk_rtx_duputobcstr(rtx, name, &mbs.len);
 | 
						|
	if (!mbs.ptr) return HAWK_NULL;
 | 
						|
	fun = find_fun(rtx, mbs.ptr);
 | 
						|
	hawk_rtx_freemem(rtx, mbs.ptr);
 | 
						|
	return fun;
 | 
						|
#else
 | 
						|
	return find_fun(rtx, name);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/* call an AWK function by the function structure */
 | 
						|
hawk_val_t* hawk_rtx_callfun (hawk_rtx_t* rtx, hawk_fun_t* fun, hawk_val_t* args[], hawk_oow_t nargs)
 | 
						|
{
 | 
						|
	struct capture_retval_data_t crdata;
 | 
						|
	hawk_val_t* v;
 | 
						|
	struct pafv_t pafv/*= { args, nargs }*/;
 | 
						|
	hawk_nde_fncall_t call;
 | 
						|
 | 
						|
	HAWK_ASSERT(fun != HAWK_NULL);
 | 
						|
 | 
						|
	pafv.args = args;
 | 
						|
	pafv.nargs = nargs;
 | 
						|
	pafv.argspec = fun->argspec;
 | 
						|
	pafv.argspeclen = fun->argspeclen;
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(rtx->exit_level >= EXIT_GLOBAL))
 | 
						|
	{
 | 
						|
		/* cannot call the function again when exit() is called
 | 
						|
		 * in an AWK program or hawk_rtx_halt() is invoked */
 | 
						|
		hawk_rtx_seterrfmt(rtx, HAWK_NULL, HAWK_EPERM, HAWK_T("now allowed to call '%.*js' after exit"), fun->name.len, fun->name.ptr);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
	/*rtx->exit_level = EXIT_NONE;*/
 | 
						|
 | 
						|
#if 0
 | 
						|
	if (fun->argspec)
 | 
						|
	{
 | 
						|
		/* this function contains pass-by-reference parameters.
 | 
						|
		 * i don't support the call here as it requires variables */
 | 
						|
		hawk_rtx_seterrfmt(rtx, HAWK_NULL, HAWK_EPERM, HAWK_T("not allowed to call '%.*js' with pass-by-reference parameters"), fun->name.len, fun->name.ptr);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	/* forge a fake node containing a function call */
 | 
						|
	HAWK_MEMSET (&call, 0, HAWK_SIZEOF(call));
 | 
						|
	call.type = HAWK_NDE_FNCALL_FUN;
 | 
						|
	call.u.fun.name = fun->name;
 | 
						|
	call.nargs = nargs;
 | 
						|
	/* keep HAWK_NULL in call.args so that hawk_rtx_evalcall() knows it's a fake call structure */
 | 
						|
 | 
						|
	/* check if the number of arguments given is more than expected */
 | 
						|
	if (nargs > fun->nargs && !fun->variadic)
 | 
						|
	{
 | 
						|
		/* TODO: is this correct? what if i want to
 | 
						|
		 *       allow arbitrary numbers of arguments? */
 | 
						|
		hawk_rtx_seterrfmt(rtx, HAWK_NULL, HAWK_EARGTM, HAWK_T("too many arguments to '%.*js'"), fun->name.len, fun->name.ptr);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	/* now that the function is found and ok, let's execute it */
 | 
						|
 | 
						|
	crdata.rtx = rtx;
 | 
						|
	crdata.val = HAWK_NULL;
 | 
						|
 | 
						|
	v = hawk_rtx_evalcall(rtx, &call, fun, push_arg_from_vals, (void*)&pafv, capture_retval_on_exit, &crdata);
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(!v))
 | 
						|
	{
 | 
						|
		/* an error occurred. let's check if it is caused by exit().
 | 
						|
		 * if so, the return value should have been captured into
 | 
						|
		 * crdata.val. */
 | 
						|
		if (crdata.val) v = crdata.val; /* yet it is */
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		/* the return value captured in termination by exit()
 | 
						|
		 * is reference-counted up in capture_retval_on_exit().
 | 
						|
		 * let's do the same thing for the return value normally
 | 
						|
		 * returned. */
 | 
						|
		hawk_rtx_refupval(rtx, v);
 | 
						|
	}
 | 
						|
 | 
						|
	/* flush all buffered io data */
 | 
						|
	hawk_rtx_flushallios (rtx);
 | 
						|
 | 
						|
	/* return the return value with its reference count at least 1.
 | 
						|
	 * the caller of this function should count down its reference. */
 | 
						|
	return v;
 | 
						|
}
 | 
						|
 | 
						|
/* call an AWK function by name */
 | 
						|
hawk_val_t* hawk_rtx_callwithucstr (hawk_rtx_t* rtx, const hawk_uch_t* name, hawk_val_t* args[], hawk_oow_t nargs)
 | 
						|
{
 | 
						|
	hawk_fun_t* fun;
 | 
						|
 | 
						|
	fun = hawk_rtx_findfunwithucstr(rtx, name);
 | 
						|
	if (HAWK_UNLIKELY(!fun)) return HAWK_NULL;
 | 
						|
 | 
						|
	return hawk_rtx_callfun(rtx, fun, args, nargs);
 | 
						|
}
 | 
						|
 | 
						|
hawk_val_t* hawk_rtx_callwithbcstr (hawk_rtx_t* rtx, const hawk_bch_t* name, hawk_val_t* args[], hawk_oow_t nargs)
 | 
						|
{
 | 
						|
	hawk_fun_t* fun;
 | 
						|
 | 
						|
	fun = hawk_rtx_findfunwithbcstr(rtx, name);
 | 
						|
	if (!fun) return HAWK_NULL;
 | 
						|
 | 
						|
	return hawk_rtx_callfun(rtx, fun, args, nargs);
 | 
						|
}
 | 
						|
 | 
						|
hawk_val_t* hawk_rtx_callwithucstrarr (hawk_rtx_t* rtx, const hawk_uch_t* name, const hawk_uch_t* args[], hawk_oow_t nargs)
 | 
						|
{
 | 
						|
	hawk_oow_t i;
 | 
						|
	hawk_val_t** v, * ret;
 | 
						|
 | 
						|
	v = hawk_rtx_allocmem(rtx, HAWK_SIZEOF(*v) * nargs);
 | 
						|
	if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
 | 
						|
	for (i = 0; i < nargs; i++)
 | 
						|
	{
 | 
						|
		v[i] = hawk_rtx_makestrvalwithucstr(rtx, args[i]);
 | 
						|
		if (HAWK_UNLIKELY(!v[i]))
 | 
						|
		{
 | 
						|
			ret = HAWK_NULL;
 | 
						|
			goto oops;
 | 
						|
		}
 | 
						|
 | 
						|
		hawk_rtx_refupval(rtx, v[i]);
 | 
						|
	}
 | 
						|
 | 
						|
	ret = hawk_rtx_callwithucstr(rtx, name, v, nargs);
 | 
						|
 | 
						|
oops:
 | 
						|
	while (i > 0)
 | 
						|
	{
 | 
						|
		hawk_rtx_refdownval(rtx, v[--i]);
 | 
						|
	}
 | 
						|
	hawk_rtx_freemem(rtx, v);
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
hawk_val_t* hawk_rtx_callwithbcstrarr (hawk_rtx_t* rtx, const hawk_bch_t* name, const hawk_bch_t* args[], hawk_oow_t nargs)
 | 
						|
{
 | 
						|
	hawk_oow_t i;
 | 
						|
	hawk_val_t** v, * ret;
 | 
						|
 | 
						|
	v = hawk_rtx_allocmem(rtx, HAWK_SIZEOF(*v) * nargs);
 | 
						|
	if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
 | 
						|
	for (i = 0; i < nargs; i++)
 | 
						|
	{
 | 
						|
		v[i] = hawk_rtx_makestrvalwithbcstr(rtx, args[i]);
 | 
						|
		if (HAWK_UNLIKELY(!v[i]))
 | 
						|
		{
 | 
						|
			ret = HAWK_NULL;
 | 
						|
			goto oops;
 | 
						|
		}
 | 
						|
 | 
						|
		hawk_rtx_refupval(rtx, v[i]);
 | 
						|
	}
 | 
						|
 | 
						|
	ret = hawk_rtx_callwithbcstr(rtx, name, v, nargs);
 | 
						|
 | 
						|
oops:
 | 
						|
	while (i > 0)
 | 
						|
	{
 | 
						|
		hawk_rtx_refdownval(rtx, v[--i]);
 | 
						|
	}
 | 
						|
	hawk_rtx_freemem(rtx, v);
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
hawk_val_t* hawk_rtx_callwithooucstrarr (hawk_rtx_t* rtx, const hawk_ooch_t* name, const hawk_uch_t* args[], hawk_oow_t nargs)
 | 
						|
{
 | 
						|
	hawk_oow_t i;
 | 
						|
	hawk_val_t** v, * ret;
 | 
						|
 | 
						|
	v = hawk_rtx_allocmem(rtx, HAWK_SIZEOF(*v) * nargs);
 | 
						|
	if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
 | 
						|
	for (i = 0; i < nargs; i++)
 | 
						|
	{
 | 
						|
		v[i] = hawk_rtx_makestrvalwithucstr(rtx, args[i]);
 | 
						|
		if (HAWK_UNLIKELY(!v[i]))
 | 
						|
		{
 | 
						|
			ret = HAWK_NULL;
 | 
						|
			goto oops;
 | 
						|
		}
 | 
						|
 | 
						|
		hawk_rtx_refupval(rtx, v[i]);
 | 
						|
	}
 | 
						|
 | 
						|
	ret = hawk_rtx_callwithoocstr(rtx, name, v, nargs);
 | 
						|
 | 
						|
oops:
 | 
						|
	while (i > 0)
 | 
						|
	{
 | 
						|
		hawk_rtx_refdownval(rtx, v[--i]);
 | 
						|
	}
 | 
						|
	hawk_rtx_freemem(rtx, v);
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
hawk_val_t* hawk_rtx_callwithoobcstrarr (hawk_rtx_t* rtx, const hawk_ooch_t* name, const hawk_bch_t* args[], hawk_oow_t nargs)
 | 
						|
{
 | 
						|
	hawk_oow_t i;
 | 
						|
	hawk_val_t** v, * ret;
 | 
						|
 | 
						|
	v = hawk_rtx_allocmem(rtx, HAWK_SIZEOF(*v) * nargs);
 | 
						|
	if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
 | 
						|
	for (i = 0; i < nargs; i++)
 | 
						|
	{
 | 
						|
		v[i] = hawk_rtx_makestrvalwithbcstr(rtx, args[i]);
 | 
						|
		if (HAWK_UNLIKELY(!v[i]))
 | 
						|
		{
 | 
						|
			ret = HAWK_NULL;
 | 
						|
			goto oops;
 | 
						|
		}
 | 
						|
 | 
						|
		hawk_rtx_refupval(rtx, v[i]);
 | 
						|
	}
 | 
						|
 | 
						|
	ret = hawk_rtx_callwithoocstr(rtx, name, v, nargs);
 | 
						|
 | 
						|
oops:
 | 
						|
	while (i > 0)
 | 
						|
	{
 | 
						|
		hawk_rtx_refdownval(rtx, v[--i]);
 | 
						|
	}
 | 
						|
	hawk_rtx_freemem(rtx, v);
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
static int run_pblocks (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
 | 
						|
#define ADJUST_ERROR(rtx) \
 | 
						|
	if (rtx->hawk->tree.chain != HAWK_NULL) \
 | 
						|
	{ \
 | 
						|
		if (rtx->hawk->tree.chain->pattern != HAWK_NULL) \
 | 
						|
			ADJERR_LOC(rtx, &rtx->hawk->tree.chain->pattern->loc); \
 | 
						|
		else if (rtx->hawk->tree.chain->action != HAWK_NULL) \
 | 
						|
			ADJERR_LOC(rtx, &rtx->hawk->tree.chain->action->loc); \
 | 
						|
	} \
 | 
						|
	else if (rtx->hawk->tree.end != HAWK_NULL) \
 | 
						|
	{ \
 | 
						|
		ADJERR_LOC(rtx, &rtx->hawk->tree.end->loc); \
 | 
						|
	}
 | 
						|
 | 
						|
	rtx->inrec.buf_pos = 0;
 | 
						|
	rtx->inrec.buf_len = 0;
 | 
						|
	rtx->inrec.eof = 0;
 | 
						|
 | 
						|
	/* run each pattern block */
 | 
						|
	while (rtx->exit_level < EXIT_GLOBAL)
 | 
						|
	{
 | 
						|
		rtx->exit_level = EXIT_NONE;
 | 
						|
 | 
						|
		n = read_record(rtx);
 | 
						|
		if (n <= -1)
 | 
						|
		{
 | 
						|
			ADJUST_ERROR (rtx);
 | 
						|
			return -1; /* error */
 | 
						|
		}
 | 
						|
		if (n == 0) break; /* end of input */
 | 
						|
 | 
						|
		if (rtx->hawk->tree.chain)
 | 
						|
		{
 | 
						|
			if (run_pblock_chain(rtx, rtx->hawk->tree.chain) <= -1) return -1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
#undef ADJUST_ERROR
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int run_pblock_chain (hawk_rtx_t* rtx, hawk_chain_t* chain)
 | 
						|
{
 | 
						|
	hawk_oow_t bno = 0;
 | 
						|
 | 
						|
	while (rtx->exit_level < EXIT_GLOBAL && chain)
 | 
						|
	{
 | 
						|
		if (rtx->exit_level == EXIT_NEXT)
 | 
						|
		{
 | 
						|
			rtx->exit_level = EXIT_NONE;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		if (run_pblock(rtx, chain, bno) <= -1) return -1;
 | 
						|
 | 
						|
		chain = chain->next;
 | 
						|
		bno++;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int run_pblock (hawk_rtx_t* rtx, hawk_chain_t* cha, hawk_oow_t bno)
 | 
						|
{
 | 
						|
	hawk_nde_t* ptn;
 | 
						|
	hawk_nde_blk_t* blk;
 | 
						|
 | 
						|
	ptn = cha->pattern;
 | 
						|
	blk = (hawk_nde_blk_t*)cha->action;
 | 
						|
 | 
						|
	if (!ptn)
 | 
						|
	{
 | 
						|
		/* just execute the block */
 | 
						|
		rtx->active_block = blk;
 | 
						|
		if (run_block(rtx, blk) <= -1) return -1;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (!ptn->next)
 | 
						|
		{
 | 
						|
			/* pattern { ... } */
 | 
						|
			hawk_val_t* v1;
 | 
						|
 | 
						|
			v1 = eval_expression(rtx, ptn);
 | 
						|
			if (HAWK_UNLIKELY(!v1)) return -1;
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, v1);
 | 
						|
 | 
						|
			if (hawk_rtx_valtobool(rtx, v1))
 | 
						|
			{
 | 
						|
				rtx->active_block = blk;
 | 
						|
				if (run_block(rtx, blk) <= -1)
 | 
						|
				{
 | 
						|
					hawk_rtx_refdownval(rtx, v1);
 | 
						|
					return -1;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refdownval(rtx, v1);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			/* pattern, pattern { ... } */
 | 
						|
			HAWK_ASSERT(ptn->next->next == HAWK_NULL);
 | 
						|
			HAWK_ASSERT(rtx->pattern_range_state != HAWK_NULL);
 | 
						|
 | 
						|
			if (rtx->pattern_range_state[bno] == 0)
 | 
						|
			{
 | 
						|
				hawk_val_t* v1;
 | 
						|
 | 
						|
				v1 = eval_expression(rtx, ptn);
 | 
						|
				if (HAWK_UNLIKELY(!v1)) return -1;
 | 
						|
				hawk_rtx_refupval(rtx, v1);
 | 
						|
				rtx->pattern_range_state[bno] = hawk_rtx_valtobool(rtx, v1);
 | 
						|
				hawk_rtx_refdownval(rtx, v1);
 | 
						|
			}
 | 
						|
 | 
						|
			if (rtx->pattern_range_state[bno] == 1)
 | 
						|
			{
 | 
						|
				hawk_val_t* v2;
 | 
						|
 | 
						|
				v2 = eval_expression(rtx, ptn->next);
 | 
						|
				if (HAWK_UNLIKELY(!v2)) return -1;
 | 
						|
				hawk_rtx_refupval(rtx, v2);
 | 
						|
				rtx->pattern_range_state[bno] = !hawk_rtx_valtobool(rtx, v2);
 | 
						|
				hawk_rtx_refdownval(rtx, v2);
 | 
						|
 | 
						|
				rtx->active_block = blk;
 | 
						|
				if (run_block(rtx, blk) <= -1) return -1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int run_block0 (hawk_rtx_t* rtx, hawk_nde_blk_t* nde)
 | 
						|
{
 | 
						|
	hawk_nde_t* p;
 | 
						|
	/*hawk_oow_t saved_stack_top;*/
 | 
						|
	int n = 0;
 | 
						|
 | 
						|
	if (nde == HAWK_NULL)
 | 
						|
	{
 | 
						|
		/* blockless pattern - execute print $0*/
 | 
						|
		hawk_rtx_refupval(rtx, rtx->inrec.d0);
 | 
						|
 | 
						|
		n = hawk_rtx_writeiostr(rtx, HAWK_OUT_CONSOLE, HAWK_T(""), HAWK_OOECS_PTR(&rtx->inrec.line), HAWK_OOECS_LEN(&rtx->inrec.line));
 | 
						|
		if (n <= -1)
 | 
						|
		{
 | 
						|
			hawk_rtx_refdownval(rtx, rtx->inrec.d0);
 | 
						|
			/* ADJERR_LOC(rtx, &nde->loc); - can't adjust error location as nde is null */
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
 | 
						|
		n = hawk_rtx_writeiostr(rtx, HAWK_OUT_CONSOLE, HAWK_T(""), rtx->gbl.ors.ptr, rtx->gbl.ors.len);
 | 
						|
		if (n <= -1)
 | 
						|
		{
 | 
						|
			hawk_rtx_refdownval(rtx, rtx->inrec.d0);
 | 
						|
			/* ADJERR_LOC(rtx, &nde->loc); - can't adjust error location as nde is null */
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
 | 
						|
		hawk_rtx_refdownval(rtx, rtx->inrec.d0);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	HAWK_ASSERT(nde->type == HAWK_NDE_BLK);
 | 
						|
	/*saved_stack_top = rtx->stack_top;*/
 | 
						|
 | 
						|
#if defined(DEBUG_RUN)
 | 
						|
	hawk_logbfmt (hawk_rtx_gethawk(rtx), "securing space for local variables nlcls = %d\n", (int)nde->nlcls);
 | 
						|
#endif
 | 
						|
 | 
						|
	if (nde->nlcls > 0)
 | 
						|
	{
 | 
						|
		hawk_oow_t tmp = nde->nlcls;
 | 
						|
 | 
						|
		/* ensure sufficient space for local variables */
 | 
						|
		if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < tmp))
 | 
						|
		{
 | 
						|
			hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_ESTACK);
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
 | 
						|
		do
 | 
						|
		{
 | 
						|
			--tmp;
 | 
						|
			HAWK_RTX_STACK_PUSH(rtx, hawk_val_nil);
 | 
						|
			/* refupval is not required for hawk_val_nil */
 | 
						|
		}
 | 
						|
		while (tmp > 0);
 | 
						|
	}
 | 
						|
	else if (nde->nlcls != nde->org_nlcls)
 | 
						|
	{
 | 
						|
		/* this part can be reached if:
 | 
						|
		 *   - the block is nested
 | 
						|
		 *   - the block declares local variables
 | 
						|
		 *   - the local variables have been migrated to the outer-most block by the parser.
 | 
						|
		 *
 | 
						|
		 * if the parser skips migrations, this part isn't reached but the normal push/pop
 | 
						|
		 * will take place for a nested block with local variable declaration.
 | 
						|
		 */
 | 
						|
		hawk_oow_t tmp, end;
 | 
						|
 | 
						|
		/* when the outer-most block has been entered, the space large enough for all local
 | 
						|
		 * variables defined has been secured. nullify part of the stack to initialze local
 | 
						|
		 * variables defined for a nested block */
 | 
						|
		end = nde->outer_nlcls + nde->org_nlcls;
 | 
						|
		for (tmp = nde->outer_nlcls; tmp < end; tmp++)
 | 
						|
		{
 | 
						|
			hawk_rtx_refdownval(rtx, HAWK_RTX_STACK_LCL(rtx, tmp));
 | 
						|
			HAWK_RTX_STACK_LCL(rtx, tmp) = hawk_val_nil;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
#if defined(DEBUG_RUN)
 | 
						|
	hawk_logbfmt (hawk_rtx_gethawk(rtx), "executing block statements\n");
 | 
						|
#endif
 | 
						|
 | 
						|
	p = nde->body;
 | 
						|
	while (p && rtx->exit_level == EXIT_NONE)
 | 
						|
	{
 | 
						|
		if (HAWK_UNLIKELY(run_statement(rtx, p) <= -1))
 | 
						|
		{
 | 
						|
			n = -1;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		p = p->next;
 | 
						|
	}
 | 
						|
 | 
						|
	/* pop off local variables */
 | 
						|
#if defined(DEBUG_RUN)
 | 
						|
	hawk_logbfmt (hawk_rtx_gethawk(rtx), "popping off local variables\n");
 | 
						|
#endif
 | 
						|
 | 
						|
	if (nde->nlcls > 0)
 | 
						|
	{
 | 
						|
		hawk_oow_t tmp = nde->nlcls;
 | 
						|
 | 
						|
		do
 | 
						|
		{
 | 
						|
			--tmp;
 | 
						|
			hawk_rtx_refdownval(rtx, HAWK_RTX_STACK_LCL(rtx, tmp));
 | 
						|
			HAWK_RTX_STACK_POP (rtx);
 | 
						|
		}
 | 
						|
		while (tmp > 0);
 | 
						|
	}
 | 
						|
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
static int run_block (hawk_rtx_t* rtx, hawk_nde_blk_t* nde)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
 | 
						|
	if (rtx->hawk->opt.depth.s.block_run > 0 &&
 | 
						|
	    rtx->depth.block >= rtx->hawk->opt.depth.s.block_run)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EBLKNST);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	rtx->depth.block++;
 | 
						|
	n = run_block0(rtx, nde);
 | 
						|
	rtx->depth.block--;
 | 
						|
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
#define ON_STATEMENT(rtx,nde) do { \
 | 
						|
	hawk_rtx_ecb_t* ecb, * ecb_next; \
 | 
						|
	if ((rtx)->hawk->haltall) (rtx)->exit_level = EXIT_ABORT; \
 | 
						|
	for (ecb = (rtx)->ecb; ecb != (hawk_rtx_ecb_t*)(rtx); ecb = ecb_next) { \
 | 
						|
		ecb_next = ecb->next; \
 | 
						|
		if (ecb->stmt) ecb->stmt(rtx, nde, ecb->ctx);  \
 | 
						|
	} \
 | 
						|
} while(0)
 | 
						|
 | 
						|
static int run_statement (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	int xret;
 | 
						|
	hawk_val_t* tmp;
 | 
						|
 | 
						|
	ON_STATEMENT(rtx, nde);
 | 
						|
 | 
						|
	switch (nde->type)
 | 
						|
	{
 | 
						|
		case HAWK_NDE_NULL:
 | 
						|
			/* do nothing */
 | 
						|
			xret = 0;
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_BLK:
 | 
						|
			xret = run_block(rtx, (hawk_nde_blk_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_IF:
 | 
						|
			xret = run_if(rtx, (hawk_nde_if_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_SWITCH:
 | 
						|
			xret = run_switch(rtx, (hawk_nde_switch_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_CASE:
 | 
						|
			/* this must never happen - run_swtich must handle this part */
 | 
						|
			HAWK_ASSERT(!"should never happen - HAWK_NDE_CASE must not be fed to run_statement");
 | 
						|
			hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EINTERN);
 | 
						|
			xret = -1;
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_WHILE:
 | 
						|
		case HAWK_NDE_DOWHILE:
 | 
						|
			xret = run_while(rtx, (hawk_nde_while_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_FOR:
 | 
						|
			xret = run_for(rtx, (hawk_nde_for_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_FORIN:
 | 
						|
			xret = run_forin(rtx, (hawk_nde_forin_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_BREAK:
 | 
						|
			xret = run_break(rtx, (hawk_nde_break_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_CONTINUE:
 | 
						|
			xret = run_continue(rtx, (hawk_nde_continue_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_RETURN:
 | 
						|
			xret = run_return(rtx, (hawk_nde_return_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_EXIT:
 | 
						|
			xret = run_exit(rtx, (hawk_nde_exit_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_NEXT:
 | 
						|
			xret = run_next(rtx, (hawk_nde_next_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_NEXTFILE:
 | 
						|
			xret = run_nextfile(rtx, (hawk_nde_nextfile_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_DELETE:
 | 
						|
			xret = run_delete(rtx, (hawk_nde_delete_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_RESET:
 | 
						|
			xret = run_reset(rtx, (hawk_nde_reset_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_PRINT:
 | 
						|
			if (rtx->hawk->opt.trait & HAWK_TOLERANT) goto __fallback__;
 | 
						|
			xret = run_print(rtx, (hawk_nde_print_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_PRINTF:
 | 
						|
			if (rtx->hawk->opt.trait & HAWK_TOLERANT) goto __fallback__;
 | 
						|
			xret = run_printf(rtx, (hawk_nde_print_t*)nde);
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
		__fallback__:
 | 
						|
			tmp = eval_expression(rtx, nde);
 | 
						|
			if (HAWK_UNLIKELY(!tmp)) xret = -1;
 | 
						|
			else
 | 
						|
			{
 | 
						|
				/* destroy the value if not referenced */
 | 
						|
				hawk_rtx_refupval(rtx, tmp);
 | 
						|
				hawk_rtx_refdownval(rtx, tmp);
 | 
						|
				xret = 0;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	return xret;
 | 
						|
}
 | 
						|
 | 
						|
static int run_if (hawk_rtx_t* rtx, hawk_nde_if_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* test;
 | 
						|
	int n = 0;
 | 
						|
 | 
						|
	/* the test expression for the if statement cannot have
 | 
						|
	 * chained expressions. this should not be allowed by the
 | 
						|
	 * parser first of all */
 | 
						|
	HAWK_ASSERT(nde->test->next == HAWK_NULL);
 | 
						|
 | 
						|
	test = eval_expression(rtx, nde->test);
 | 
						|
	if (HAWK_UNLIKELY(!test)) return -1;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, test);
 | 
						|
	if (hawk_rtx_valtobool(rtx, test))
 | 
						|
	{
 | 
						|
		n = run_statement(rtx, nde->then_part);
 | 
						|
	}
 | 
						|
	else if (nde->else_part)
 | 
						|
	{
 | 
						|
		n = run_statement(rtx, nde->else_part);
 | 
						|
	}
 | 
						|
 | 
						|
	hawk_rtx_refdownval(rtx, test); /* TODO: is this correct?*/
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
static int run_switch (hawk_rtx_t* rtx, hawk_nde_switch_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* test;
 | 
						|
	hawk_val_t* v;
 | 
						|
	hawk_nde_case_t* case_part;
 | 
						|
	hawk_nde_case_t* default_part;
 | 
						|
	int eval_true = 0;
 | 
						|
	int ret = 0;
 | 
						|
 | 
						|
	/* the expression for the switch statement cannot have
 | 
						|
	 * chained expressions. this should not be allowed by the
 | 
						|
	 * parser first of all */
 | 
						|
	HAWK_ASSERT(nde->type == HAWK_NDE_SWITCH);
 | 
						|
	HAWK_ASSERT(nde->test->next == HAWK_NULL);
 | 
						|
 | 
						|
	test = eval_expression(rtx, nde->test);
 | 
						|
	if (HAWK_UNLIKELY(!test)) return -1;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, test);
 | 
						|
 | 
						|
	case_part = (hawk_nde_case_t*)nde->case_part;
 | 
						|
	default_part = (hawk_nde_case_t*)nde->default_part;
 | 
						|
	HAWK_ASSERT(case_part->type == HAWK_NDE_CASE);
 | 
						|
	HAWK_ASSERT(default_part->type == HAWK_NDE_CASE);
 | 
						|
 | 
						|
	while (case_part)
 | 
						|
	{
 | 
						|
		int x;
 | 
						|
 | 
						|
		if (eval_true) goto skip_eval;
 | 
						|
		if (case_part->val) // skip the default part.
 | 
						|
		{
 | 
						|
			v = eval_expression(rtx, case_part->val);
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
			x = hawk_rtx_cmpval(rtx, test, v, &ret);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			if (x <= -1)
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, test);
 | 
						|
				return -1;
 | 
						|
			}
 | 
						|
			if (ret == 0)
 | 
						|
			{
 | 
						|
			skip_eval:
 | 
						|
				eval_true = 1;
 | 
						|
				if (case_part->action)
 | 
						|
				{
 | 
						|
					hawk_nde_t* action;
 | 
						|
 | 
						|
					action = case_part->action;
 | 
						|
					do
 | 
						|
					{
 | 
						|
						if (run_statement(rtx, action) <= -1)
 | 
						|
						{
 | 
						|
							ret = -1;
 | 
						|
							goto done;
 | 
						|
						}
 | 
						|
 | 
						|
						if (rtx->exit_level == EXIT_BREAK) /* if 'break' has been executed */
 | 
						|
						{
 | 
						|
							rtx->exit_level = EXIT_NONE;
 | 
						|
							goto done;
 | 
						|
						}
 | 
						|
						else if (rtx->exit_level != EXIT_NONE) goto done;
 | 
						|
 | 
						|
						action = action->next;
 | 
						|
					}
 | 
						|
					while(action);
 | 
						|
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		case_part = (hawk_nde_case_t*)case_part->next;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!eval_true && default_part)
 | 
						|
	{
 | 
						|
		case_part = default_part;
 | 
						|
		do
 | 
						|
		{
 | 
						|
			if (case_part->action)
 | 
						|
			{
 | 
						|
				hawk_nde_t* action;
 | 
						|
 | 
						|
				action = case_part->action;
 | 
						|
				do
 | 
						|
				{
 | 
						|
					if (run_statement(rtx, action) <= -1)
 | 
						|
					{
 | 
						|
						ret = -1;
 | 
						|
						goto done;
 | 
						|
					}
 | 
						|
 | 
						|
					if (rtx->exit_level == EXIT_BREAK) /* if 'break' has been executed */
 | 
						|
					{
 | 
						|
						rtx->exit_level = EXIT_NONE;
 | 
						|
						goto done;
 | 
						|
					}
 | 
						|
					else if (rtx->exit_level != EXIT_NONE) goto done;
 | 
						|
 | 
						|
					action = action->next;
 | 
						|
				}
 | 
						|
				while (action);
 | 
						|
			}
 | 
						|
			case_part = (hawk_nde_case_t*)case_part->next;
 | 
						|
		}
 | 
						|
		while (case_part);
 | 
						|
	}
 | 
						|
 | 
						|
done:
 | 
						|
	hawk_rtx_refdownval(rtx, test);
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
static int run_while (hawk_rtx_t* rtx, hawk_nde_while_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* test;
 | 
						|
 | 
						|
	if (nde->type == HAWK_NDE_WHILE)
 | 
						|
	{
 | 
						|
		/* no chained expressions are allowed for the test
 | 
						|
		 * expression of the while statement */
 | 
						|
		HAWK_ASSERT(nde->test->next == HAWK_NULL);
 | 
						|
 | 
						|
		while (1)
 | 
						|
		{
 | 
						|
			ON_STATEMENT(rtx, nde->test);
 | 
						|
 | 
						|
			test = eval_expression(rtx, nde->test);
 | 
						|
			if (HAWK_UNLIKELY(!test)) return -1;
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, test);
 | 
						|
 | 
						|
			if (hawk_rtx_valtobool(rtx, test))
 | 
						|
			{
 | 
						|
				if (run_statement(rtx,nde->body) <= -1)
 | 
						|
				{
 | 
						|
					hawk_rtx_refdownval(rtx, test);
 | 
						|
					return -1;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, test);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refdownval(rtx, test);
 | 
						|
 | 
						|
			if (rtx->exit_level == EXIT_BREAK)
 | 
						|
			{
 | 
						|
				rtx->exit_level = EXIT_NONE;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			else if (rtx->exit_level == EXIT_CONTINUE)
 | 
						|
			{
 | 
						|
				rtx->exit_level = EXIT_NONE;
 | 
						|
			}
 | 
						|
			else if (rtx->exit_level != EXIT_NONE) break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else if (nde->type == HAWK_NDE_DOWHILE)
 | 
						|
	{
 | 
						|
		/* no chained expressions are allowed for the test
 | 
						|
		 * expression of the while statement */
 | 
						|
		HAWK_ASSERT(nde->test->next == HAWK_NULL);
 | 
						|
 | 
						|
		do
 | 
						|
		{
 | 
						|
			if (run_statement(rtx,nde->body) <= -1) return -1;
 | 
						|
 | 
						|
			if (rtx->exit_level == EXIT_BREAK)
 | 
						|
			{
 | 
						|
				rtx->exit_level = EXIT_NONE;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			else if (rtx->exit_level == EXIT_CONTINUE)
 | 
						|
			{
 | 
						|
				rtx->exit_level = EXIT_NONE;
 | 
						|
			}
 | 
						|
			else if (rtx->exit_level != EXIT_NONE) break;
 | 
						|
 | 
						|
			ON_STATEMENT(rtx, nde->test);
 | 
						|
 | 
						|
			test = eval_expression(rtx, nde->test);
 | 
						|
			if (HAWK_UNLIKELY(!test)) return -1;
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, test);
 | 
						|
 | 
						|
			if (!hawk_rtx_valtobool(rtx, test))
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, test);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refdownval(rtx, test);
 | 
						|
		}
 | 
						|
		while (1);
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int run_for (hawk_rtx_t* rtx, hawk_nde_for_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* val;
 | 
						|
 | 
						|
	if (nde->init)
 | 
						|
	{
 | 
						|
		HAWK_ASSERT(nde->init->next == HAWK_NULL);
 | 
						|
 | 
						|
		ON_STATEMENT(rtx, nde->init);
 | 
						|
		val = eval_expression(rtx,nde->init);
 | 
						|
		if (HAWK_UNLIKELY(!val)) return -1;
 | 
						|
 | 
						|
		hawk_rtx_refupval(rtx, val);
 | 
						|
		hawk_rtx_refdownval(rtx, val);
 | 
						|
	}
 | 
						|
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		if (nde->test)
 | 
						|
		{
 | 
						|
			hawk_val_t* test;
 | 
						|
 | 
						|
			/* no chained expressions for the test expression of
 | 
						|
			 * the for statement are allowed */
 | 
						|
			HAWK_ASSERT(nde->test->next == HAWK_NULL);
 | 
						|
 | 
						|
			ON_STATEMENT(rtx, nde->test);
 | 
						|
			test = eval_expression(rtx, nde->test);
 | 
						|
			if (HAWK_UNLIKELY(!test)) return -1;
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, test);
 | 
						|
			if (hawk_rtx_valtobool(rtx, test))
 | 
						|
			{
 | 
						|
				if (run_statement(rtx, nde->body) <= -1)
 | 
						|
				{
 | 
						|
					hawk_rtx_refdownval(rtx, test);
 | 
						|
					return -1;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, test);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refdownval(rtx, test);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (run_statement(rtx,nde->body) <= -1) return -1;
 | 
						|
		}
 | 
						|
 | 
						|
		if (rtx->exit_level == EXIT_BREAK)
 | 
						|
		{
 | 
						|
			rtx->exit_level = EXIT_NONE;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		else if (rtx->exit_level == EXIT_CONTINUE)
 | 
						|
		{
 | 
						|
			rtx->exit_level = EXIT_NONE;
 | 
						|
		}
 | 
						|
		else if (rtx->exit_level != EXIT_NONE) break;
 | 
						|
 | 
						|
		if (nde->incr != HAWK_NULL)
 | 
						|
		{
 | 
						|
			HAWK_ASSERT(nde->incr->next == HAWK_NULL);
 | 
						|
 | 
						|
			ON_STATEMENT(rtx, nde->incr);
 | 
						|
			val = eval_expression(rtx, nde->incr);
 | 
						|
			if (HAWK_UNLIKELY(!val)) return -1;
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, val);
 | 
						|
			hawk_rtx_refdownval(rtx, val);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int run_forin (hawk_rtx_t* rtx, hawk_nde_forin_t* nde)
 | 
						|
{
 | 
						|
	hawk_nde_exp_t* test;
 | 
						|
	hawk_val_t* rv;
 | 
						|
	hawk_val_type_t rvtype;
 | 
						|
 | 
						|
	int ret;
 | 
						|
 | 
						|
	test = (hawk_nde_exp_t*)nde->test;
 | 
						|
	HAWK_ASSERT(test->type == HAWK_NDE_EXP_BIN && test->opcode == HAWK_BINOP_IN);
 | 
						|
 | 
						|
	/* chained expressions should not be allowed by the parser first of all */
 | 
						|
	HAWK_ASSERT(test->right->next == HAWK_NULL);
 | 
						|
 | 
						|
	rv = eval_expression(rtx, test->right);
 | 
						|
	if (HAWK_UNLIKELY(!rv)) return -1;
 | 
						|
 | 
						|
	ret = 0;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, rv);
 | 
						|
	rvtype = HAWK_RTX_GETVALTYPE(rtx, rv);
 | 
						|
	switch (rvtype)
 | 
						|
	{
 | 
						|
		case HAWK_VAL_NIL:
 | 
						|
			/* just return without excuting the loop body */
 | 
						|
			goto done1;
 | 
						|
 | 
						|
		case HAWK_VAL_MAP:
 | 
						|
		{
 | 
						|
			hawk_map_t* map;
 | 
						|
			hawk_map_pair_t* pair;
 | 
						|
			hawk_map_itr_t itr;
 | 
						|
			hawk_oow_t old_forin_size, i;
 | 
						|
 | 
						|
			map = ((hawk_val_map_t*)rv)->map;
 | 
						|
 | 
						|
			old_forin_size = rtx->forin.size;
 | 
						|
			if (rtx->forin.capa - rtx->forin.size < hawk_map_getsize(map))
 | 
						|
			{
 | 
						|
				hawk_val_t** tmp;
 | 
						|
				hawk_oow_t newcapa;
 | 
						|
 | 
						|
				newcapa = rtx->forin.size + hawk_map_getsize(map);
 | 
						|
				newcapa = HAWK_ALIGN_POW2(newcapa, 128);
 | 
						|
				tmp = hawk_rtx_reallocmem(rtx, rtx->forin.ptr, newcapa * HAWK_SIZEOF(*tmp));
 | 
						|
				if (HAWK_UNLIKELY(!tmp))
 | 
						|
				{
 | 
						|
					ADJERR_LOC(rtx, &test->left->loc);
 | 
						|
					ret = -1;
 | 
						|
					goto done2;
 | 
						|
				}
 | 
						|
 | 
						|
				rtx->forin.ptr = tmp;
 | 
						|
				rtx->forin.capa = newcapa;
 | 
						|
			}
 | 
						|
 | 
						|
			/* take a snapshot of the keys first so that the actual pairs become mutation safe
 | 
						|
			 * this proctection is needed in case the body contains destructive statements like 'delete' or '@reset'*/
 | 
						|
			hawk_init_map_itr (&itr, 0);
 | 
						|
			pair = hawk_map_getfirstpair(map, &itr);
 | 
						|
			while (pair)
 | 
						|
			{
 | 
						|
				hawk_val_t* str;
 | 
						|
 | 
						|
				str = (hawk_val_t*)hawk_rtx_makenstrvalwithoochars(rtx, HAWK_HTB_KPTR(pair), HAWK_HTB_KLEN(pair));
 | 
						|
				if (HAWK_UNLIKELY(!str))
 | 
						|
				{
 | 
						|
					ADJERR_LOC(rtx, &test->left->loc);
 | 
						|
					ret = -1;
 | 
						|
					goto done2;
 | 
						|
				}
 | 
						|
 | 
						|
				rtx->forin.ptr[rtx->forin.size++] = str;
 | 
						|
				hawk_rtx_refupval(rtx, str);
 | 
						|
 | 
						|
				pair = hawk_map_getnextpair(map, &itr);
 | 
						|
			}
 | 
						|
 | 
						|
			/* iterate over the keys in the snapshot */
 | 
						|
			for (i = old_forin_size;  i < rtx->forin.size; i++)
 | 
						|
			{
 | 
						|
				if (HAWK_UNLIKELY(!do_assignment(rtx, test->left, rtx->forin.ptr[i])) || HAWK_UNLIKELY(run_statement(rtx, nde->body) <= -1))
 | 
						|
				{
 | 
						|
					ret = -1;
 | 
						|
					goto done2;
 | 
						|
				}
 | 
						|
 | 
						|
				if (rtx->exit_level == EXIT_BREAK)
 | 
						|
				{
 | 
						|
					rtx->exit_level = EXIT_NONE;
 | 
						|
					goto done2;
 | 
						|
				}
 | 
						|
				else if (rtx->exit_level == EXIT_CONTINUE)
 | 
						|
				{
 | 
						|
					rtx->exit_level = EXIT_NONE;
 | 
						|
				}
 | 
						|
				else if (rtx->exit_level != EXIT_NONE)
 | 
						|
				{
 | 
						|
					goto done2;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
		done2:
 | 
						|
			while (rtx->forin.size > old_forin_size)
 | 
						|
				hawk_rtx_refdownval(rtx, rtx->forin.ptr[--rtx->forin.size]);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_VAL_ARR:
 | 
						|
		{
 | 
						|
			hawk_arr_t* arr;
 | 
						|
			hawk_oow_t arr_size;
 | 
						|
			hawk_oow_t old_forin_size, i;
 | 
						|
 | 
						|
			arr = ((hawk_val_arr_t*)rv)->arr;
 | 
						|
			arr_size = HAWK_ARR_SIZE(arr);
 | 
						|
 | 
						|
			old_forin_size = rtx->forin.size;
 | 
						|
			if (rtx->forin.capa - rtx->forin.size < hawk_arr_getsize(arr))
 | 
						|
			{
 | 
						|
				hawk_val_t** tmp;
 | 
						|
				hawk_oow_t newcapa;
 | 
						|
 | 
						|
				newcapa = rtx->forin.size + hawk_arr_getsize(arr);
 | 
						|
				newcapa = HAWK_ALIGN_POW2(newcapa, 128);
 | 
						|
				tmp = hawk_rtx_reallocmem(rtx, rtx->forin.ptr, newcapa * HAWK_SIZEOF(*tmp));
 | 
						|
				if (HAWK_UNLIKELY(!tmp))
 | 
						|
				{
 | 
						|
					ADJERR_LOC(rtx, &test->left->loc);
 | 
						|
					ret = -1;
 | 
						|
					goto done3;
 | 
						|
				}
 | 
						|
 | 
						|
				rtx->forin.ptr = tmp;
 | 
						|
				rtx->forin.capa = newcapa;
 | 
						|
			}
 | 
						|
 | 
						|
			/* take a snapshot of the keys first so that the actual pairs become mutation safe
 | 
						|
			 * this proctection is needed in case the body contains destructive statements like 'delete' or '@reset'.
 | 
						|
			 * besides, there can be empty slots. after a[1] = 20; a[9] = 30;,  a[2], a[3], etc are empty. */
 | 
						|
			for  (i = 0; i < arr_size; i++)
 | 
						|
			{
 | 
						|
				if (HAWK_ARR_SLOT(arr, i))
 | 
						|
				{
 | 
						|
					hawk_val_t* tmp;
 | 
						|
 | 
						|
					tmp = (hawk_val_t*)hawk_rtx_makeintval(rtx, i);
 | 
						|
					if (HAWK_UNLIKELY(!tmp))
 | 
						|
					{
 | 
						|
						ADJERR_LOC(rtx, &test->left->loc);
 | 
						|
						ret = -1;
 | 
						|
						goto done3;
 | 
						|
					}
 | 
						|
 | 
						|
					rtx->forin.ptr[rtx->forin.size++] = tmp;
 | 
						|
					hawk_rtx_refupval(rtx, tmp);
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			/* iterate over the keys in the snapshot */
 | 
						|
			for (i = old_forin_size;  i < rtx->forin.size; i++)
 | 
						|
			{
 | 
						|
				if (HAWK_UNLIKELY(!do_assignment(rtx, test->left, rtx->forin.ptr[i])) || HAWK_UNLIKELY(run_statement(rtx, nde->body) <= -1))
 | 
						|
				{
 | 
						|
					ret = -1;
 | 
						|
					goto done3;
 | 
						|
				}
 | 
						|
 | 
						|
				if (rtx->exit_level == EXIT_BREAK)
 | 
						|
				{
 | 
						|
					rtx->exit_level = EXIT_NONE;
 | 
						|
					goto done3;
 | 
						|
				}
 | 
						|
				else if (rtx->exit_level == EXIT_CONTINUE)
 | 
						|
				{
 | 
						|
					rtx->exit_level = EXIT_NONE;
 | 
						|
				}
 | 
						|
				else if (rtx->exit_level != EXIT_NONE)
 | 
						|
				{
 | 
						|
					goto done3;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
		done3:
 | 
						|
			while (rtx->forin.size > old_forin_size)
 | 
						|
				hawk_rtx_refdownval(rtx, rtx->forin.ptr[--rtx->forin.size]);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		default:
 | 
						|
			hawk_rtx_seterrnum(rtx, &test->right->loc, HAWK_EINROP);
 | 
						|
			ret = -1;
 | 
						|
			goto done1;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
done1:
 | 
						|
	hawk_rtx_refdownval(rtx, rv);
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
static int run_break (hawk_rtx_t* rtx, hawk_nde_break_t* nde)
 | 
						|
{
 | 
						|
	rtx->exit_level = EXIT_BREAK;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int run_continue (hawk_rtx_t* rtx, hawk_nde_continue_t* nde)
 | 
						|
{
 | 
						|
	rtx->exit_level = EXIT_CONTINUE;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int run_return (hawk_rtx_t* rtx, hawk_nde_return_t* nde)
 | 
						|
{
 | 
						|
	if (nde->val)
 | 
						|
	{
 | 
						|
		hawk_val_t* val;
 | 
						|
 | 
						|
		/* chained expressions should not be allowed
 | 
						|
		 * by the parser first of all */
 | 
						|
		HAWK_ASSERT(nde->val->next == HAWK_NULL);
 | 
						|
 | 
						|
		val = eval_expression(rtx, nde->val);
 | 
						|
		if (HAWK_UNLIKELY(!val)) return -1;
 | 
						|
 | 
						|
		if (!(rtx->hawk->opt.trait & HAWK_FLEXMAP))
 | 
						|
		{
 | 
						|
			hawk_val_type_t vtype = HAWK_RTX_GETVALTYPE(rtx, val);
 | 
						|
 | 
						|
			if (vtype == HAWK_VAL_MAP || vtype == HAWK_VAL_ARR)
 | 
						|
			{
 | 
						|
				/* cannot return a map */
 | 
						|
				hawk_rtx_refupval(rtx, val);
 | 
						|
				hawk_rtx_refdownval(rtx, val);
 | 
						|
				hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_ENONSCARET);
 | 
						|
				return -1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		hawk_rtx_refdownval(rtx, HAWK_RTX_STACK_RETVAL(rtx));
 | 
						|
		HAWK_RTX_STACK_RETVAL(rtx) = val;
 | 
						|
 | 
						|
		/* NOTE: see eval_call() for the trick */
 | 
						|
		hawk_rtx_refupval(rtx, val);
 | 
						|
	}
 | 
						|
 | 
						|
	rtx->exit_level = EXIT_FUNCTION;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int run_exit (hawk_rtx_t* rtx, hawk_nde_exit_t* nde)
 | 
						|
{
 | 
						|
	if (nde->val)
 | 
						|
	{
 | 
						|
		hawk_val_t* val;
 | 
						|
 | 
						|
		/* chained expressions should not be allowed
 | 
						|
		 * by the parser first of all */
 | 
						|
		HAWK_ASSERT(nde->val->next == HAWK_NULL);
 | 
						|
 | 
						|
		val = eval_expression(rtx, nde->val);
 | 
						|
		if (HAWK_UNLIKELY(!val)) return -1;
 | 
						|
 | 
						|
		hawk_rtx_refdownval(rtx, HAWK_RTX_STACK_RETVAL_GBL(rtx));
 | 
						|
		HAWK_RTX_STACK_RETVAL_GBL(rtx) = val; /* global return value */
 | 
						|
 | 
						|
		hawk_rtx_refupval(rtx, val);
 | 
						|
	}
 | 
						|
 | 
						|
	rtx->exit_level = (nde->abort)? EXIT_ABORT: EXIT_GLOBAL;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int run_next (hawk_rtx_t* rtx, hawk_nde_next_t* nde)
 | 
						|
{
 | 
						|
	/* the parser checks if next has been called in the begin/end
 | 
						|
	 * block or whereever inappropriate. so the rtxtime doesn't
 | 
						|
	 * check that explicitly */
 | 
						|
	if  (rtx->active_block == (hawk_nde_blk_t*)rtx->hawk->tree.begin)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_ERNEXTBEG);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
	else if (rtx->active_block == (hawk_nde_blk_t*)rtx->hawk->tree.end)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_ERNEXTEND);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	rtx->exit_level = EXIT_NEXT;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int run_nextinfile (hawk_rtx_t* rtx, hawk_nde_nextfile_t* nde)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
 | 
						|
	/* normal nextfile statement */
 | 
						|
	if  (rtx->active_block == (hawk_nde_blk_t*)rtx->hawk->tree.begin)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_ERNEXTFBEG);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
	else if (rtx->active_block == (hawk_nde_blk_t*)rtx->hawk->tree.end)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_ERNEXTFEND);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	n = hawk_rtx_nextio_read(rtx, HAWK_IN_CONSOLE, HAWK_T(""));
 | 
						|
	if (n <= -1)
 | 
						|
	{
 | 
						|
		ADJERR_LOC(rtx, &nde->loc);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (n == 0)
 | 
						|
	{
 | 
						|
		/* no more input console */
 | 
						|
		rtx->exit_level = EXIT_GLOBAL;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* FNR resets to 0, NR remains the same */
 | 
						|
	if (update_fnr(rtx, 0, rtx->gbl.nr) <= -1)
 | 
						|
	{
 | 
						|
		ADJERR_LOC(rtx, &nde->loc);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	rtx->exit_level = EXIT_NEXT;
 | 
						|
	return 0;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static int run_nextoutfile (hawk_rtx_t* rtx, hawk_nde_nextfile_t* nde)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
 | 
						|
	/* nextofile can be called from BEGIN and END block unlike nextfile */
 | 
						|
 | 
						|
	n = hawk_rtx_nextio_write(rtx, HAWK_OUT_CONSOLE, HAWK_T(""));
 | 
						|
	if (n <= -1)
 | 
						|
	{
 | 
						|
		/* adjust the error line */
 | 
						|
		ADJERR_LOC(rtx, &nde->loc);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (n == 0)
 | 
						|
	{
 | 
						|
		/* should it terminate the program there is no more
 | 
						|
		 * output console? no. there will just be no more console
 | 
						|
		 * output */
 | 
						|
		/*rtx->exit_level = EXIT_GLOBAL;*/
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int run_nextfile (hawk_rtx_t* rtx, hawk_nde_nextfile_t* nde)
 | 
						|
{
 | 
						|
	return (nde->out)? run_nextoutfile(rtx, nde): run_nextinfile(rtx, nde);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static hawk_val_t* assign_newmapval_in_map (hawk_rtx_t* rtx, hawk_map_t* container, hawk_ooch_t* idxptr, hawk_oow_t idxlen)
 | 
						|
{
 | 
						|
	hawk_val_t* tmp;
 | 
						|
	hawk_map_pair_t* pair;
 | 
						|
 | 
						|
	tmp = hawk_rtx_makemapval(rtx);
 | 
						|
	if (HAWK_UNLIKELY(!tmp)) return HAWK_NULL;
 | 
						|
 | 
						|
	/* as this is the assignment, it needs to update the reference count of the target value. */
 | 
						|
	hawk_rtx_refupval(rtx, tmp);
 | 
						|
	pair = hawk_map_upsert(container, idxptr, idxlen, tmp, 0);
 | 
						|
	if (HAWK_UNLIKELY(!pair))
 | 
						|
	{
 | 
						|
		hawk_rtx_refdownval(rtx, tmp);  /* decrement upon upsert() failure */
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	HAWK_ASSERT(tmp == HAWK_MAP_VPTR(pair));
 | 
						|
	return tmp;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* assign_newarrval_in_arr (hawk_rtx_t* rtx, hawk_arr_t* container, hawk_ooi_t idx)
 | 
						|
{
 | 
						|
	hawk_val_t* tmp;
 | 
						|
 | 
						|
	tmp = hawk_rtx_makearrval(rtx, -1);
 | 
						|
	if (HAWK_UNLIKELY(!tmp)) return HAWK_NULL;
 | 
						|
 | 
						|
	/* as this is the assignment, it needs to update the reference count of the target value. */
 | 
						|
	hawk_rtx_refupval(rtx, tmp);
 | 
						|
	if (HAWK_UNLIKELY(hawk_arr_upsert(container, idx, tmp, 0) == HAWK_ARR_NIL))
 | 
						|
	{
 | 
						|
		hawk_rtx_refdownval(rtx, tmp);  /* decrement upon upsert() failure */
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
	return tmp;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* fetch_topval_from_var (hawk_rtx_t* rtx, hawk_nde_var_t* var)
 | 
						|
{
 | 
						|
	hawk_val_t* val;
 | 
						|
 | 
						|
	switch (var->type)
 | 
						|
	{
 | 
						|
 | 
						|
		case HAWK_NDE_NAMED:
 | 
						|
		case HAWK_NDE_NAMEDIDX:
 | 
						|
		{
 | 
						|
			hawk_htb_pair_t* pair;
 | 
						|
			pair = hawk_htb_search(rtx->named, var->id.name.ptr, var->id.name.len);
 | 
						|
			val = pair? (hawk_val_t*)HAWK_HTB_VPTR(pair): hawk_val_nil;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_NDE_GBL:
 | 
						|
		case HAWK_NDE_GBLIDX:
 | 
						|
			val = HAWK_RTX_STACK_GBL(rtx, var->id.idxa);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_LCL:
 | 
						|
		case HAWK_NDE_LCLIDX:
 | 
						|
			val = HAWK_RTX_STACK_LCL(rtx, var->id.idxa);
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			HAWK_ASSERT(var->type == HAWK_NDE_ARG || var->type == HAWK_NDE_ARGIDX);
 | 
						|
			val = HAWK_RTX_STACK_ARG(rtx, var->id.idxa);
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* assign_topval_to_var (hawk_rtx_t* rtx, hawk_nde_var_t* var, hawk_val_t* val)
 | 
						|
{
 | 
						|
	switch (var->type)
 | 
						|
	{
 | 
						|
		case HAWK_NDE_NAMED:
 | 
						|
		case HAWK_NDE_NAMEDIDX:
 | 
						|
		{
 | 
						|
			/* doesn't have to decrease the reference count
 | 
						|
			 * of the previous value here as it is done by
 | 
						|
			 * hawk_htb_upsert */
 | 
						|
			hawk_rtx_refupval(rtx, val);
 | 
						|
			if (HAWK_UNLIKELY(hawk_htb_upsert(rtx->named, var->id.name.ptr, var->id.name.len, val, 0) == HAWK_NULL))
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, val);
 | 
						|
				ADJERR_LOC(rtx, &var->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_NDE_GBL:
 | 
						|
		case HAWK_NDE_GBLIDX:
 | 
						|
		{
 | 
						|
			int x;
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, val);
 | 
						|
			x = hawk_rtx_setgbl(rtx, (int)var->id.idxa, val);
 | 
						|
			hawk_rtx_refdownval(rtx, val);
 | 
						|
			if (HAWK_UNLIKELY(x <= -1))
 | 
						|
			{
 | 
						|
				ADJERR_LOC(rtx, &var->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_NDE_LCL:
 | 
						|
		case HAWK_NDE_LCLIDX:
 | 
						|
		{
 | 
						|
			hawk_val_t* old;
 | 
						|
			old = HAWK_RTX_STACK_LCL(rtx,var->id.idxa);
 | 
						|
			hawk_rtx_refdownval(rtx, old);
 | 
						|
			HAWK_RTX_STACK_LCL(rtx,var->id.idxa) = val;
 | 
						|
			hawk_rtx_refupval(rtx, val);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		default: /* HAWK_NDE_ARG, HAWK_NDE_ARGIDX */
 | 
						|
		{
 | 
						|
			hawk_val_t* old;
 | 
						|
			old = HAWK_RTX_STACK_ARG(rtx,var->id.idxa);
 | 
						|
			hawk_rtx_refdownval(rtx, old);
 | 
						|
			HAWK_RTX_STACK_ARG(rtx,var->id.idxa) = val;
 | 
						|
			hawk_rtx_refupval(rtx, val);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* assign_newmapval_to_var (hawk_rtx_t* rtx, hawk_nde_var_t* var)
 | 
						|
{
 | 
						|
	hawk_val_t* tmp;
 | 
						|
 | 
						|
	HAWK_ASSERT(var->type >= HAWK_NDE_NAMED && var->type <= HAWK_NDE_ARGIDX);
 | 
						|
 | 
						|
	tmp = hawk_rtx_makemapval(rtx);
 | 
						|
	if (HAWK_UNLIKELY(!tmp))
 | 
						|
	{
 | 
						|
		ADJERR_LOC(rtx, &var->loc);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return assign_topval_to_var(rtx, var, tmp);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static HAWK_INLINE int delete_indexed (hawk_rtx_t* rtx, hawk_val_t* vv, hawk_nde_var_t* var)
 | 
						|
{
 | 
						|
	hawk_map_t* map;
 | 
						|
	hawk_ooch_t* str = HAWK_NULL;
 | 
						|
	hawk_oow_t len;
 | 
						|
	hawk_ooch_t idxbuf[HAWK_IDX_BUF_SIZE];
 | 
						|
 | 
						|
	hawk_arr_t* arr;
 | 
						|
	hawk_ooi_t idx;
 | 
						|
 | 
						|
	hawk_nde_t* remidx;
 | 
						|
	hawk_val_type_t vtype;
 | 
						|
 | 
						|
	HAWK_ASSERT(var->idx != HAWK_NULL);
 | 
						|
 | 
						|
	/* delete x["abc"];
 | 
						|
	 * delete x[20,"abc"]; */
 | 
						|
 | 
						|
	vtype = HAWK_RTX_GETVALTYPE(rtx, vv);
 | 
						|
	if (vtype == HAWK_VAL_MAP)
 | 
						|
	{
 | 
						|
		len = HAWK_COUNTOF(idxbuf);
 | 
						|
		str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx, HAWK_NULL);
 | 
						|
		if (HAWK_UNLIKELY(!str)) goto oops;
 | 
						|
		map = ((hawk_val_map_t*)vv)->map;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		HAWK_ASSERT(vtype == HAWK_VAL_ARR);
 | 
						|
		idx = idxnde_to_int(rtx, var->idx, &remidx);
 | 
						|
		if (HAWK_UNLIKELY(idx <= -1)) goto oops;
 | 
						|
		arr = ((hawk_val_arr_t*)vv)->arr;
 | 
						|
	}
 | 
						|
 | 
						|
#if defined(HAWK_ENABLE_GC)
 | 
						|
	while (remidx)
 | 
						|
	{
 | 
						|
		hawk_val_type_t container_vtype;
 | 
						|
 | 
						|
		if (vtype == HAWK_VAL_MAP)
 | 
						|
		{
 | 
						|
			hawk_map_pair_t* pair;
 | 
						|
			pair = hawk_map_search(map, str, len);
 | 
						|
			vv = pair? (hawk_val_t*)HAWK_MAP_VPTR(pair): hawk_val_nil;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			vv = (idx < HAWK_ARR_SIZE(arr) && HAWK_ARR_SLOT(arr, idx))? ((hawk_val_t*)HAWK_ARR_DPTR(arr, idx)): hawk_val_nil;
 | 
						|
		}
 | 
						|
		container_vtype = vtype;
 | 
						|
		vtype = HAWK_RTX_GETVALTYPE(rtx, vv);
 | 
						|
 | 
						|
		switch (vtype)
 | 
						|
		{
 | 
						|
			case HAWK_VAL_MAP:
 | 
						|
			val_map:
 | 
						|
				if (str && str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
				len = HAWK_COUNTOF(idxbuf);
 | 
						|
				str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx, HAWK_NULL);
 | 
						|
				if (HAWK_UNLIKELY(!str)) goto oops;
 | 
						|
				map = ((hawk_val_map_t*)vv)->map;
 | 
						|
				break;
 | 
						|
 | 
						|
			case HAWK_VAL_ARR:
 | 
						|
			val_arr:
 | 
						|
				idx = idxnde_to_int(rtx, remidx, &remidx);
 | 
						|
				if (HAWK_UNLIKELY(idx <= -1)) goto oops;
 | 
						|
				arr = ((hawk_val_arr_t*)vv)->arr;
 | 
						|
				break;
 | 
						|
 | 
						|
			default:
 | 
						|
				if (vtype == HAWK_VAL_NIL || (rtx->hawk->opt.trait & HAWK_FLEXMAP))
 | 
						|
				{
 | 
						|
					if (container_vtype == HAWK_VAL_MAP)
 | 
						|
					{
 | 
						|
						vv = assign_newmapval_in_map(rtx, map, str, len);
 | 
						|
						if (HAWK_UNLIKELY(!vv)) { ADJERR_LOC(rtx, &var->loc); goto oops; }
 | 
						|
						vtype = HAWK_VAL_MAP;
 | 
						|
						goto val_map;
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						vv = assign_newarrval_in_arr(rtx, arr, idx);
 | 
						|
						if (HAWK_UNLIKELY(!vv)) { ADJERR_LOC(rtx, &var->loc); goto oops; }
 | 
						|
						vtype = HAWK_VAL_ARR;
 | 
						|
						goto val_arr;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					hawk_rtx_seterrfmt(rtx, &var->loc, HAWK_ENOTDEL, HAWK_T("nested scalar value under '%.*js' not deletable"), var->id.name.len, var->id.name.ptr);
 | 
						|
					goto oops;
 | 
						|
				}
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	if (vtype == HAWK_VAL_MAP)
 | 
						|
		hawk_map_delete (map, str, len);
 | 
						|
	else
 | 
						|
		hawk_arr_uplete (arr, idx,  1); /* no reindexing by compaction. keep the place unset */
 | 
						|
 | 
						|
	if (str && str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
	return 0;
 | 
						|
 | 
						|
oops:
 | 
						|
	if (str && str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
	return -1;
 | 
						|
}
 | 
						|
 | 
						|
static int run_delete (hawk_rtx_t* rtx, hawk_nde_delete_t* nde)
 | 
						|
{
 | 
						|
	hawk_nde_var_t* var;
 | 
						|
	hawk_val_t* val;
 | 
						|
	hawk_val_type_t vtype;
 | 
						|
 | 
						|
	var = (hawk_nde_var_t*)nde->var;
 | 
						|
 | 
						|
	val = fetch_topval_from_var(rtx, var);
 | 
						|
	HAWK_ASSERT(val != HAWK_NULL);
 | 
						|
 | 
						|
	vtype = HAWK_RTX_GETVALTYPE(rtx, val);
 | 
						|
	switch (vtype)
 | 
						|
	{
 | 
						|
		case HAWK_VAL_NIL:
 | 
						|
			/* value not set. create a map and assign it to the variable */
 | 
						|
			if (HAWK_UNLIKELY(assign_newmapval_to_var(rtx, var) == HAWK_NULL)) goto oops;
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_VAL_MAP:
 | 
						|
			if (var->type == HAWK_NDE_NAMEDIDX || var->type == HAWK_NDE_GBLIDX ||
 | 
						|
			    var->type == HAWK_NDE_LCLIDX || var->type == HAWK_NDE_ARGIDX)
 | 
						|
			{
 | 
						|
				if (delete_indexed(rtx, val, var) <= -1) goto oops;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				/*
 | 
						|
				BEGIN {
 | 
						|
				  @local a;
 | 
						|
				  a[1] = 20; a[2] = "hello"; a[3][4][5]="ttt";
 | 
						|
				  print typename(a), length(a);
 | 
						|
				  delete a;
 | 
						|
				  print typename(a), length(a);
 | 
						|
				}
 | 
						|
				*/
 | 
						|
				hawk_map_clear (((hawk_val_map_t*)val)->map);
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_VAL_ARR:
 | 
						|
			if (var->type == HAWK_NDE_NAMEDIDX || var->type == HAWK_NDE_GBLIDX ||
 | 
						|
			    var->type == HAWK_NDE_LCLIDX || var->type == HAWK_NDE_ARGIDX)
 | 
						|
			{
 | 
						|
				if (delete_indexed(rtx, val, var) <= -1) goto oops;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				hawk_arr_clear (((hawk_val_arr_t*)val)->arr);
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			hawk_rtx_seterrfmt(rtx, &var->loc, HAWK_ENOTDEL, HAWK_T("'%.*js' not deletable"), var->id.name.len, var->id.name.ptr);
 | 
						|
			goto oops;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
 | 
						|
oops:
 | 
						|
	ADJERR_LOC(rtx, &var->loc);
 | 
						|
	return -1;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static int run_reset (hawk_rtx_t* rtx, hawk_nde_reset_t* nde)
 | 
						|
{
 | 
						|
	hawk_nde_var_t* var;
 | 
						|
 | 
						|
	var = (hawk_nde_var_t*)nde->var;
 | 
						|
 | 
						|
	HAWK_ASSERT(var->type >= HAWK_NDE_NAMED && var->type <= HAWK_NDE_ARG);
 | 
						|
 | 
						|
	switch (var->type)
 | 
						|
	{
 | 
						|
		case HAWK_NDE_NAMED:
 | 
						|
			/* if a named variable has an index part, something is definitely wrong */
 | 
						|
			HAWK_ASSERT(var->idx == HAWK_NULL);
 | 
						|
 | 
						|
			/* a named variable can be reset if removed from the internal map to manage it */
 | 
						|
			hawk_htb_delete (rtx->named, var->id.name.ptr, var->id.name.len);
 | 
						|
			return 0;
 | 
						|
 | 
						|
		case HAWK_NDE_GBL:
 | 
						|
		case HAWK_NDE_LCL:
 | 
						|
		case HAWK_NDE_ARG:
 | 
						|
		{
 | 
						|
			hawk_val_t* val;
 | 
						|
 | 
						|
			HAWK_ASSERT(var->idx == HAWK_NULL);
 | 
						|
 | 
						|
			val = fetch_topval_from_var(rtx, var);
 | 
						|
			HAWK_ASSERT(val != HAWK_NULL);
 | 
						|
 | 
						|
			if (HAWK_RTX_GETVALTYPE(rtx, val) != HAWK_VAL_NIL)
 | 
						|
			{
 | 
						|
				assign_topval_to_var(rtx, var, hawk_val_nil); /* this must not fail */
 | 
						|
			}
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
 | 
						|
		default:
 | 
						|
			/* the reset statement can only be called with plain variables */
 | 
						|
			HAWK_ASSERT(!"should never happen - wrong target for @reset");
 | 
						|
			hawk_rtx_seterrnum(rtx, &var->loc, HAWK_EBADARG);
 | 
						|
			return -1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* io_nde_to_str(hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_oocs_t* dst, int seterr)
 | 
						|
{
 | 
						|
	hawk_val_t* v;
 | 
						|
 | 
						|
	v = eval_expression(rtx, nde);
 | 
						|
	if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, v);
 | 
						|
	dst->ptr = hawk_rtx_getvaloocstr(rtx, v, &dst->len);
 | 
						|
	if (HAWK_UNLIKELY(!dst))
 | 
						|
	{
 | 
						|
		hawk_rtx_refdownval(rtx, v);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (seterr && dst->len <= 0)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrfmt(rtx, &nde->loc, HAWK_EIONMEM, HAWK_T("empty I/O name"));
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		hawk_oow_t len;
 | 
						|
 | 
						|
		len = dst->len;
 | 
						|
		while (len > 0)
 | 
						|
		{
 | 
						|
			if (dst->ptr[--len] == '\0')
 | 
						|
			{
 | 
						|
				hawk_rtx_seterrfmt(rtx, &nde->loc, HAWK_EIONMNL, HAWK_T("invalid I/O name of length %zu containing '\\0'"), dst->len);
 | 
						|
				dst->len = 0; /* indicate that the name is not valid */
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return v;
 | 
						|
}
 | 
						|
 | 
						|
static int run_print (hawk_rtx_t* rtx, hawk_nde_print_t* nde)
 | 
						|
{
 | 
						|
	hawk_oocs_t out;
 | 
						|
	hawk_val_t* out_v = HAWK_NULL;
 | 
						|
	int n, xret = 0;
 | 
						|
 | 
						|
	HAWK_ASSERT(
 | 
						|
		(nde->out_type == HAWK_OUT_PIPE && nde->out != HAWK_NULL) ||
 | 
						|
		(nde->out_type == HAWK_OUT_RWPIPE && nde->out != HAWK_NULL) ||
 | 
						|
		(nde->out_type == HAWK_OUT_FILE && nde->out != HAWK_NULL) ||
 | 
						|
		(nde->out_type == HAWK_OUT_APFILE && nde->out != HAWK_NULL) ||
 | 
						|
		(nde->out_type == HAWK_OUT_CONSOLE && nde->out == HAWK_NULL));
 | 
						|
 | 
						|
	/* check if destination has been specified. */
 | 
						|
	if (nde->out)
 | 
						|
	{
 | 
						|
		out_v = io_nde_to_str(rtx, nde->out, &out, 1);
 | 
						|
		if (!out_v || out.len <= 0) goto oops_1;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		out.ptr = (hawk_ooch_t*)HAWK_T("");
 | 
						|
		out.len = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* check if print is followed by any arguments */
 | 
						|
	if (!nde->args)
 | 
						|
	{
 | 
						|
		/* if it doesn't have any arguments, print the entire input record */
 | 
						|
		n = hawk_rtx_writeiostr(rtx, nde->out_type, out.ptr, HAWK_OOECS_PTR(&rtx->inrec.line), HAWK_OOECS_LEN(&rtx->inrec.line));
 | 
						|
		if (n <= -1 /*&& rtx->errinf.num != HAWK_EIOIMPL*/)
 | 
						|
		{
 | 
						|
			if (rtx->hawk->opt.trait & HAWK_TOLERANT)
 | 
						|
			{
 | 
						|
				xret = PRINT_IOERR;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				goto oops;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		/* if it has any arguments, print the arguments separated by
 | 
						|
		 * the value OFS */
 | 
						|
		hawk_nde_t* head, * np;
 | 
						|
		hawk_val_t* v;
 | 
						|
 | 
						|
		if (nde->args->type == HAWK_NDE_GRP)
 | 
						|
		{
 | 
						|
			/* parenthesized print */
 | 
						|
			HAWK_ASSERT(nde->args->next == HAWK_NULL);
 | 
						|
			head = ((hawk_nde_grp_t*)nde->args)->body;
 | 
						|
		}
 | 
						|
		else head = nde->args;
 | 
						|
 | 
						|
		for (np = head; np != HAWK_NULL; np = np->next)
 | 
						|
		{
 | 
						|
			if (np != head)
 | 
						|
			{
 | 
						|
				n = hawk_rtx_writeiostr(rtx, nde->out_type, out.ptr, rtx->gbl.ofs.ptr, rtx->gbl.ofs.len);
 | 
						|
				if (n <= -1 /*&& rtx->errinf.num != HAWK_EIOIMPL*/)
 | 
						|
				{
 | 
						|
					if (rtx->hawk->opt.trait & HAWK_TOLERANT)
 | 
						|
					{
 | 
						|
						xret = PRINT_IOERR;
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						goto oops;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			v = eval_expression(rtx, np);
 | 
						|
			if (HAWK_UNLIKELY(!v)) goto oops_1;
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
			n = hawk_rtx_writeioval(rtx, nde->out_type, out.ptr, v);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
 | 
						|
			if (n <= -1 /*&& rtx->errinf.num != HAWK_EIOIMPL*/)
 | 
						|
			{
 | 
						|
				if (rtx->hawk->opt.trait & HAWK_TOLERANT)
 | 
						|
				{
 | 
						|
					xret = PRINT_IOERR;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					goto oops;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* print the value ORS to terminate the operation */
 | 
						|
	n = hawk_rtx_writeiostr(rtx, nde->out_type, out.ptr, rtx->gbl.ors.ptr, rtx->gbl.ors.len);
 | 
						|
	if (n <= -1 /*&& rtx->errinf.num != HAWK_EIOIMPL*/)
 | 
						|
	{
 | 
						|
		if (rtx->hawk->opt.trait & HAWK_TOLERANT)
 | 
						|
		{
 | 
						|
			xret = PRINT_IOERR;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			goto oops;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* unlike printf, flushio() is not needed here as print
 | 
						|
	 * inserts <NL> that triggers auto-flush */
 | 
						|
	if (out_v)
 | 
						|
	{
 | 
						|
		hawk_rtx_freevaloocstr(rtx, out_v, out.ptr);
 | 
						|
		hawk_rtx_refdownval(rtx, out_v);
 | 
						|
	}
 | 
						|
 | 
						|
	return xret;
 | 
						|
 | 
						|
oops:
 | 
						|
	ADJERR_LOC(rtx, &nde->loc);
 | 
						|
 | 
						|
oops_1:
 | 
						|
	if (out_v)
 | 
						|
	{
 | 
						|
		hawk_rtx_freevaloocstr(rtx, out_v, out.ptr);
 | 
						|
		hawk_rtx_refdownval(rtx, out_v);
 | 
						|
	}
 | 
						|
 | 
						|
	return -1;
 | 
						|
}
 | 
						|
 | 
						|
static int run_printf (hawk_rtx_t* rtx, hawk_nde_print_t* nde)
 | 
						|
{
 | 
						|
	hawk_oocs_t out;
 | 
						|
	hawk_val_t* out_v = HAWK_NULL;
 | 
						|
	hawk_val_t* v;
 | 
						|
	hawk_val_type_t vtype;
 | 
						|
	hawk_nde_t* head;
 | 
						|
	int n, xret = 0;
 | 
						|
 | 
						|
	HAWK_ASSERT(
 | 
						|
		(nde->out_type == HAWK_OUT_PIPE && nde->out != HAWK_NULL) ||
 | 
						|
		(nde->out_type == HAWK_OUT_RWPIPE && nde->out != HAWK_NULL) ||
 | 
						|
		(nde->out_type == HAWK_OUT_FILE && nde->out != HAWK_NULL) ||
 | 
						|
		(nde->out_type == HAWK_OUT_APFILE && nde->out != HAWK_NULL) ||
 | 
						|
		(nde->out_type == HAWK_OUT_CONSOLE && nde->out == HAWK_NULL));
 | 
						|
 | 
						|
	if (nde->out)
 | 
						|
	{
 | 
						|
		out_v = io_nde_to_str(rtx, nde->out, &out, 1);
 | 
						|
		if (!out_v || out.len <= 0) goto oops_1;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		out.ptr = (hawk_ooch_t*)HAWK_T("");
 | 
						|
		out.len = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/*( valid printf statement should have at least one argument. the parser must ensure this. */
 | 
						|
	HAWK_ASSERT(nde->args != HAWK_NULL);
 | 
						|
 | 
						|
	if (nde->args->type == HAWK_NDE_GRP)
 | 
						|
	{
 | 
						|
		/* parenthesized print */
 | 
						|
		HAWK_ASSERT(nde->args->next == HAWK_NULL);
 | 
						|
		head = ((hawk_nde_grp_t*)nde->args)->body;
 | 
						|
	}
 | 
						|
	else head = nde->args;
 | 
						|
 | 
						|
	/* valid printf statement should have at least one argument. the parser must ensure this */
 | 
						|
	HAWK_ASSERT(head != HAWK_NULL);
 | 
						|
 | 
						|
	v = eval_expression(rtx, head);
 | 
						|
	if (HAWK_UNLIKELY(!v)) goto oops_1;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, v);
 | 
						|
	vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | 
						|
	switch (vtype)
 | 
						|
	{
 | 
						|
		case HAWK_VAL_STR:
 | 
						|
			/* perform the formatted output */
 | 
						|
			n = output_formatted(rtx, nde->out_type, out.ptr, ((hawk_val_str_t*)v)->val.ptr, ((hawk_val_str_t*)v)->val.len, head->next);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			if (n <= -1)
 | 
						|
			{
 | 
						|
				if (n == PRINT_IOERR) xret = n;
 | 
						|
				else goto oops;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_VAL_MBS:
 | 
						|
			/* perform the formatted output */
 | 
						|
			n = output_formatted_bytes(rtx, nde->out_type, out.ptr, ((hawk_val_mbs_t*)v)->val.ptr, ((hawk_val_mbs_t*)v)->val.len, head->next);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			if (n <= -1)
 | 
						|
			{
 | 
						|
				if (n == PRINT_IOERR) xret = n;
 | 
						|
				else goto oops;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_VAL_BOB:
 | 
						|
			n = output_formatted_bytes(rtx, nde->out_type, out.ptr, ((hawk_val_bob_t*)v)->val.ptr, ((hawk_val_bob_t*)v)->val.len, head->next);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			if (n <= -1)
 | 
						|
			{
 | 
						|
				if (n == PRINT_IOERR) xret = n;
 | 
						|
				else goto oops;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			/* the remaining arguments are ignored as the format cannot
 | 
						|
			 * contain any % characters. e.g. printf (1, "xxxx") */
 | 
						|
			n = hawk_rtx_writeioval(rtx, nde->out_type, out.ptr, v);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
 | 
						|
			if (n <= -1 /*&& rtx->errinf.num != HAWK_EIOIMPL*/)
 | 
						|
			{
 | 
						|
				if (rtx->hawk->opt.trait & HAWK_TOLERANT) xret = PRINT_IOERR;
 | 
						|
				else goto oops;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	if (hawk_rtx_flushio(rtx, nde->out_type, out.ptr) <= -1)
 | 
						|
	{
 | 
						|
		if (rtx->hawk->opt.trait & HAWK_TOLERANT) xret = PRINT_IOERR;
 | 
						|
		else goto oops_1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (out_v)
 | 
						|
	{
 | 
						|
		hawk_rtx_freevaloocstr(rtx, out_v, out.ptr);
 | 
						|
		hawk_rtx_refdownval(rtx, out_v);
 | 
						|
	}
 | 
						|
 | 
						|
	return xret;
 | 
						|
 | 
						|
oops:
 | 
						|
	ADJERR_LOC(rtx, &nde->loc);
 | 
						|
 | 
						|
oops_1:
 | 
						|
	if (out_v)
 | 
						|
	{
 | 
						|
		hawk_rtx_freevaloocstr(rtx, out_v, out.ptr);
 | 
						|
		hawk_rtx_refdownval(rtx, out_v);
 | 
						|
	}
 | 
						|
 | 
						|
	return -1;
 | 
						|
}
 | 
						|
 | 
						|
static int output_formatted (
 | 
						|
	hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_ooch_t* dst,
 | 
						|
	const hawk_ooch_t* fmt, hawk_oow_t fmt_len, hawk_nde_t* args)
 | 
						|
{
 | 
						|
	hawk_ooch_t* ptr;
 | 
						|
	hawk_oow_t len;
 | 
						|
	int n;
 | 
						|
 | 
						|
	ptr = hawk_rtx_format(rtx, HAWK_NULL, HAWK_NULL, fmt, fmt_len, 0, args, &len);
 | 
						|
	if (!ptr) return -1;
 | 
						|
 | 
						|
	n = hawk_rtx_writeiostr(rtx, out_type, dst, ptr, len);
 | 
						|
	if (n <= -1 /*&& rtx->errinf.num != HAWK_EIOIMPL*/)
 | 
						|
	{
 | 
						|
		return (rtx->hawk->opt.trait & HAWK_TOLERANT)? PRINT_IOERR: -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int output_formatted_bytes (
 | 
						|
	hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_ooch_t* dst,
 | 
						|
	const hawk_bch_t* fmt, hawk_oow_t fmt_len, hawk_nde_t* args)
 | 
						|
{
 | 
						|
	hawk_bch_t* ptr;
 | 
						|
	hawk_oow_t len;
 | 
						|
	int n;
 | 
						|
 | 
						|
	ptr = hawk_rtx_formatmbs(rtx, HAWK_NULL, HAWK_NULL, fmt, fmt_len, 0, args, &len);
 | 
						|
	if (!ptr) return -1;
 | 
						|
 | 
						|
	n = hawk_rtx_writeiobytes(rtx, out_type, dst, ptr, len);
 | 
						|
	if (n <= -1 /*&& rtx->errinf.num != HAWK_EIOIMPL*/)
 | 
						|
	{
 | 
						|
		return (rtx->hawk->opt.trait & HAWK_TOLERANT)? PRINT_IOERR: -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_expression (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* v;
 | 
						|
	int n;
 | 
						|
 | 
						|
#if 0
 | 
						|
	if (rtx->exit_level >= EXIT_GLOBAL)
 | 
						|
	{
 | 
						|
		/* returns HAWK_NULL as if an error occurred but
 | 
						|
		 * clears the error number. run_main will
 | 
						|
		 * detect this condition and treat it as a
 | 
						|
		 * non-error condition.*/
 | 
						|
		rtx->errinf.num = HAWK_ENOERR;
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	v = eval_expression0(rtx, nde);
 | 
						|
	if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
 | 
						|
	if (HAWK_RTX_GETVALTYPE(rtx, v) == HAWK_VAL_REX)
 | 
						|
	{
 | 
						|
		hawk_oocs_t vs;
 | 
						|
		int free_vs = 0;
 | 
						|
 | 
						|
		/* special case where a regular expression is used in
 | 
						|
		 * without any match operators:
 | 
						|
		 *    print /abc/;
 | 
						|
		 * perform match against $0.
 | 
						|
		 */
 | 
						|
		hawk_rtx_refupval(rtx, v);
 | 
						|
 | 
						|
		if (HAWK_RTX_GETVALTYPE(rtx, rtx->inrec.d0) == HAWK_VAL_NIL)
 | 
						|
		{
 | 
						|
			/* the record has never been read.
 | 
						|
			 * probably, this function has been triggered
 | 
						|
			 * by the statements in the BEGIN block */
 | 
						|
			vs.ptr = HAWK_T("");
 | 
						|
			vs.len = 0;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
		#if 0
 | 
						|
			/* the internal value representing $0 should always be of the string type
 | 
						|
			 * once it has been set/updated. it is nil initially. */
 | 
						|
			HAWK_ASSERT(HAWK_RTX_GETVALTYPE(rtx, rtx->inrec.d0) == HAWK_VAL_STR);
 | 
						|
			vs.ptr = ((hawk_val_str_t*)rtx->inrec.d0)->val.ptr;
 | 
						|
			vs.len = ((hawk_val_str_t*)rtx->inrec.d0)->val.len;
 | 
						|
		#else
 | 
						|
			vs.ptr = hawk_rtx_getvaloocstr(rtx, rtx->inrec.d0, &vs.len);
 | 
						|
			if (!vs.ptr)
 | 
						|
			{
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				hawk_rtx_refdownval(rtx, v);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			free_vs  = 1;
 | 
						|
		#endif
 | 
						|
		}
 | 
						|
 | 
						|
		n = hawk_rtx_matchvalwithoocs(rtx, v, &vs, &vs, HAWK_NULL, HAWK_NULL);
 | 
						|
		hawk_rtx_refdownval(rtx, v);
 | 
						|
		if (free_vs) hawk_rtx_freevaloocstr(rtx, rtx->inrec.d0, vs.ptr);
 | 
						|
		if (n <= -1)
 | 
						|
		{
 | 
						|
			ADJERR_LOC(rtx, &nde->loc);
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
 | 
						|
		v = hawk_rtx_makeintval(rtx, (n != 0));
 | 
						|
		HAWK_ASSERT(v != HAWK_NULL); /* this will never fail as the value is 0 or 1 */
 | 
						|
	}
 | 
						|
 | 
						|
	return v;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_expression0 (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	static eval_expr_t __evaluator[] =
 | 
						|
	{
 | 
						|
		/* the order of functions here should match the order
 | 
						|
		 * of node types(hawk_nde_type_t) declared in hawk.h */
 | 
						|
		eval_group,
 | 
						|
		eval_assignment,
 | 
						|
		eval_binary,
 | 
						|
		eval_unary,
 | 
						|
		eval_incpre,
 | 
						|
		eval_incpst,
 | 
						|
		eval_cnd,
 | 
						|
		eval_fncall_fnc,
 | 
						|
		eval_fncall_fun,
 | 
						|
		eval_fncall_var,
 | 
						|
		eval_char,
 | 
						|
		eval_bchr,
 | 
						|
		eval_int,
 | 
						|
		eval_flt,
 | 
						|
		eval_str,
 | 
						|
		eval_mbs,
 | 
						|
		eval_rex,
 | 
						|
		eval_xnil,
 | 
						|
		eval_xargc,
 | 
						|
		eval_xargv,
 | 
						|
		eval_xargvidx,
 | 
						|
		eval_fun,
 | 
						|
		eval_named,
 | 
						|
		eval_gbl,
 | 
						|
		eval_lcl,
 | 
						|
		eval_arg,
 | 
						|
		eval_namedidx,
 | 
						|
		eval_gblidx,
 | 
						|
		eval_lclidx,
 | 
						|
		eval_argidx,
 | 
						|
		eval_pos,
 | 
						|
		eval_getline,
 | 
						|
		eval_print,
 | 
						|
		eval_printf
 | 
						|
	};
 | 
						|
 | 
						|
	hawk_val_t* v;
 | 
						|
 | 
						|
	HAWK_ASSERT(nde->type >= HAWK_NDE_GRP && (nde->type - HAWK_NDE_GRP) < HAWK_COUNTOF(__evaluator));
 | 
						|
 | 
						|
	v = __evaluator[nde->type - HAWK_NDE_GRP](rtx, nde);
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(v && rtx->exit_level >= EXIT_GLOBAL))
 | 
						|
	{
 | 
						|
		hawk_rtx_refupval(rtx, v);
 | 
						|
		hawk_rtx_refdownval(rtx, v);
 | 
						|
 | 
						|
		/* returns HAWK_NULL as if an error occurred but
 | 
						|
		 * clears the error number. run_main will
 | 
						|
		 * detect this condition and treat it as a
 | 
						|
		 * non-error condition.*/
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_ENOERR);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	/* this function returns a regular expression without further mathiching.
 | 
						|
	 * it is done in eval_expression(). */
 | 
						|
	return v;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_group (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
#if 0
 | 
						|
	/* eval_binop_in evaluates the HAWK_NDE_GRP specially.
 | 
						|
	 * so this function should never be reached. */
 | 
						|
	HAWK_ASSERT(!"should never happen - NDE_GRP only for in");
 | 
						|
	hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EINTERN);
 | 
						|
	return HAWK_NULL;
 | 
						|
#endif
 | 
						|
 | 
						|
	/* a group can be evauluated in a normal context
 | 
						|
	 * if a program is parsed with HAWK_TOLERANT on.
 | 
						|
	 * before the introduction of this option, the grouped
 | 
						|
	 * expression was valid only coerced with the 'in'
 | 
						|
	 * operator.
 | 
						|
	 * */
 | 
						|
 | 
						|
	/* when a group is evaluated in a normal context,
 | 
						|
	 * we return the last expression as a value. */
 | 
						|
 | 
						|
	hawk_val_t* val;
 | 
						|
	hawk_nde_t* np;
 | 
						|
 | 
						|
	np = ((hawk_nde_grp_t*)nde)->body;
 | 
						|
 | 
						|
	HAWK_ASSERT(np != HAWK_NULL);
 | 
						|
 | 
						|
loop:
 | 
						|
	val = eval_expression(rtx, np);
 | 
						|
	if (HAWK_UNLIKELY(!val)) return HAWK_NULL;
 | 
						|
 | 
						|
	np = np->next;
 | 
						|
	if (np)
 | 
						|
	{
 | 
						|
		hawk_rtx_refupval(rtx, val);
 | 
						|
		hawk_rtx_refdownval(rtx, val);
 | 
						|
		goto loop;
 | 
						|
	}
 | 
						|
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_assignment (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* val, * ret;
 | 
						|
	hawk_nde_ass_t* ass = (hawk_nde_ass_t*)nde;
 | 
						|
 | 
						|
	HAWK_ASSERT(ass->left != HAWK_NULL);
 | 
						|
	HAWK_ASSERT(ass->right != HAWK_NULL);
 | 
						|
 | 
						|
	HAWK_ASSERT(ass->right->next == HAWK_NULL);
 | 
						|
	val = eval_expression(rtx, ass->right);
 | 
						|
	if (HAWK_UNLIKELY(!val)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, val);
 | 
						|
 | 
						|
	if (ass->opcode != HAWK_ASSOP_NONE)
 | 
						|
	{
 | 
						|
		hawk_val_t* val2, * tmp;
 | 
						|
		static binop_func_t binop_func[] =
 | 
						|
		{
 | 
						|
			/* this table must match hawk_assop_type_t in rtx.h */
 | 
						|
			HAWK_NULL, /* HAWK_ASSOP_NONE */
 | 
						|
			eval_binop_plus,
 | 
						|
			eval_binop_minus,
 | 
						|
			eval_binop_mul,
 | 
						|
			eval_binop_div,
 | 
						|
			eval_binop_idiv,
 | 
						|
			eval_binop_mod,
 | 
						|
			eval_binop_exp,
 | 
						|
			eval_binop_concat,
 | 
						|
			eval_binop_rshift,
 | 
						|
			eval_binop_lshift,
 | 
						|
			eval_binop_band,
 | 
						|
			eval_binop_bxor,
 | 
						|
			eval_binop_bor
 | 
						|
		};
 | 
						|
 | 
						|
		HAWK_ASSERT(ass->left->next == HAWK_NULL);
 | 
						|
		val2 = eval_expression(rtx, ass->left);
 | 
						|
		if (HAWK_UNLIKELY(!val2))
 | 
						|
		{
 | 
						|
			hawk_rtx_refdownval(rtx, val);
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
 | 
						|
		hawk_rtx_refupval(rtx, val2);
 | 
						|
 | 
						|
		HAWK_ASSERT(ass->opcode >= 0);
 | 
						|
		HAWK_ASSERT(ass->opcode < HAWK_COUNTOF(binop_func));
 | 
						|
		HAWK_ASSERT(binop_func[ass->opcode] != HAWK_NULL);
 | 
						|
 | 
						|
		tmp = binop_func[ass->opcode](rtx, val2, val);
 | 
						|
		if (HAWK_UNLIKELY(!tmp))
 | 
						|
		{
 | 
						|
			hawk_rtx_refdownval(rtx, val2);
 | 
						|
			hawk_rtx_refdownval(rtx, val);
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
 | 
						|
		hawk_rtx_refdownval(rtx, val2);
 | 
						|
		hawk_rtx_refdownval(rtx, val);
 | 
						|
 | 
						|
		val = tmp;
 | 
						|
		hawk_rtx_refupval(rtx, val);
 | 
						|
	}
 | 
						|
 | 
						|
	ret = do_assignment(rtx, ass->left, val);
 | 
						|
	hawk_rtx_refdownval(rtx, val);
 | 
						|
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* do_assignment (hawk_rtx_t* rtx, hawk_nde_t* var, hawk_val_t* val)
 | 
						|
{
 | 
						|
	hawk_val_t* ret;
 | 
						|
	hawk_errnum_t errnum;
 | 
						|
 | 
						|
	switch (var->type)
 | 
						|
	{
 | 
						|
		case HAWK_NDE_NAMED:
 | 
						|
		case HAWK_NDE_GBL:
 | 
						|
		case HAWK_NDE_LCL:
 | 
						|
		case HAWK_NDE_ARG:
 | 
						|
			ret = do_assignment_nonindexed(rtx, (hawk_nde_var_t*)var, val);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_NDE_NAMEDIDX:
 | 
						|
		case HAWK_NDE_GBLIDX:
 | 
						|
		case HAWK_NDE_LCLIDX:
 | 
						|
		case HAWK_NDE_ARGIDX:
 | 
						|
		{
 | 
						|
		#if !defined(HAWK_ENABLE_GC)
 | 
						|
			hawk_val_type_t vtype = HAWK_RTX_GETVALTYPE(rtx, val);
 | 
						|
			if (vtype == HAWK_VAL_MAP || vtype == HAWK_VAL_ARR)
 | 
						|
			{
 | 
						|
				/* a map cannot become a member of a map */
 | 
						|
				errnum = HAWK_ENONSCATOIDX;
 | 
						|
				goto exit_on_error;
 | 
						|
			}
 | 
						|
		#endif
 | 
						|
 | 
						|
			ret = do_assignment_indexed(rtx, (hawk_nde_var_t*)var, val);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_NDE_POS:
 | 
						|
		{
 | 
						|
			hawk_val_type_t vtype = HAWK_RTX_GETVALTYPE(rtx, val);
 | 
						|
			if (vtype == HAWK_VAL_MAP || vtype == HAWK_VAL_ARR)
 | 
						|
			{
 | 
						|
				/* a map cannot be assigned to a positional */
 | 
						|
				errnum = HAWK_ENONSCATOPOS;
 | 
						|
				goto exit_on_error;
 | 
						|
			}
 | 
						|
 | 
						|
			ret = do_assignment_positional(rtx, (hawk_nde_pos_t*)var, val);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		default:
 | 
						|
			HAWK_ASSERT(!"should never happen - invalid variable type");
 | 
						|
			errnum = HAWK_EINTERN;
 | 
						|
			goto exit_on_error;
 | 
						|
	}
 | 
						|
 | 
						|
	return ret;
 | 
						|
 | 
						|
exit_on_error:
 | 
						|
	hawk_rtx_seterrnum(rtx, &var->loc, errnum);
 | 
						|
	return HAWK_NULL;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* do_assignment_nonindexed (hawk_rtx_t* rtx, hawk_nde_var_t* var, hawk_val_t* val)
 | 
						|
{
 | 
						|
	hawk_val_type_t vtype;
 | 
						|
 | 
						|
	HAWK_ASSERT(
 | 
						|
		var->type == HAWK_NDE_NAMED ||
 | 
						|
		var->type == HAWK_NDE_GBL ||
 | 
						|
		var->type == HAWK_NDE_LCL ||
 | 
						|
		var->type == HAWK_NDE_ARG
 | 
						|
	);
 | 
						|
 | 
						|
	HAWK_ASSERT(var->idx == HAWK_NULL);
 | 
						|
	vtype = HAWK_RTX_GETVALTYPE(rtx, val);
 | 
						|
 | 
						|
	switch (var->type)
 | 
						|
	{
 | 
						|
		case HAWK_NDE_NAMED:
 | 
						|
		{
 | 
						|
			hawk_htb_pair_t* pair;
 | 
						|
 | 
						|
			pair = hawk_htb_search(rtx->named, var->id.name.ptr, var->id.name.len);
 | 
						|
 | 
						|
			if (!(rtx->hawk->opt.trait & HAWK_FLEXMAP))
 | 
						|
			{
 | 
						|
				hawk_val_type_t old_vtype;
 | 
						|
				if (pair && ((old_vtype = HAWK_RTX_GETVALTYPE(rtx, (hawk_val_t*)HAWK_HTB_VPTR(pair))) == HAWK_VAL_MAP || old_vtype == HAWK_VAL_ARR))
 | 
						|
				{
 | 
						|
					/* old value is a map - it can only be accessed through indexing. */
 | 
						|
					if (vtype == old_vtype)
 | 
						|
						hawk_rtx_seterrfmt(rtx, &var->loc, HAWK_ENONSCATONONSCA, HAWK_T("not allowed to change a nonscalar value in '%.*js' to another nonscalar value"), var->id.name.len, var->id.name.ptr);
 | 
						|
					else
 | 
						|
						hawk_rtx_seterrfmt(rtx, &var->loc, HAWK_ENONSCATOSCALAR, HAWK_T("not allowed to change a nonscalar value in '%.*js' to a scalar value"), var->id.name.len, var->id.name.ptr);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
				else if (vtype == HAWK_VAL_MAP || vtype == HAWK_VAL_ARR)
 | 
						|
				{
 | 
						|
					/* old value is not a map but a new value is a map.
 | 
						|
					 * a map cannot be assigned to a variable if FLEXMAP is off. */
 | 
						|
					hawk_rtx_seterrfmt(rtx, &var->loc, HAWK_ENONSCATOVAR, HAWK_T("not allowed to assign a nonscalar value to a variable '%.*js'"), var->id.name.len, var->id.name.ptr);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (hawk_htb_upsert(rtx->named, var->id.name.ptr, var->id.name.len, val, 0) == HAWK_NULL)
 | 
						|
			{
 | 
						|
				ADJERR_LOC(rtx, &var->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, val);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_NDE_GBL:
 | 
						|
		{
 | 
						|
			if (set_global(rtx, var->id.idxa, var, val, 1) == -1)
 | 
						|
			{
 | 
						|
				ADJERR_LOC(rtx, &var->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_NDE_LCL:
 | 
						|
		{
 | 
						|
			hawk_val_t* old = HAWK_RTX_STACK_LCL(rtx,var->id.idxa);
 | 
						|
 | 
						|
			if (!(rtx->hawk->opt.trait & HAWK_FLEXMAP))
 | 
						|
			{
 | 
						|
				hawk_val_type_t old_type;
 | 
						|
 | 
						|
				if ((old_type = HAWK_RTX_GETVALTYPE(rtx, old)) == HAWK_VAL_MAP || old_type == HAWK_VAL_ARR)
 | 
						|
				{
 | 
						|
					/* old value is a map - it can only be accessed through indexing. */
 | 
						|
					if (vtype == old_type)
 | 
						|
						hawk_rtx_seterrfmt(rtx, &var->loc, HAWK_ENONSCATONONSCA, HAWK_T("not allowed to change a nonscalar value in '%.*js' to another nonscalar value"), var->id.name.len, var->id.name.ptr);
 | 
						|
					else
 | 
						|
						hawk_rtx_seterrfmt(rtx, &var->loc, HAWK_ENONSCATOSCALAR, HAWK_T("not allowed to change a nonscalar value in '%.*js' to a scalar value"), var->id.name.len, var->id.name.ptr);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
				else if (vtype == HAWK_VAL_MAP || vtype == HAWK_VAL_ARR)
 | 
						|
				{
 | 
						|
					/* old value is not a map but a new value is a map.
 | 
						|
					 * a map cannot be assigned to a variable if FLEXMAP is off. */
 | 
						|
					hawk_rtx_seterrfmt(rtx, &var->loc, HAWK_ENONSCATOVAR, HAWK_T("not allowed to assign a nonscalar value to a variable '%.*js'"), var->id.name.len, var->id.name.ptr);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refdownval(rtx, old);
 | 
						|
			HAWK_RTX_STACK_LCL(rtx,var->id.idxa) = val;
 | 
						|
			hawk_rtx_refupval(rtx, val);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_NDE_ARG:
 | 
						|
		{
 | 
						|
			hawk_val_t* old = HAWK_RTX_STACK_ARG(rtx,var->id.idxa);
 | 
						|
 | 
						|
			if (!(rtx->hawk->opt.trait & HAWK_FLEXMAP))
 | 
						|
			{
 | 
						|
				hawk_val_type_t old_type;
 | 
						|
 | 
						|
				if ((old_type = HAWK_RTX_GETVALTYPE(rtx, old) == HAWK_VAL_MAP) || old_type == HAWK_VAL_ARR)
 | 
						|
				{
 | 
						|
					/* old value is a map - it can only be accessed through indexing. */
 | 
						|
					if (vtype == old_type)
 | 
						|
						hawk_rtx_seterrfmt(rtx, &var->loc, HAWK_ENONSCATONONSCA, HAWK_T("not allowed to change a nonscalar value in '%.*js' to another nonscalar value"), var->id.name.len, var->id.name.ptr);
 | 
						|
					else
 | 
						|
						hawk_rtx_seterrfmt(rtx, &var->loc, HAWK_ENONSCATOSCALAR, HAWK_T("not allowed to change a nonscalar value in '%.*js' to a scalar value"), var->id.name.len, var->id.name.ptr);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
				else if (vtype == HAWK_VAL_MAP || vtype == HAWK_VAL_ARR)
 | 
						|
				{
 | 
						|
					/* old value is not a map but a new value is a map.
 | 
						|
					 * a map cannot be assigned to a variable if FLEXMAP is off. */
 | 
						|
					hawk_rtx_seterrfmt(rtx, &var->loc, HAWK_ENONSCATOVAR, HAWK_T("not allowed to assign a nonscalar value to a variable '%.*js'"), var->id.name.len, var->id.name.ptr);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refdownval(rtx, old);
 | 
						|
			HAWK_RTX_STACK_ARG(rtx,var->id.idxa) = val;
 | 
						|
			hawk_rtx_refupval(rtx, val);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		default:
 | 
						|
			hawk_rtx_seterrnum(rtx, &var->loc, HAWK_EINTERN);
 | 
						|
			return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* do_assignment_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var, hawk_val_t* val)
 | 
						|
{
 | 
						|
	hawk_map_t* map;
 | 
						|
	hawk_ooch_t* str = HAWK_NULL;
 | 
						|
	hawk_oow_t len;
 | 
						|
	hawk_ooch_t idxbuf[HAWK_IDX_BUF_SIZE];
 | 
						|
 | 
						|
	hawk_ooi_t idx;
 | 
						|
	hawk_arr_t* arr;
 | 
						|
 | 
						|
	hawk_nde_t* remidx;
 | 
						|
	hawk_val_t* vv; /* existing value pointed to by var */
 | 
						|
	hawk_val_type_t vtype;
 | 
						|
 | 
						|
	HAWK_ASSERT(
 | 
						|
		(var->type == HAWK_NDE_NAMEDIDX ||
 | 
						|
		 var->type == HAWK_NDE_GBLIDX ||
 | 
						|
		 var->type == HAWK_NDE_LCLIDX ||
 | 
						|
		 var->type == HAWK_NDE_ARGIDX) && var->idx != HAWK_NULL);
 | 
						|
#if !defined(HAWK_ENABLE_GC)
 | 
						|
	HAWK_ASSERT(HAWK_RTX_GETVALTYPE(rtx, val) != HAWK_VAL_MAP &&
 | 
						|
	             HAWK_RTX_GETVALTYPE(rtx, val) != HAWK_VAL_ARR);
 | 
						|
#endif
 | 
						|
 | 
						|
	/* check the value that the assigned variable points to */
 | 
						|
	vv = fetch_topval_from_var(rtx, var);
 | 
						|
	vtype = HAWK_RTX_GETVALTYPE(rtx, vv);
 | 
						|
	switch (vtype)
 | 
						|
	{
 | 
						|
		case HAWK_VAL_MAP:
 | 
						|
		case HAWK_VAL_ARR:
 | 
						|
		{
 | 
						|
		val_map_or_arr:
 | 
						|
			if (vtype == HAWK_VAL_MAP)
 | 
						|
			{
 | 
						|
				len = HAWK_COUNTOF(idxbuf);
 | 
						|
				str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx, HAWK_NULL);
 | 
						|
				if (HAWK_UNLIKELY(!str)) goto oops;
 | 
						|
				map = ((hawk_val_map_t*)vv)->map;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				idx = idxnde_to_int(rtx, var->idx, &remidx);
 | 
						|
				if (idx <= -1) goto oops;
 | 
						|
				arr = ((hawk_val_arr_t*)vv)->arr;
 | 
						|
			}
 | 
						|
 | 
						|
		#if defined(HAWK_ENABLE_GC)
 | 
						|
			while (remidx)
 | 
						|
			{
 | 
						|
				hawk_val_type_t container_vtype;
 | 
						|
 | 
						|
				if (vtype == HAWK_VAL_MAP)
 | 
						|
				{
 | 
						|
					hawk_map_pair_t* pair;
 | 
						|
					pair = hawk_map_search(map, str, len);
 | 
						|
					vv = pair? (hawk_val_t*)HAWK_MAP_VPTR(pair): hawk_val_nil;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					vv = (idx < HAWK_ARR_SIZE(arr) && HAWK_ARR_SLOT(arr, idx))? ((hawk_val_t*)HAWK_ARR_DPTR(arr, idx)): hawk_val_nil;
 | 
						|
				}
 | 
						|
				container_vtype = vtype;
 | 
						|
				vtype = HAWK_RTX_GETVALTYPE(rtx, vv);
 | 
						|
 | 
						|
				switch (vtype)
 | 
						|
				{
 | 
						|
					case HAWK_VAL_MAP:
 | 
						|
					val_map:
 | 
						|
						if (str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
						len = HAWK_COUNTOF(idxbuf);
 | 
						|
						str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx, HAWK_NULL);
 | 
						|
						if (HAWK_UNLIKELY(!str)) goto oops;
 | 
						|
						map = ((hawk_val_map_t*)vv)->map;
 | 
						|
						break;
 | 
						|
 | 
						|
					case HAWK_VAL_ARR:
 | 
						|
					val_arr:
 | 
						|
						idx = idxnde_to_int(rtx, remidx, &remidx);
 | 
						|
						if (idx <= -1) goto oops;
 | 
						|
						arr = ((hawk_val_arr_t*)vv)->arr;
 | 
						|
						break;
 | 
						|
 | 
						|
					default:
 | 
						|
						if (vtype == HAWK_VAL_NIL || (rtx->hawk->opt.trait & HAWK_FLEXMAP))
 | 
						|
						{
 | 
						|
							/* BEGIN { @local a, b; b="hello"; a[1]=b; a[1][2]=20; print a[1][2];} */
 | 
						|
							/* BEGIN { a[1]="hello"; a[1][2]=20; print a[1][2];  } */
 | 
						|
							/* BEGIN { b="hello"; a[1]=b; a[1][2]=20; print a[1][2]; } */
 | 
						|
 | 
						|
							/* well, this is not the first level index.
 | 
						|
							 * the logic is different from the first level where reset_variable is called.
 | 
						|
							 * here it simply creates a new map. */
 | 
						|
							if (container_vtype == HAWK_VAL_MAP)
 | 
						|
							{
 | 
						|
								vv = assign_newmapval_in_map(rtx, map, str, len);
 | 
						|
								if (HAWK_UNLIKELY(!vv)) { ADJERR_LOC(rtx, &var->loc); goto oops; }
 | 
						|
								vtype = HAWK_VAL_MAP;
 | 
						|
								goto val_map;
 | 
						|
							}
 | 
						|
							else
 | 
						|
							{
 | 
						|
								vv = assign_newarrval_in_arr(rtx, arr, idx);
 | 
						|
								if (HAWK_UNLIKELY(!vv)) { ADJERR_LOC(rtx, &var->loc); goto oops; }
 | 
						|
								vtype = HAWK_VAL_ARR;
 | 
						|
								goto val_arr;
 | 
						|
							}
 | 
						|
						}
 | 
						|
						else
 | 
						|
						{
 | 
						|
							hawk_rtx_seterrfmt(rtx, &var->loc, HAWK_ESCALARTONONSCA, HAWK_T("not allowed to change a nested scalar value under '%.*js' to a nonscalar value"), var->id.name.len, var->id.name.ptr);
 | 
						|
							goto oops;
 | 
						|
						}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		#endif
 | 
						|
 | 
						|
		#if defined(DEBUG_RUN)
 | 
						|
			hawk_logbfmt (hawk_rtx_gethawk(rtx), "**** index str=>%js, map->ref=%d, map->type=%d\n", str, (int)v->ref, (int)v->type);
 | 
						|
		#endif
 | 
						|
 | 
						|
			if (vtype == HAWK_VAL_MAP)
 | 
						|
			{
 | 
						|
				if (HAWK_UNLIKELY(hawk_map_upsert(map, str, len, val, 0) == HAWK_NULL))
 | 
						|
				{
 | 
						|
					ADJERR_LOC(rtx, &var->loc);
 | 
						|
					goto oops;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (HAWK_UNLIKELY(hawk_arr_upsert(arr, idx, val, 0) == HAWK_ARR_NIL))
 | 
						|
				{
 | 
						|
					ADJERR_LOC(rtx, &var->loc);
 | 
						|
					goto oops;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, val);
 | 
						|
			if (str && str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
			return val;
 | 
						|
		}
 | 
						|
 | 
						|
		default:
 | 
						|
			if (vtype == HAWK_VAL_NIL || (rtx->hawk->opt.trait & HAWK_FLEXMAP))
 | 
						|
			{
 | 
						|
				/* 1. switch a nil value to a map value at the first level */
 | 
						|
				/* 2. if FLEXMAP is on, you can switch a scalar value to a map value */
 | 
						|
				vv = assign_newmapval_to_var(rtx, var);
 | 
						|
				if (HAWK_UNLIKELY(!vv)) return HAWK_NULL;
 | 
						|
				vtype = HAWK_VAL_MAP;
 | 
						|
				goto val_map_or_arr;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				/* you can't manipulate a variable pointing to
 | 
						|
				 * a scalar value with an index if FLEXMAP is off. */
 | 
						|
				hawk_rtx_seterrfmt(rtx, &var->loc, HAWK_ESCALARTONONSCA, HAWK_T("not allowed to change a scalar value in '%.*js' to a nonscalar value"), var->id.name.len, var->id.name.ptr);
 | 
						|
				goto oops;
 | 
						|
			}
 | 
						|
	}
 | 
						|
 | 
						|
oops:
 | 
						|
	if (str && str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
	return HAWK_NULL;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* do_assignment_positional (hawk_rtx_t* rtx, hawk_nde_pos_t* pos, hawk_val_t* val)
 | 
						|
{
 | 
						|
	hawk_val_t* v;
 | 
						|
	hawk_val_type_t vtype;
 | 
						|
	hawk_int_t lv;
 | 
						|
	hawk_oocs_t str;
 | 
						|
	int n;
 | 
						|
 | 
						|
	v = eval_expression(rtx, pos->val);
 | 
						|
	if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, v);
 | 
						|
	n = hawk_rtx_valtoint(rtx, v, &lv);
 | 
						|
	hawk_rtx_refdownval(rtx, v);
 | 
						|
 | 
						|
	if (n <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &pos->loc, HAWK_EPOSIDX);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!IS_VALID_POSIDX(lv))
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &pos->loc, HAWK_EPOSIDX);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	vtype = HAWK_RTX_GETVALTYPE(rtx, val);
 | 
						|
	if (vtype == HAWK_VAL_STR)
 | 
						|
	{
 | 
						|
		str = ((hawk_val_str_t*)val)->val;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		hawk_rtx_valtostr_out_t out;
 | 
						|
 | 
						|
		out.type = HAWK_RTX_VALTOSTR_CPLDUP;
 | 
						|
		if (hawk_rtx_valtostr(rtx, val, &out) <= -1)
 | 
						|
		{
 | 
						|
			ADJERR_LOC(rtx, &pos->loc);
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
 | 
						|
		str = out.u.cpldup;
 | 
						|
	}
 | 
						|
 | 
						|
	n = hawk_rtx_setrec(rtx, (hawk_oow_t)lv, &str, 0);
 | 
						|
 | 
						|
	if (vtype == HAWK_VAL_STR)
 | 
						|
	{
 | 
						|
		/* do nothing */
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		hawk_rtx_freemem(rtx, str.ptr);
 | 
						|
	}
 | 
						|
 | 
						|
	if (n <= -1) return HAWK_NULL;
 | 
						|
	return (lv == 0)? rtx->inrec.d0: rtx->inrec.flds[lv-1].val;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binary (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	static binop_func_t binop_func[] =
 | 
						|
	{
 | 
						|
		/* the order of the functions should be inline with
 | 
						|
		 * the operator declaration in rtx.h */
 | 
						|
 | 
						|
		HAWK_NULL, /* eval_binop_lor */
 | 
						|
		HAWK_NULL, /* eval_binop_land */
 | 
						|
		HAWK_NULL, /* eval_binop_in */
 | 
						|
 | 
						|
		eval_binop_bor,
 | 
						|
		eval_binop_bxor,
 | 
						|
		eval_binop_band,
 | 
						|
 | 
						|
		eval_binop_teq,
 | 
						|
		eval_binop_tne,
 | 
						|
		eval_binop_eq,
 | 
						|
		eval_binop_ne,
 | 
						|
		eval_binop_gt,
 | 
						|
		eval_binop_ge,
 | 
						|
		eval_binop_lt,
 | 
						|
		eval_binop_le,
 | 
						|
 | 
						|
		eval_binop_lshift,
 | 
						|
		eval_binop_rshift,
 | 
						|
 | 
						|
		eval_binop_plus,
 | 
						|
		eval_binop_minus,
 | 
						|
		eval_binop_mul,
 | 
						|
		eval_binop_div,
 | 
						|
		eval_binop_idiv,
 | 
						|
		eval_binop_mod,
 | 
						|
		eval_binop_exp,
 | 
						|
 | 
						|
		eval_binop_concat,
 | 
						|
		HAWK_NULL, /* eval_binop_ma */
 | 
						|
		HAWK_NULL  /* eval_binop_nm */
 | 
						|
	};
 | 
						|
 | 
						|
	hawk_nde_exp_t* exp = (hawk_nde_exp_t*)nde;
 | 
						|
	hawk_val_t* left, * right, * res;
 | 
						|
 | 
						|
	HAWK_ASSERT(exp->type == HAWK_NDE_EXP_BIN);
 | 
						|
 | 
						|
	switch (exp->opcode)
 | 
						|
	{
 | 
						|
		case HAWK_BINOP_LAND:
 | 
						|
			res = eval_binop_land(rtx, exp->left, exp->right);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_BINOP_LOR:
 | 
						|
			res = eval_binop_lor(rtx, exp->left, exp->right);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_BINOP_IN:
 | 
						|
			/* treat the in operator specially */
 | 
						|
			res = eval_binop_in(rtx, exp->left, exp->right);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_BINOP_NM:
 | 
						|
			res = eval_binop_nm(rtx, exp->left, exp->right);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_BINOP_MA:
 | 
						|
			res = eval_binop_ma(rtx, exp->left, exp->right);
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			HAWK_ASSERT(exp->left->next == HAWK_NULL);
 | 
						|
			left = eval_expression(rtx, exp->left);
 | 
						|
			if (HAWK_UNLIKELY(!left)) return HAWK_NULL;
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, left);
 | 
						|
 | 
						|
			HAWK_ASSERT(exp->right->next == HAWK_NULL);
 | 
						|
			right = eval_expression(rtx, exp->right);
 | 
						|
			if (HAWK_UNLIKELY(!right))
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, left);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, right);
 | 
						|
 | 
						|
			HAWK_ASSERT(exp->opcode >= 0 && exp->opcode < HAWK_COUNTOF(binop_func));
 | 
						|
			HAWK_ASSERT(binop_func[exp->opcode] != HAWK_NULL);
 | 
						|
 | 
						|
			res = binop_func[exp->opcode](rtx, left, right);
 | 
						|
			if (HAWK_UNLIKELY(!res)) ADJERR_LOC(rtx, &nde->loc);
 | 
						|
 | 
						|
			hawk_rtx_refdownval(rtx, left);
 | 
						|
			hawk_rtx_refdownval(rtx, right);
 | 
						|
	}
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_lor (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* right)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	hawk_val_t* res = HAWK_NULL;
 | 
						|
 | 
						|
	res = hawk_rtx_makeintval(
 | 
						|
		rtx,
 | 
						|
		hawk_rtx_valtobool(rtx,left) ||
 | 
						|
		hawk_rtx_valtobool(rtx,right)
 | 
						|
	);
 | 
						|
	if (res == HAWK_NULL)
 | 
						|
	{
 | 
						|
		ADJERR_LOC(rtx, &left->loc);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return res;
 | 
						|
	*/
 | 
						|
 | 
						|
	/* short-circuit evaluation required special treatment */
 | 
						|
	hawk_val_t* lv, * rv, * res;
 | 
						|
 | 
						|
	HAWK_ASSERT(left->next == HAWK_NULL);
 | 
						|
	lv = eval_expression(rtx, left);
 | 
						|
	if (HAWK_UNLIKELY(!lv)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, lv);
 | 
						|
	if (hawk_rtx_valtobool(rtx, lv))
 | 
						|
	{
 | 
						|
		res = HAWK_VAL_ONE;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		HAWK_ASSERT(right->next == HAWK_NULL);
 | 
						|
		rv = eval_expression(rtx, right);
 | 
						|
		if (HAWK_UNLIKELY(!rv))
 | 
						|
		{
 | 
						|
			hawk_rtx_refdownval(rtx, lv);
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
		hawk_rtx_refupval(rtx, rv);
 | 
						|
 | 
						|
		res = hawk_rtx_valtobool(rtx,rv)?
 | 
						|
			HAWK_VAL_ONE: HAWK_VAL_ZERO;
 | 
						|
		hawk_rtx_refdownval(rtx, rv);
 | 
						|
	}
 | 
						|
 | 
						|
	hawk_rtx_refdownval(rtx, lv);
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_land (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* right)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	hawk_val_t* res = HAWK_NULL;
 | 
						|
 | 
						|
	res = hawk_rtx_makeintval(
 | 
						|
		rtx,
 | 
						|
		hawk_rtx_valtobool(rtx,left) &&
 | 
						|
		hawk_rtx_valtobool(rtx,right)
 | 
						|
	);
 | 
						|
	if (res == HAWK_NULL)
 | 
						|
	{
 | 
						|
		ADJERR_LOC(rtx, &left->loc);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return res;
 | 
						|
	*/
 | 
						|
 | 
						|
	/* short-circuit evaluation required special treatment */
 | 
						|
	hawk_val_t* lv, * rv, * res;
 | 
						|
 | 
						|
	HAWK_ASSERT(left->next == HAWK_NULL);
 | 
						|
	lv = eval_expression(rtx, left);
 | 
						|
	if (HAWK_UNLIKELY(!lv)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, lv);
 | 
						|
	if (!hawk_rtx_valtobool(rtx, lv))
 | 
						|
	{
 | 
						|
		res = HAWK_VAL_ZERO;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		HAWK_ASSERT(right->next == HAWK_NULL);
 | 
						|
		rv = eval_expression(rtx, right);
 | 
						|
		if (HAWK_UNLIKELY(!rv))
 | 
						|
		{
 | 
						|
			hawk_rtx_refdownval(rtx, lv);
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
		hawk_rtx_refupval(rtx, rv);
 | 
						|
 | 
						|
		res = hawk_rtx_valtobool(rtx,rv)? HAWK_VAL_ONE: HAWK_VAL_ZERO;
 | 
						|
		hawk_rtx_refdownval(rtx, rv);
 | 
						|
	}
 | 
						|
 | 
						|
	hawk_rtx_refdownval(rtx, lv);
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_in (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* right)
 | 
						|
{
 | 
						|
	hawk_val_t* res;
 | 
						|
	hawk_val_t* ropv;
 | 
						|
	hawk_val_type_t ropvtype;
 | 
						|
	hawk_ooch_t* str;
 | 
						|
	hawk_oow_t len;
 | 
						|
	hawk_ooch_t idxbuf[HAWK_IDX_BUF_SIZE];
 | 
						|
	hawk_nde_t* remidx;
 | 
						|
	hawk_int_t idxint;
 | 
						|
 | 
						|
	if (right->type == HAWK_NDE_XARGV) goto rvalue_ok;
 | 
						|
 | 
						|
#if defined(HAWK_ENABLE_GC)
 | 
						|
	if (right->type < HAWK_NDE_NAMED || right->type > HAWK_NDE_ARGIDX)
 | 
						|
#else
 | 
						|
	if (right->type < HAWK_NDE_NAMED || right->type > HAWK_NDE_ARG)
 | 
						|
#endif
 | 
						|
	{
 | 
						|
		/* the compiler should have handled this case */
 | 
						|
		HAWK_ASSERT(!"should never happen - it needs a plain variable");
 | 
						|
		hawk_rtx_seterrnum(rtx, &right->loc, HAWK_EINTERN);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
rvalue_ok:
 | 
						|
	/* evaluate the left-hand side of the operator */
 | 
						|
	len = HAWK_COUNTOF(idxbuf);
 | 
						|
	str = (left->type == HAWK_NDE_GRP)? /* it is inefficinet to call idxnde_to_str() for an array. but i don't know if the right hand side is a map or an array yet */
 | 
						|
		idxnde_to_str(rtx, ((hawk_nde_grp_t*)left)->body, idxbuf, &len, &remidx, HAWK_NULL):
 | 
						|
		idxnde_to_str(rtx, left, idxbuf, &len, &remidx, &idxint);
 | 
						|
	if (HAWK_UNLIKELY(!str)) return HAWK_NULL;
 | 
						|
 | 
						|
	/* There is no way to express a true multi-dimensional indices for the 'in' operator.
 | 
						|
	 * So remidx must be NULL here.
 | 
						|
	 *   a[10][20] <--- no way to express the test of 20 under 10 in a.
 | 
						|
	 * You may use multi-level test conjoined with a logical and operator in such a case.
 | 
						|
	 *   ((10 in a) && (20 in a[10]))
 | 
						|
	 *
 | 
						|
	 *  '(10, 20) in a' is to test for a[10,20] if 'a' is a map.
 | 
						|
	 */
 | 
						|
	HAWK_ASSERT(remidx == HAWK_NULL);
 | 
						|
 | 
						|
	/* evaluate the right-hand side of the operator */
 | 
						|
	HAWK_ASSERT(right->next == HAWK_NULL);
 | 
						|
	ropv = eval_expression(rtx, right);
 | 
						|
	if (HAWK_UNLIKELY(!ropv))
 | 
						|
	{
 | 
						|
		if (str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, ropv);
 | 
						|
 | 
						|
	ropvtype = HAWK_RTX_GETVALTYPE(rtx, ropv);
 | 
						|
	switch (ropvtype)
 | 
						|
	{
 | 
						|
		case HAWK_VAL_NIL:
 | 
						|
			res = HAWK_VAL_ZERO;
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_VAL_MAP:
 | 
						|
		{
 | 
						|
 | 
						|
			hawk_map_t* map;
 | 
						|
 | 
						|
			map = ((hawk_val_map_t*)ropv)->map;
 | 
						|
			res = (hawk_map_search(map, str, len) == HAWK_NULL)? HAWK_VAL_ZERO: HAWK_VAL_ONE;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_VAL_ARR:
 | 
						|
		{
 | 
						|
			hawk_arr_t* arr;
 | 
						|
 | 
						|
			if (left->type == HAWK_NDE_GRP)
 | 
						|
			{
 | 
						|
				hawk_rtx_seterrnum(rtx, &left->loc, HAWK_EARRIDXMULTI);
 | 
						|
				goto oops;
 | 
						|
			}
 | 
						|
 | 
						|
			arr = ((hawk_val_arr_t*)ropv)->arr;
 | 
						|
			res = (idxint < 0 || idxint >= HAWK_ARR_SIZE(arr) || !HAWK_ARR_SLOT(arr, idxint))? HAWK_VAL_ZERO: HAWK_VAL_ONE;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		default:
 | 
						|
			hawk_rtx_seterrnum(rtx, &right->loc, HAWK_EINROP);
 | 
						|
			goto oops;
 | 
						|
	}
 | 
						|
 | 
						|
	if (str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
	hawk_rtx_refdownval(rtx, ropv);
 | 
						|
	return res;
 | 
						|
 | 
						|
oops:
 | 
						|
	if (str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
	hawk_rtx_refdownval(rtx, ropv);
 | 
						|
 | 
						|
	return HAWK_NULL;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_bor (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	hawk_int_t l1, l2;
 | 
						|
 | 
						|
	if (hawk_rtx_valtoint(rtx, left, &l1) <= -1 ||
 | 
						|
	    hawk_rtx_valtoint(rtx, right, &l2) <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return hawk_rtx_makeintval(rtx, l1 | l2);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_bxor (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	hawk_int_t l1, l2;
 | 
						|
 | 
						|
	if (hawk_rtx_valtoint(rtx, left, &l1) <= -1 ||
 | 
						|
	    hawk_rtx_valtoint(rtx, right, &l2) <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return hawk_rtx_makeintval(rtx, l1 ^ l2);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_band (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	hawk_int_t l1, l2;
 | 
						|
 | 
						|
	if (hawk_rtx_valtoint(rtx, left, &l1) <= -1 ||
 | 
						|
	    hawk_rtx_valtoint(rtx, right, &l2) <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return hawk_rtx_makeintval(rtx, l1 & l2);
 | 
						|
}
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
 | 
						|
enum cmp_op_t
 | 
						|
{
 | 
						|
	CMP_OP_NONE = 0,
 | 
						|
	CMP_OP_EQ = 1,
 | 
						|
	CMP_OP_NE = 2,
 | 
						|
	CMP_OP_GT = 3,
 | 
						|
	CMP_OP_GE = 4,
 | 
						|
	CMP_OP_LT = 5,
 | 
						|
	CMP_OP_LE = 6
 | 
						|
};
 | 
						|
typedef enum cmp_op_t cmp_op_t;
 | 
						|
 | 
						|
static HAWK_INLINE cmp_op_t inverse_cmp_op (cmp_op_t op)
 | 
						|
{
 | 
						|
	static cmp_op_t inverse_cmp_op_tab[] =
 | 
						|
	{
 | 
						|
		CMP_OP_NONE,
 | 
						|
		CMP_OP_NE,
 | 
						|
		CMP_OP_EQ,
 | 
						|
		CMP_OP_LT,
 | 
						|
		CMP_OP_LE,
 | 
						|
		CMP_OP_GT,
 | 
						|
		CMP_OP_GE
 | 
						|
	};
 | 
						|
	return inverse_cmp_op_tab[op];
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_ensure_not_equal (hawk_rtx_t* rtx, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	/* checking equality is mostly obvious. however, it is not possible
 | 
						|
	 * to test if one is less/greater than the other for some operands.
 | 
						|
	 * this function return a number that ensures to make NE to true and
 | 
						|
	 * all other operations false */
 | 
						|
 | 
						|
	switch (op_hint)
 | 
						|
	{
 | 
						|
		case CMP_OP_EQ:
 | 
						|
		case CMP_OP_NE:
 | 
						|
			return 1;  /* not equal */
 | 
						|
 | 
						|
		case CMP_OP_GT:
 | 
						|
		case CMP_OP_LT:
 | 
						|
			return 0; /* make GT or LT to be false by claiming equal */
 | 
						|
 | 
						|
		case CMP_OP_GE:
 | 
						|
			return -1; /* make GE false by claiming less */
 | 
						|
		case CMP_OP_LE:
 | 
						|
			return 1;  /* make LE false by claiming greater */
 | 
						|
 | 
						|
		default:
 | 
						|
			hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
			return -1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
static HAWK_INLINE int __cmp_nil_nil (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_nil_char (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_oochu_t v = HAWK_RTX_GETCHARFROMVAL(rtx, right);
 | 
						|
	return (v < 0)? 1: ((v > 0)? -1: 0);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_nil_bchr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_bchu_t v = HAWK_RTX_GETBCHRFROMVAL(rtx, right);
 | 
						|
	return (v < 0)? 1: ((v > 0)? -1: 0);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_nil_int (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_int_t v = HAWK_RTX_GETINTFROMVAL(rtx, right);
 | 
						|
	return (v < 0)? 1: ((v > 0)? -1: 0);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_nil_flt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	if (((hawk_val_flt_t*)right)->val < 0) return 1;
 | 
						|
	if (((hawk_val_flt_t*)right)->val > 0) return -1;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_nil_str (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return (((hawk_val_str_t*)right)->val.len == 0)? 0: -1;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_nil_mbs (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return (((hawk_val_mbs_t*)right)->val.len == 0)? 0: -1;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_nil_fun (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	/* != -> true, all others -> false */
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_nil_map (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return (HAWK_MAP_SIZE(((hawk_val_map_t*)right)->map) == 0)? 0: -1;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_nil_arr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return (HAWK_ARR_SIZE(((hawk_val_arr_t*)right)->arr) == 0)? 0: -1;
 | 
						|
}
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_char_nil (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_nil_char(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_char_char (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_oochu_t v1 = HAWK_RTX_GETCHARFROMVAL(rtx, left);
 | 
						|
	hawk_oochu_t v2 = HAWK_RTX_GETCHARFROMVAL(rtx, right);
 | 
						|
	return (v1 > v2)? 1: ((v1 < v2)? -1: 0);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_char_bchr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_oochu_t v1 = HAWK_RTX_GETCHARFROMVAL(rtx, left);
 | 
						|
	hawk_bchu_t v2 = HAWK_RTX_GETBCHRFROMVAL(rtx, right);
 | 
						|
	return (v1 > v2)? 1: ((v1 < v2)? -1: 0);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_char_int (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	hawk_oochu_t v1 = HAWK_RTX_GETCHARFROMVAL(rtx, left);
 | 
						|
	hawk_int_t v2 = HAWK_RTX_GETINTFROMVAL(rtx, right);
 | 
						|
	return (v1 > v2)? 1: ((v1 < v2)? -1: 0);
 | 
						|
	*/
 | 
						|
	hawk_ooch_t v1;
 | 
						|
	hawk_ooch_t* str0;
 | 
						|
	hawk_oow_t len0;
 | 
						|
	int n;
 | 
						|
 | 
						|
	v1 = HAWK_RTX_GETCHARFROMVAL(rtx, left);
 | 
						|
	str0 = hawk_rtx_getvaloocstr(rtx, right, &len0);
 | 
						|
	if (!str0) return CMP_ERROR;
 | 
						|
	n = hawk_comp_oochars(&v1, 1, str0, len0, rtx->gbl.ignorecase);
 | 
						|
	hawk_rtx_freevaloocstr(rtx, right, str0);
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_char_flt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	hawk_ooch_t v1 = HAWK_RTX_GETCHARFROMVAL(rtx, left);
 | 
						|
	if (v1 > ((hawk_val_flt_t*)right)->val) return 1;
 | 
						|
	if (v1 < ((hawk_val_flt_t*)right)->val) return -1;
 | 
						|
	return 0;
 | 
						|
	*/
 | 
						|
	return __cmp_char_int(rtx, left, right, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_char_str (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_ooch_t v1 = HAWK_RTX_GETCHARFROMVAL(rtx, left);
 | 
						|
	return hawk_comp_oochars(&v1, 1, ((hawk_val_str_t*)right)->val.ptr, ((hawk_val_str_t*)right)->val.len, rtx->gbl.ignorecase);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_char_mbs (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_ooch_t v1 = HAWK_RTX_GETCHARFROMVAL(rtx, left);
 | 
						|
	hawk_bch_t bc;
 | 
						|
	if (v1 > 0xFF) return 1;
 | 
						|
	bc = v1;
 | 
						|
	return hawk_comp_bchars(&bc, 1, ((hawk_val_mbs_t*)right)->val.ptr, ((hawk_val_mbs_t*)right)->val.len, rtx->gbl.ignorecase);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_char_fun (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_char_map (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_char_arr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_bchr_nil (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_nil_bchr(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_bchr_char (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_char_bchr(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_bchr_bchr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_bchu_t v1 = HAWK_RTX_GETBCHRFROMVAL(rtx, left);
 | 
						|
	hawk_bchu_t v2 = HAWK_RTX_GETBCHRFROMVAL(rtx, right);
 | 
						|
	return (v1 > v2)? 1: ((v1 < v2)? -1: 0);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_bchr_int (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	hawk_bchu_t v1 = HAWK_RTX_GETBCHRFROMVAL(rtx, left);
 | 
						|
	hawk_int_t v2 = HAWK_RTX_GETINTFROMVAL(rtx, right);
 | 
						|
	return (v1 > v2)? 1: ((v1 < v2)? -1: 0);
 | 
						|
	*/
 | 
						|
	hawk_bch_t v1;
 | 
						|
	hawk_bch_t* str0;
 | 
						|
	hawk_oow_t len0;
 | 
						|
	int n;
 | 
						|
 | 
						|
	v1 = HAWK_RTX_GETBCHRFROMVAL(rtx, left);
 | 
						|
	str0 = hawk_rtx_getvalbcstr(rtx, right, &len0);
 | 
						|
	if (!str0) return CMP_ERROR;
 | 
						|
	n = hawk_comp_bchars(&v1, 1, str0, len0, rtx->gbl.ignorecase);
 | 
						|
	hawk_rtx_freevalbcstr(rtx, right, str0);
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_bchr_flt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	hawk_bchu_t v1 = HAWK_RTX_GETBCHRFROMVAL(rtx, left);
 | 
						|
	if (v1 > ((hawk_val_flt_t*)right)->val) return 1;
 | 
						|
	if (v1 < ((hawk_val_flt_t*)right)->val) return -1;
 | 
						|
	return 0;
 | 
						|
	*/
 | 
						|
	return __cmp_bchr_int(rtx, left, right, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_bchr_str (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_bchu_t v1 = HAWK_RTX_GETBCHRFROMVAL(rtx, left);
 | 
						|
	hawk_oochu_t oc = v1;
 | 
						|
	return hawk_comp_oochars(&oc, 1, ((hawk_val_str_t*)right)->val.ptr, ((hawk_val_str_t*)right)->val.len, rtx->gbl.ignorecase);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_bchr_mbs (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_bch_t v1 = HAWK_RTX_GETBCHRFROMVAL(rtx, left);
 | 
						|
	return hawk_comp_bchars(&v1, 1, ((hawk_val_mbs_t*)right)->val.ptr, ((hawk_val_mbs_t*)right)->val.len, rtx->gbl.ignorecase);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_bchr_fun (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_bchr_map (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_bchr_arr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_int_nil (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_nil_int(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_int_char (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_char_int(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_int_bchr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_bchr_int(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_int_int (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_int_t v1 = HAWK_RTX_GETINTFROMVAL(rtx, left);
 | 
						|
	hawk_int_t v2 = HAWK_RTX_GETINTFROMVAL(rtx, right);
 | 
						|
	return (v1 > v2)? 1: ((v1 < v2)? -1: 0);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_int_flt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_int_t v1 = HAWK_RTX_GETINTFROMVAL(rtx, left);
 | 
						|
	if (v1 > ((hawk_val_flt_t*)right)->val) return 1;
 | 
						|
	if (v1 < ((hawk_val_flt_t*)right)->val) return -1;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_int_str (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_t* hawk = hawk_rtx_gethawk(rtx);
 | 
						|
	hawk_ooch_t* str0;
 | 
						|
	hawk_oow_t len0;
 | 
						|
	int n;
 | 
						|
 | 
						|
	/* SCO CC doesn't seem to handle right->v_nstr > 0 properly */
 | 
						|
	if ((hawk->opt.trait & HAWK_NCMPONSTR) || right->v_nstr /*> 0*/)
 | 
						|
	{
 | 
						|
		hawk_int_t ll, v1;
 | 
						|
		hawk_flt_t rr;
 | 
						|
 | 
						|
		n = hawk_oochars_to_num(
 | 
						|
			HAWK_OOCHARS_TO_NUM_MAKE_OPTION(1, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0),
 | 
						|
			((hawk_val_str_t*)right)->val.ptr,
 | 
						|
			((hawk_val_str_t*)right)->val.len,
 | 
						|
			&ll, &rr
 | 
						|
		);
 | 
						|
 | 
						|
		v1 = HAWK_RTX_GETINTFROMVAL(rtx, left);
 | 
						|
		if (n == 0)
 | 
						|
		{
 | 
						|
			/* a numeric integral string */
 | 
						|
			return (v1 > ll)? 1: ((v1 < ll)? -1: 0);
 | 
						|
		}
 | 
						|
		else if (n > 0)
 | 
						|
		{
 | 
						|
			/* a numeric floating-point string */
 | 
						|
			return (v1 > rr)? 1: ((v1 < rr)? -1: 0);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	str0 = hawk_rtx_getvaloocstr(rtx, left, &len0);
 | 
						|
	if (!str0) return CMP_ERROR;
 | 
						|
	n = hawk_comp_oochars(str0, len0, ((hawk_val_str_t*)right)->val.ptr, ((hawk_val_str_t*)right)->val.len, rtx->gbl.ignorecase);
 | 
						|
	hawk_rtx_freevaloocstr(rtx, left, str0);
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_int_mbs (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_t* hawk = hawk_rtx_gethawk(rtx);
 | 
						|
	hawk_bch_t* str0;
 | 
						|
	hawk_oow_t len0;
 | 
						|
	int n;
 | 
						|
 | 
						|
	if ((hawk->opt.trait & HAWK_NCMPONSTR) || right->v_nstr /*> 0*/)
 | 
						|
	{
 | 
						|
		hawk_int_t ll, v1;
 | 
						|
		hawk_flt_t rr;
 | 
						|
 | 
						|
		n = hawk_bchars_to_num (
 | 
						|
			HAWK_OOCHARS_TO_NUM_MAKE_OPTION(1, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0),
 | 
						|
			((hawk_val_mbs_t*)right)->val.ptr,
 | 
						|
			((hawk_val_mbs_t*)right)->val.len,
 | 
						|
			&ll, &rr
 | 
						|
		);
 | 
						|
 | 
						|
		v1 = HAWK_RTX_GETINTFROMVAL(rtx, left);
 | 
						|
		if (n == 0)
 | 
						|
		{
 | 
						|
			/* a numeric integral string */
 | 
						|
			return (v1 > ll)? 1: ((v1 < ll)? -1: 0);
 | 
						|
		}
 | 
						|
		else if (n > 0)
 | 
						|
		{
 | 
						|
			/* a numeric floating-point string */
 | 
						|
			return (v1 > rr)? 1: ((v1 < rr)? -1: 0);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	str0 = hawk_rtx_getvalbcstr(rtx, left, &len0);
 | 
						|
	if (!str0) return -1;
 | 
						|
	n = hawk_comp_bchars(str0, len0, ((hawk_val_mbs_t*)right)->val.ptr, ((hawk_val_mbs_t*)right)->val.len, rtx->gbl.ignorecase);
 | 
						|
	hawk_rtx_freevalbcstr(rtx, left, str0);
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_int_fun (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_int_map (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_int_arr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_flt_nil (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_nil_flt(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_flt_char (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_char_flt(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_flt_bchr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_bchr_flt(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_flt_int (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_int_flt(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_flt_flt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	if (((hawk_val_flt_t*)left)->val > ((hawk_val_flt_t*)right)->val) return 1;
 | 
						|
	if (((hawk_val_flt_t*)left)->val < ((hawk_val_flt_t*)right)->val) return -1;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_flt_str (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_t* hawk = hawk_rtx_gethawk(rtx);
 | 
						|
	hawk_ooch_t* str0;
 | 
						|
	hawk_oow_t len0;
 | 
						|
	int n;
 | 
						|
 | 
						|
	/* SCO CC doesn't seem to handle right->v_nstr > 0 properly */
 | 
						|
	if ((hawk->opt.trait & HAWK_NCMPONSTR) || right->v_nstr /*> 0*/)
 | 
						|
	{
 | 
						|
		const hawk_ooch_t* end;
 | 
						|
		hawk_flt_t rr;
 | 
						|
 | 
						|
		rr = hawk_oochars_to_flt(((hawk_val_str_t*)right)->val.ptr, ((hawk_val_str_t*)right)->val.len, &end, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx));
 | 
						|
		if (end == ((hawk_val_str_t*)right)->val.ptr + ((hawk_val_str_t*)right)->val.len)
 | 
						|
		{
 | 
						|
			return (((hawk_val_flt_t*)left)->val > rr)? 1:
 | 
						|
			       (((hawk_val_flt_t*)left)->val < rr)? -1: 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	str0 = hawk_rtx_getvaloocstr(rtx, left, &len0);
 | 
						|
	if (!str0) return CMP_ERROR;
 | 
						|
	n = hawk_comp_oochars(str0, len0, ((hawk_val_str_t*)right)->val.ptr, ((hawk_val_str_t*)right)->val.len, rtx->gbl.ignorecase);
 | 
						|
	hawk_rtx_freevaloocstr(rtx, left, str0);
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_flt_mbs (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_t* hawk = hawk_rtx_gethawk(rtx);
 | 
						|
	hawk_bch_t* str0;
 | 
						|
	hawk_oow_t len0;
 | 
						|
	int n;
 | 
						|
 | 
						|
	if ((hawk->opt.trait & HAWK_NCMPONSTR) || right->v_nstr /*> 0*/)
 | 
						|
	{
 | 
						|
		const hawk_bch_t* end;
 | 
						|
		hawk_flt_t rr;
 | 
						|
 | 
						|
		rr = hawk_bchars_to_flt(((hawk_val_mbs_t*)right)->val.ptr, ((hawk_val_mbs_t*)right)->val.len, &end, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx));
 | 
						|
		if (end == ((hawk_val_mbs_t*)right)->val.ptr + ((hawk_val_mbs_t*)right)->val.len)
 | 
						|
		{
 | 
						|
			return (((hawk_val_flt_t*)left)->val > rr)? 1:
 | 
						|
			       (((hawk_val_flt_t*)left)->val < rr)? -1: 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	str0 = hawk_rtx_getvalbcstr(rtx, left, &len0);
 | 
						|
	if (HAWK_UNLIKELY(!str0)) return CMP_ERROR;
 | 
						|
	n = hawk_comp_bchars(str0, len0, ((hawk_val_mbs_t*)right)->val.ptr, ((hawk_val_mbs_t*)right)->val.len, rtx->gbl.ignorecase);
 | 
						|
	hawk_rtx_freevalbcstr(rtx, left, str0);
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_flt_fun (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_flt_map (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_flt_arr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_str_nil (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_nil_str(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_str_char (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_char_str(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_str_bchr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_bchr_str(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_str_int (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_int_str(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_str_flt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_flt_str(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_str_str (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_val_str_t* ls, * rs;
 | 
						|
	int stripspc;
 | 
						|
 | 
						|
	ls = (hawk_val_str_t*)left;
 | 
						|
	rs = (hawk_val_str_t*)right;
 | 
						|
 | 
						|
	if (HAWK_LIKELY(ls->v_nstr == 0 || rs->v_nstr == 0))
 | 
						|
	{
 | 
						|
		/* both are definitely strings */
 | 
						|
		return hawk_comp_oochars(ls->val.ptr, ls->val.len, rs->val.ptr, rs->val.len, rtx->gbl.ignorecase);
 | 
						|
	}
 | 
						|
 | 
						|
	stripspc = HAWK_RTX_IS_STRIPSTRSPC_ON(rtx);
 | 
						|
 | 
						|
	if (ls->v_nstr == 1)
 | 
						|
	{
 | 
						|
		hawk_int_t ll;
 | 
						|
 | 
						|
		ll = hawk_oochars_to_int(ls->val.ptr, ls->val.len, HAWK_OOCHARS_TO_INT_MAKE_OPTION(stripspc, stripspc, 0), HAWK_NULL, HAWK_NULL);
 | 
						|
 | 
						|
		if (rs->v_nstr == 1)
 | 
						|
		{
 | 
						|
			hawk_int_t rr;
 | 
						|
 | 
						|
			rr = hawk_oochars_to_int(rs->val.ptr, rs->val.len, HAWK_OOCHARS_TO_INT_MAKE_OPTION(stripspc, stripspc, 0), HAWK_NULL, HAWK_NULL);
 | 
						|
 | 
						|
			return (ll > rr)? 1:
 | 
						|
			       (ll < rr)? -1: 0;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			hawk_flt_t rr;
 | 
						|
 | 
						|
			HAWK_ASSERT(rs->v_nstr == 2);
 | 
						|
 | 
						|
			rr = hawk_oochars_to_flt(rs->val.ptr, rs->val.len, HAWK_NULL, stripspc);
 | 
						|
 | 
						|
			return (ll > rr)? 1:
 | 
						|
			       (ll < rr)? -1: 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		hawk_flt_t ll;
 | 
						|
 | 
						|
		HAWK_ASSERT(ls->v_nstr == 2);
 | 
						|
 | 
						|
		ll = hawk_oochars_to_flt(ls->val.ptr, ls->val.len, HAWK_NULL, stripspc);
 | 
						|
 | 
						|
		if (rs->v_nstr == 1)
 | 
						|
		{
 | 
						|
			hawk_int_t rr;
 | 
						|
 | 
						|
			rr = hawk_oochars_to_int(rs->val.ptr, rs->val.len, HAWK_OOCHARS_TO_INT_MAKE_OPTION(stripspc, stripspc, 0), HAWK_NULL, HAWK_NULL);
 | 
						|
 | 
						|
			return (ll > rr)? 1:
 | 
						|
			       (ll < rr)? -1: 0;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			hawk_flt_t rr;
 | 
						|
 | 
						|
			HAWK_ASSERT(rs->v_nstr == 2);
 | 
						|
 | 
						|
			rr = hawk_oochars_to_flt(rs->val.ptr, rs->val.len, HAWK_NULL, stripspc);
 | 
						|
 | 
						|
			return (ll > rr)? 1:
 | 
						|
			       (ll < rr)? -1: 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_str_mbs (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_val_str_t* ls = (hawk_val_str_t*)left;
 | 
						|
	hawk_val_mbs_t* rs = (hawk_val_mbs_t*)right;
 | 
						|
 | 
						|
#if (HAWK_SIZEOF_BCH_T != HAWK_SIZEOF_UINT8_T)
 | 
						|
#	error Unsupported size of hawk_bch_t
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(HAWK_OOCH_IS_BCH)
 | 
						|
	return hawk_comp_bchars(ls->val.ptr, ls->val.len, rs->val.ptr, rs->val.len, rtx->gbl.ignorecase);
 | 
						|
#else
 | 
						|
	hawk_bch_t* mbsptr;
 | 
						|
	hawk_oow_t mbslen;
 | 
						|
	int n;
 | 
						|
 | 
						|
	mbsptr = hawk_rtx_duputobchars(rtx, ls->val.ptr, ls->val.len, &mbslen);
 | 
						|
	if (!mbsptr) return CMP_ERROR;
 | 
						|
	n = hawk_comp_bchars(mbsptr, mbslen, (const hawk_bch_t*)rs->val.ptr, rs->val.len, rtx->gbl.ignorecase);
 | 
						|
	hawk_rtx_freemem(rtx, mbsptr);
 | 
						|
	return n;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_str_fun (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_str_map (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_str_arr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_mbs_nil (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_nil_mbs(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_mbs_char (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_char_mbs(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_mbs_bchr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_bchr_mbs(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_mbs_int (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_int_mbs(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_mbs_flt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_flt_mbs(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_mbs_str (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_str_mbs(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_mbs_mbs (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	hawk_val_mbs_t* ls = (hawk_val_mbs_t*)left;
 | 
						|
	hawk_val_mbs_t* rs = (hawk_val_mbs_t*)right;
 | 
						|
#if (HAWK_SIZEOF_BCH_T != HAWK_SIZEOF_UINT8_T)
 | 
						|
#	error Unsupported size of hawk_bch_t
 | 
						|
#endif
 | 
						|
	return hawk_comp_bchars(ls->val.ptr, ls->val.len, rs->val.ptr, rs->val.len, rtx->gbl.ignorecase);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_mbs_fun (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_mbs_map (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_mbs_arr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_fun_nil (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_fun_char (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_fun_bchr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_fun_int (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_fun_flt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_fun_str (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_fun_mbs (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_fun_fun (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return (((hawk_val_fun_t*)left)->fun == ((hawk_val_fun_t*)right)->fun)? 0: __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_fun_map (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_fun_arr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_map_nil (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_nil_map(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_map_char (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_char_map(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_map_bchr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_bchr_map(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_map_int (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_int_map(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_map_flt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_flt_map(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_map_str (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_map_mbs (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_map_fun (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_map_map (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	/* can't compare a map with a map */
 | 
						|
	hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
	return CMP_ERROR;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_map_arr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	/* can't compare a map with an array */
 | 
						|
	hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
	return CMP_ERROR;
 | 
						|
}
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_arr_nil (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_nil_arr(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_arr_char (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_char_arr(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_arr_bchr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_bchr_arr(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_arr_int (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_int_arr(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_arr_flt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	n = __cmp_flt_arr(rtx, right, left, inverse_cmp_op(op_hint));
 | 
						|
	if (n == CMP_ERROR) return CMP_ERROR;
 | 
						|
	return -n;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_arr_str (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_arr_mbs (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_arr_fun (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	return __cmp_ensure_not_equal(rtx, op_hint);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_arr_map (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	/* can't compare a map with a map */
 | 
						|
	hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
	return CMP_ERROR;
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_arr_arr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint)
 | 
						|
{
 | 
						|
	/* can't compare a map with an array */
 | 
						|
	hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
	return CMP_ERROR;
 | 
						|
}
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
 | 
						|
 | 
						|
static HAWK_INLINE int __cmp_val (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint, int* ret)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	hawk_val_type_t lvtype, rvtype;
 | 
						|
	typedef int (*cmp_val_t) (hawk_rtx_t*, hawk_val_t*, hawk_val_t*, cmp_op_t op_hint);
 | 
						|
 | 
						|
	static cmp_val_t func[] =
 | 
						|
	{
 | 
						|
		/* this table must be synchronized with the HAWK_VAL_XXX values in hawk.h */
 | 
						|
		__cmp_nil_nil,   __cmp_nil_char,   __cmp_nil_bchr,   __cmp_nil_int,   __cmp_nil_flt,   __cmp_nil_str,   __cmp_nil_mbs,   __cmp_nil_fun,   __cmp_nil_map,   __cmp_nil_arr,
 | 
						|
		__cmp_char_nil,  __cmp_char_char,  __cmp_char_bchr,  __cmp_char_int,  __cmp_char_flt,  __cmp_char_str,  __cmp_char_mbs,  __cmp_char_fun,  __cmp_char_map,  __cmp_char_arr,
 | 
						|
		__cmp_bchr_nil,  __cmp_bchr_char,  __cmp_bchr_bchr,  __cmp_bchr_int,  __cmp_bchr_flt,  __cmp_bchr_str,  __cmp_bchr_mbs,  __cmp_bchr_fun,  __cmp_bchr_map,  __cmp_bchr_arr,
 | 
						|
		__cmp_int_nil,   __cmp_int_char,   __cmp_int_bchr,   __cmp_int_int,   __cmp_int_flt,   __cmp_int_str,   __cmp_int_mbs,   __cmp_int_fun,   __cmp_int_map,   __cmp_int_arr,
 | 
						|
		__cmp_flt_nil,   __cmp_flt_char,   __cmp_flt_bchr,   __cmp_flt_int,   __cmp_flt_flt,   __cmp_flt_str,   __cmp_flt_mbs,   __cmp_flt_fun,   __cmp_flt_map,   __cmp_flt_arr,
 | 
						|
		__cmp_str_nil,   __cmp_str_char,   __cmp_str_bchr,   __cmp_str_int,   __cmp_str_flt,   __cmp_str_str,   __cmp_str_mbs,   __cmp_str_fun,   __cmp_str_map,   __cmp_str_arr,
 | 
						|
		__cmp_mbs_nil,   __cmp_mbs_char,   __cmp_mbs_bchr,   __cmp_mbs_int,   __cmp_mbs_flt,   __cmp_mbs_str,   __cmp_mbs_mbs,   __cmp_mbs_fun,   __cmp_mbs_map,   __cmp_mbs_arr,
 | 
						|
		__cmp_fun_nil,   __cmp_fun_char,   __cmp_fun_bchr,   __cmp_fun_int,   __cmp_fun_flt,   __cmp_fun_str,   __cmp_fun_mbs,   __cmp_fun_fun,   __cmp_fun_map,   __cmp_fun_arr,
 | 
						|
		__cmp_map_nil,   __cmp_map_char,   __cmp_map_bchr,   __cmp_map_int,   __cmp_map_flt,   __cmp_map_str,   __cmp_map_mbs,   __cmp_map_fun,   __cmp_map_map,   __cmp_map_arr,
 | 
						|
		__cmp_arr_nil,   __cmp_arr_char,   __cmp_arr_bchr,   __cmp_arr_int,   __cmp_arr_flt,   __cmp_arr_str,   __cmp_arr_mbs,   __cmp_arr_fun,   __cmp_arr_map,   __cmp_arr_arr
 | 
						|
	};
 | 
						|
 | 
						|
	lvtype = HAWK_RTX_GETVALTYPE(rtx, left);
 | 
						|
	rvtype = HAWK_RTX_GETVALTYPE(rtx, right);
 | 
						|
	if (!(rtx->hawk->opt.trait & HAWK_FLEXMAP) && (lvtype == HAWK_VAL_MAP || rvtype == HAWK_VAL_MAP || lvtype == HAWK_VAL_ARR || rvtype == HAWK_VAL_ARR))
 | 
						|
	{
 | 
						|
		/* a map can't be compared againt other values in the non-flexible mode. */
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	HAWK_ASSERT(lvtype >= HAWK_VAL_NIL && lvtype <= HAWK_VAL_ARR);
 | 
						|
	HAWK_ASSERT(rvtype >= HAWK_VAL_NIL && rvtype <= HAWK_VAL_ARR);
 | 
						|
 | 
						|
	/* mapping fomula and table layout assume:
 | 
						|
	 *  HAWK_VAL_NIL  = 0
 | 
						|
	 *  HAWK_VAL_CHAR = 1
 | 
						|
	 *  HAWK_VAL_BCHR = 2
 | 
						|
	 *  HAWK_VAL_INT  = 3
 | 
						|
	 *  HAWK_VAL_FLT  = 4
 | 
						|
	 *  HAWK_VAL_STR  = 5
 | 
						|
	 *  HAWK_VAL_MBS  = 6
 | 
						|
	 *  HAWK_VAL_FUN  = 7
 | 
						|
	 *  HAWK_VAL_MAP  = 8
 | 
						|
	 *  HAWK_VAL_ARR  = 9
 | 
						|
	 *
 | 
						|
	 * op_hint indicate the operation in progress when this function is called.
 | 
						|
	 * this hint doesn't require the comparison function to compare using this
 | 
						|
	 * operation. the comparision function should return 0 if equal, -1 if less,
 | 
						|
	 * 1 if greater, CMP_ERROR upon error regardless of this hint.
 | 
						|
	 */
 | 
						|
	n = func[lvtype * 10 + rvtype](rtx, left, right, op_hint);
 | 
						|
	if (n == CMP_ERROR) return -1;
 | 
						|
 | 
						|
	*ret = n;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int hawk_rtx_cmpval (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, int* ret)
 | 
						|
{
 | 
						|
	return __cmp_val(rtx, left, right, CMP_OP_NONE, ret);
 | 
						|
}
 | 
						|
 | 
						|
static int teq_val (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	hawk_val_type_t lt, rt;
 | 
						|
 | 
						|
	if (left == right) n = 1;
 | 
						|
	else
 | 
						|
	{
 | 
						|
		lt = HAWK_RTX_GETVALTYPE(rtx, left);
 | 
						|
		rt = HAWK_RTX_GETVALTYPE(rtx, right);
 | 
						|
 | 
						|
		if (lt != rt) n = 0;
 | 
						|
		else
 | 
						|
		{
 | 
						|
			switch (lt)
 | 
						|
			{
 | 
						|
				case HAWK_VAL_NIL:
 | 
						|
					n = 1;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_CHAR:
 | 
						|
					/* since a CHAR value is only reprensented in the value pointer,
 | 
						|
					 * n is guaranteed to be 0 here. so the following check isn't needed */
 | 
						|
					n = (HAWK_RTX_GETCHARFROMVAL(rtx, left) == HAWK_RTX_GETCHARFROMVAL(rtx, right));
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_BCHR:
 | 
						|
					 /* since a BCHR value is only reprensented in the value pointer,
 | 
						|
					 * n is guaranteed to be 0 here. so the following check isn't needed */
 | 
						|
					n = (HAWK_RTX_GETBCHRFROMVAL(rtx, left) == HAWK_RTX_GETBCHRFROMVAL(rtx, right));
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_INT:
 | 
						|
					n = (HAWK_RTX_GETINTFROMVAL(rtx, left) == HAWK_RTX_GETINTFROMVAL(rtx, right));
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_FLT:
 | 
						|
					n = ((hawk_val_flt_t*)left)->val == ((hawk_val_flt_t*)right)->val;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_STR:
 | 
						|
					n = hawk_comp_oochars(
 | 
						|
						((hawk_val_str_t*)left)->val.ptr,
 | 
						|
						((hawk_val_str_t*)left)->val.len,
 | 
						|
						((hawk_val_str_t*)right)->val.ptr,
 | 
						|
						((hawk_val_str_t*)right)->val.len,
 | 
						|
						rtx->gbl.ignorecase) == 0;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_MBS:
 | 
						|
					n = hawk_comp_bchars(
 | 
						|
						((hawk_val_mbs_t*)left)->val.ptr,
 | 
						|
						((hawk_val_mbs_t*)left)->val.len,
 | 
						|
						((hawk_val_mbs_t*)right)->val.ptr,
 | 
						|
						((hawk_val_mbs_t*)right)->val.len,
 | 
						|
						rtx->gbl.ignorecase) == 0;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_FUN:
 | 
						|
					n = ((hawk_val_fun_t*)left)->fun == ((hawk_val_fun_t*)right)->fun;
 | 
						|
					break;
 | 
						|
 | 
						|
				default:
 | 
						|
					/* map-x and map-y are always different regardless of
 | 
						|
					 * their contents. however, if they are pointing to the
 | 
						|
					 * same map value, it won't reach here but will be
 | 
						|
					 * handled by the first check in this function */
 | 
						|
					n = 0;
 | 
						|
					break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_teq (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	return teq_val(rtx, left, right)? HAWK_VAL_ONE: HAWK_VAL_ZERO;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_tne (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	return teq_val(rtx, left, right)? HAWK_VAL_ZERO: HAWK_VAL_ONE;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_eq (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	if (__cmp_val(rtx, left, right, CMP_OP_EQ, &n) <= -1) return HAWK_NULL;
 | 
						|
	return (n == 0)? HAWK_VAL_ONE: HAWK_VAL_ZERO;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_ne (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	if (__cmp_val(rtx, left, right, CMP_OP_NE, &n) <= -1) return HAWK_NULL;
 | 
						|
	return (n != 0)? HAWK_VAL_ONE: HAWK_VAL_ZERO;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_gt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	if (__cmp_val(rtx, left, right, CMP_OP_GT, &n) <= -1) return HAWK_NULL;
 | 
						|
	return (n > 0)? HAWK_VAL_ONE: HAWK_VAL_ZERO;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_ge (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	if (__cmp_val(rtx, left, right, CMP_OP_GE, &n) <= -1) return HAWK_NULL;
 | 
						|
	return (n >= 0)? HAWK_VAL_ONE: HAWK_VAL_ZERO;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_lt (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	if (__cmp_val(rtx, left, right, CMP_OP_LT, &n) <= -1) return HAWK_NULL;
 | 
						|
	return (n < 0)? HAWK_VAL_ONE: HAWK_VAL_ZERO;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_le (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
	if (__cmp_val(rtx, left, right, CMP_OP_LE, &n) <= -1) return HAWK_NULL;
 | 
						|
	return (n <= 0)? HAWK_VAL_ONE: HAWK_VAL_ZERO;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_lshift (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	hawk_int_t l1, l2;
 | 
						|
 | 
						|
	if (hawk_rtx_valtoint(rtx, left, &l1) <= -1 ||
 | 
						|
	    hawk_rtx_valtoint(rtx, right, &l2) <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return hawk_rtx_makeintval(rtx, l1 << l2);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_rshift (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	hawk_int_t l1, l2;
 | 
						|
 | 
						|
	if (hawk_rtx_valtoint(rtx, left, &l1) <= -1 ||
 | 
						|
	    hawk_rtx_valtoint(rtx, right, &l2) <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return hawk_rtx_makeintval(rtx, l1 >> l2);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_plus (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n1, n2, n3;
 | 
						|
	hawk_int_t l1, l2;
 | 
						|
	hawk_flt_t r1, r2;
 | 
						|
 | 
						|
	n1 = hawk_rtx_valtonum(rtx, left, &l1, &r1);
 | 
						|
	n2 = hawk_rtx_valtonum(rtx, right, &l2, &r2);
 | 
						|
 | 
						|
	if (n1 <= -1 || n2 <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
	/*
 | 
						|
	n1  n2    n3
 | 
						|
	0   0   = 0
 | 
						|
	1   0   = 1
 | 
						|
	0   1   = 2
 | 
						|
	1   1   = 3
 | 
						|
	*/
 | 
						|
	n3 = n1 + (n2 << 1);
 | 
						|
	HAWK_ASSERT(n3 >= 0 && n3 <= 3);
 | 
						|
 | 
						|
	return (n3 == 0)? hawk_rtx_makeintval(rtx,(hawk_int_t)l1+(hawk_int_t)l2):
 | 
						|
	       (n3 == 1)? hawk_rtx_makefltval(rtx,(hawk_flt_t)r1+(hawk_flt_t)l2):
 | 
						|
	       (n3 == 2)? hawk_rtx_makefltval(rtx,(hawk_flt_t)l1+(hawk_flt_t)r2):
 | 
						|
	                  hawk_rtx_makefltval(rtx,(hawk_flt_t)r1+(hawk_flt_t)r2);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_minus (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n1, n2, n3;
 | 
						|
	hawk_int_t l1, l2;
 | 
						|
	hawk_flt_t r1, r2;
 | 
						|
 | 
						|
	n1 = hawk_rtx_valtonum(rtx, left, &l1, &r1);
 | 
						|
	n2 = hawk_rtx_valtonum(rtx, right, &l2, &r2);
 | 
						|
 | 
						|
	if (n1 <= -1 || n2 <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	n3 = n1 + (n2 << 1);
 | 
						|
	HAWK_ASSERT(n3 >= 0 && n3 <= 3);
 | 
						|
	return (n3 == 0)? hawk_rtx_makeintval(rtx,(hawk_int_t)l1-(hawk_int_t)l2):
 | 
						|
	       (n3 == 1)? hawk_rtx_makefltval(rtx,(hawk_flt_t)r1-(hawk_flt_t)l2):
 | 
						|
	       (n3 == 2)? hawk_rtx_makefltval(rtx,(hawk_flt_t)l1-(hawk_flt_t)r2):
 | 
						|
	                  hawk_rtx_makefltval(rtx,(hawk_flt_t)r1-(hawk_flt_t)r2);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_mul (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n1, n2, n3;
 | 
						|
	hawk_int_t l1, l2;
 | 
						|
	hawk_flt_t r1, r2;
 | 
						|
 | 
						|
	n1 = hawk_rtx_valtonum(rtx, left, &l1, &r1);
 | 
						|
	n2 = hawk_rtx_valtonum(rtx, right, &l2, &r2);
 | 
						|
 | 
						|
	if (n1 <= -1 || n2 <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	n3 = n1 + (n2 << 1);
 | 
						|
	HAWK_ASSERT(n3 >= 0 && n3 <= 3);
 | 
						|
	return (n3 == 0)? hawk_rtx_makeintval(rtx,(hawk_int_t)l1*(hawk_int_t)l2):
 | 
						|
	       (n3 == 1)? hawk_rtx_makefltval(rtx,(hawk_flt_t)r1*(hawk_flt_t)l2):
 | 
						|
	       (n3 == 2)? hawk_rtx_makefltval(rtx,(hawk_flt_t)l1*(hawk_flt_t)r2):
 | 
						|
	                  hawk_rtx_makefltval(rtx,(hawk_flt_t)r1*(hawk_flt_t)r2);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_div (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n1, n2, n3;
 | 
						|
	hawk_int_t l1, l2;
 | 
						|
	hawk_flt_t r1, r2;
 | 
						|
	hawk_val_t* res;
 | 
						|
 | 
						|
	n1 = hawk_rtx_valtonum(rtx, left, &l1, &r1);
 | 
						|
	n2 = hawk_rtx_valtonum(rtx, right, &l2, &r2);
 | 
						|
 | 
						|
	if (n1 <= -1 || n2 <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	n3 = n1 + (n2 << 1);
 | 
						|
	switch (n3)
 | 
						|
	{
 | 
						|
		case 0:
 | 
						|
			if  (l2 == 0)
 | 
						|
			{
 | 
						|
				hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EDIVBY0);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			if ((l1 % l2) == 0)
 | 
						|
			{
 | 
						|
				res = hawk_rtx_makeintval(rtx, l1 / l2);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				res = hawk_rtx_makefltval(rtx, (hawk_flt_t)l1 / (hawk_flt_t)l2);
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		case 1:
 | 
						|
			res = hawk_rtx_makefltval(rtx, r1 / (hawk_flt_t)l2);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 2:
 | 
						|
			res = hawk_rtx_makefltval(rtx, (hawk_flt_t)l1 / r2);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 3:
 | 
						|
			res = hawk_rtx_makefltval(rtx, r1 / r2);
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_idiv (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n1, n2, n3;
 | 
						|
	hawk_int_t l1, l2;
 | 
						|
	hawk_flt_t r1, r2, quo;
 | 
						|
	hawk_val_t* res;
 | 
						|
 | 
						|
	n1 = hawk_rtx_valtonum(rtx, left, &l1, &r1);
 | 
						|
	n2 = hawk_rtx_valtonum(rtx, right, &l2, &r2);
 | 
						|
 | 
						|
	if (n1 <= -1 || n2 <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	n3 = n1 + (n2 << 1);
 | 
						|
	switch (n3)
 | 
						|
	{
 | 
						|
		case 0:
 | 
						|
			if (l2 == 0)
 | 
						|
			{
 | 
						|
				hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EDIVBY0);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
			res = hawk_rtx_makeintval(rtx, l1 / l2);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 1:
 | 
						|
			quo = r1 / (hawk_flt_t)l2;
 | 
						|
			res = hawk_rtx_makeintval(rtx, (hawk_int_t)quo);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 2:
 | 
						|
			quo = (hawk_flt_t)l1 / r2;
 | 
						|
			res = hawk_rtx_makeintval(rtx, (hawk_int_t)quo);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 3:
 | 
						|
			quo = r1 / r2;
 | 
						|
			res = hawk_rtx_makeintval(rtx, (hawk_int_t)quo);
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_mod (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n1, n2, n3;
 | 
						|
	hawk_int_t l1, l2;
 | 
						|
	hawk_flt_t r1, r2;
 | 
						|
	hawk_val_t* res;
 | 
						|
 | 
						|
	/* the mod function must be provided when the hawk object is created to be able to calculate floating-pointer remainder */
 | 
						|
	HAWK_ASSERT(rtx->hawk->prm.math.mod != HAWK_NULL);
 | 
						|
 | 
						|
	n1 = hawk_rtx_valtonum(rtx, left, &l1, &r1);
 | 
						|
	n2 = hawk_rtx_valtonum(rtx, right, &l2, &r2);
 | 
						|
 | 
						|
	if (n1 <= -1 || n2 <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	n3 = n1 + (n2 << 1);
 | 
						|
	switch (n3)
 | 
						|
	{
 | 
						|
		case 0:
 | 
						|
			if (l2 == 0)
 | 
						|
			{
 | 
						|
				hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EDIVBY0);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
			res = hawk_rtx_makeintval(rtx, l1 % l2);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 1:
 | 
						|
			res = hawk_rtx_makefltval(rtx, rtx->hawk->prm.math.mod(hawk_rtx_gethawk(rtx), r1, (hawk_flt_t)l2));
 | 
						|
			break;
 | 
						|
 | 
						|
		case 2:
 | 
						|
			res = hawk_rtx_makefltval(rtx, rtx->hawk->prm.math.mod(hawk_rtx_gethawk(rtx), (hawk_flt_t)l1, r2));
 | 
						|
			break;
 | 
						|
 | 
						|
		case 3:
 | 
						|
			res = hawk_rtx_makefltval(rtx, rtx->hawk->prm.math.mod(hawk_rtx_gethawk(rtx), (hawk_flt_t)r1, (hawk_flt_t)r2));
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_exp (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	int n1, n2, n3;
 | 
						|
	hawk_int_t l1, l2;
 | 
						|
	hawk_flt_t r1, r2;
 | 
						|
	hawk_val_t* res;
 | 
						|
 | 
						|
	n1 = hawk_rtx_valtonum(rtx, left, &l1, &r1);
 | 
						|
	n2 = hawk_rtx_valtonum(rtx, right, &l2, &r2);
 | 
						|
 | 
						|
	if (n1 <= -1 || n2 <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	n3 = n1 + (n2 << 1);
 | 
						|
	switch (n3)
 | 
						|
	{
 | 
						|
		case 0:
 | 
						|
			/* left - int, right - int */
 | 
						|
			if (l2 >= 0)
 | 
						|
			{
 | 
						|
				hawk_int_t v = 1;
 | 
						|
				while (l2-- > 0) v *= l1;
 | 
						|
				res = hawk_rtx_makeintval(rtx, v);
 | 
						|
			}
 | 
						|
			else if (l1 == 0)
 | 
						|
			{
 | 
						|
				hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EDIVBY0);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				hawk_flt_t v = 1.0;
 | 
						|
				l2 *= -1;
 | 
						|
				while (l2-- > 0) v /= l1;
 | 
						|
				res = hawk_rtx_makefltval(rtx, v);
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		case 1:
 | 
						|
			/* left - real, right - int */
 | 
						|
			if (l2 >= 0)
 | 
						|
			{
 | 
						|
				hawk_flt_t v = 1.0;
 | 
						|
				while (l2-- > 0) v *= r1;
 | 
						|
				res = hawk_rtx_makefltval(rtx, v);
 | 
						|
			}
 | 
						|
			else if (r1 == 0.0)
 | 
						|
			{
 | 
						|
				hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EDIVBY0);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				hawk_flt_t v = 1.0;
 | 
						|
				l2 *= -1;
 | 
						|
				while (l2-- > 0) v /= r1;
 | 
						|
				res = hawk_rtx_makefltval(rtx, v);
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		case 2:
 | 
						|
			/* left - int, right - real */
 | 
						|
			res = hawk_rtx_makefltval(
 | 
						|
				rtx,
 | 
						|
				rtx->hawk->prm.math.pow(hawk_rtx_gethawk(rtx), (hawk_flt_t)l1, r2)
 | 
						|
			);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 3:
 | 
						|
			/* left - real, right - real */
 | 
						|
			res = hawk_rtx_makefltval(
 | 
						|
				rtx,
 | 
						|
				rtx->hawk->prm.math.pow(hawk_rtx_gethawk(rtx), r1, r2)
 | 
						|
			);
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_concat (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right)
 | 
						|
{
 | 
						|
	hawk_val_t* res;
 | 
						|
 | 
						|
	switch (HAWK_RTX_GETVALTYPE(rtx, left))
 | 
						|
	{
 | 
						|
		case HAWK_VAL_BCHR:
 | 
						|
		case HAWK_VAL_MBS:
 | 
						|
		case HAWK_VAL_BOB:
 | 
						|
		{
 | 
						|
			hawk_bcs_t l, r;
 | 
						|
 | 
						|
			l.ptr = hawk_rtx_getvalbcstr(rtx, left, &l.len);
 | 
						|
			if (HAWK_UNLIKELY(!l.ptr)) return HAWK_NULL;
 | 
						|
 | 
						|
			r.ptr = hawk_rtx_getvalbcstr(rtx, right, &r.len);
 | 
						|
			if (HAWK_UNLIKELY(!r.ptr))
 | 
						|
			{
 | 
						|
				hawk_rtx_freevalbcstr(rtx, left, l.ptr);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			res = (hawk_val_t*)hawk_rtx_makembsvalwithbchars2(rtx, l.ptr, l.len, r.ptr, r.len);
 | 
						|
 | 
						|
			hawk_rtx_freevalbcstr(rtx, right, r.ptr);
 | 
						|
			hawk_rtx_freevalbcstr(rtx, left, l.ptr);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		default:
 | 
						|
		{
 | 
						|
			hawk_oocs_t l, r;
 | 
						|
 | 
						|
			l.ptr = hawk_rtx_getvaloocstr(rtx, left, &l.len);
 | 
						|
			if (HAWK_UNLIKELY(!l.ptr)) return HAWK_NULL;
 | 
						|
 | 
						|
			r.ptr = hawk_rtx_getvaloocstr(rtx, right, &r.len);
 | 
						|
			if (HAWK_UNLIKELY(!r.ptr))
 | 
						|
			{
 | 
						|
				hawk_rtx_freevaloocstr(rtx, left, l.ptr);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			res = (hawk_val_t*)hawk_rtx_makestrvalwithoochars2(rtx, l.ptr, l.len, r.ptr, r.len);
 | 
						|
 | 
						|
			hawk_rtx_freevaloocstr(rtx, right, r.ptr);
 | 
						|
			hawk_rtx_freevaloocstr(rtx, left, l.ptr);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_match0 (
 | 
						|
	hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right,
 | 
						|
	const hawk_loc_t* lloc, const hawk_loc_t* rloc, int ret)
 | 
						|
{
 | 
						|
	hawk_val_t* res;
 | 
						|
	hawk_oocs_t out;
 | 
						|
	int n;
 | 
						|
 | 
						|
	out.ptr = hawk_rtx_getvaloocstr(rtx, left, &out.len);
 | 
						|
	if (HAWK_UNLIKELY(!out.ptr)) return HAWK_NULL;
 | 
						|
 | 
						|
	n = hawk_rtx_matchvalwithoocs(rtx, right, &out, &out, HAWK_NULL, HAWK_NULL);
 | 
						|
	hawk_rtx_freevaloocstr(rtx, left, out.ptr);
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(n <= -1))
 | 
						|
	{
 | 
						|
		ADJERR_LOC(rtx, lloc);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	res = hawk_rtx_makeintval(rtx, (n == ret));
 | 
						|
	if (HAWK_UNLIKELY(!res))
 | 
						|
	{
 | 
						|
		ADJERR_LOC(rtx, lloc);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_ma (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* right)
 | 
						|
{
 | 
						|
	hawk_val_t* lv, * rv, * res;
 | 
						|
 | 
						|
	HAWK_ASSERT(left->next == HAWK_NULL);
 | 
						|
	HAWK_ASSERT(right->next == HAWK_NULL);
 | 
						|
 | 
						|
	lv = eval_expression(rtx, left);
 | 
						|
	if (HAWK_UNLIKELY(!lv)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, lv);
 | 
						|
 | 
						|
	rv = eval_expression0(rtx, right);
 | 
						|
	if (HAWK_UNLIKELY(!rv))
 | 
						|
	{
 | 
						|
		hawk_rtx_refdownval(rtx, lv);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, rv);
 | 
						|
 | 
						|
	res = eval_binop_match0(rtx, lv, rv, &left->loc, &right->loc, 1);
 | 
						|
 | 
						|
	hawk_rtx_refdownval(rtx, rv);
 | 
						|
	hawk_rtx_refdownval(rtx, lv);
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_binop_nm (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* right)
 | 
						|
{
 | 
						|
	hawk_val_t* lv, * rv, * res;
 | 
						|
 | 
						|
	HAWK_ASSERT(left->next == HAWK_NULL);
 | 
						|
	HAWK_ASSERT(right->next == HAWK_NULL);
 | 
						|
 | 
						|
	lv = eval_expression(rtx, left);
 | 
						|
	if (HAWK_UNLIKELY(!lv)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, lv);
 | 
						|
 | 
						|
	rv = eval_expression0(rtx, right);
 | 
						|
	if (HAWK_UNLIKELY(!rv))
 | 
						|
	{
 | 
						|
		hawk_rtx_refdownval(rtx, lv);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, rv);
 | 
						|
 | 
						|
	res = eval_binop_match0(rtx, lv, rv, &left->loc, &right->loc, 0);
 | 
						|
 | 
						|
	hawk_rtx_refdownval(rtx, rv);
 | 
						|
	hawk_rtx_refdownval(rtx, lv);
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_unary (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* left, * res = HAWK_NULL;
 | 
						|
	hawk_nde_exp_t* exp = (hawk_nde_exp_t*)nde;
 | 
						|
	int n;
 | 
						|
	hawk_int_t l;
 | 
						|
	hawk_flt_t r;
 | 
						|
 | 
						|
	HAWK_ASSERT(
 | 
						|
		exp->type == HAWK_NDE_EXP_UNR);
 | 
						|
	HAWK_ASSERT(
 | 
						|
		exp->left != HAWK_NULL && exp->right == HAWK_NULL);
 | 
						|
	HAWK_ASSERT(
 | 
						|
		exp->opcode == HAWK_UNROP_PLUS ||
 | 
						|
		exp->opcode == HAWK_UNROP_MINUS ||
 | 
						|
		exp->opcode == HAWK_UNROP_LNOT ||
 | 
						|
		exp->opcode == HAWK_UNROP_BNOT);
 | 
						|
 | 
						|
	HAWK_ASSERT(exp->left->next == HAWK_NULL);
 | 
						|
	left = eval_expression(rtx, exp->left);
 | 
						|
	if (HAWK_UNLIKELY(!left)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, left);
 | 
						|
 | 
						|
	switch (exp->opcode)
 | 
						|
	{
 | 
						|
		case HAWK_UNROP_MINUS:
 | 
						|
			n = hawk_rtx_valtonum(rtx, left, &l, &r);
 | 
						|
			if (HAWK_UNLIKELY(n <= -1)) goto exit_func;
 | 
						|
 | 
						|
			res = (n == 0)? hawk_rtx_makeintval(rtx, -l):
 | 
						|
			                hawk_rtx_makefltval(rtx, -r);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_UNROP_LNOT:
 | 
						|
			if (HAWK_RTX_GETVALTYPE(rtx, left) == HAWK_VAL_STR)
 | 
						|
			{
 | 
						|
				/* 0 if the string length is greater than 0.
 | 
						|
				 * 1 if it's empty */
 | 
						|
				res = hawk_rtx_makeintval(rtx, !(((hawk_val_str_t*)left)->val.len > 0));
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				n = hawk_rtx_valtonum(rtx, left, &l, &r);
 | 
						|
				if (HAWK_UNLIKELY(n <= -1)) goto exit_func;
 | 
						|
 | 
						|
				res = (n == 0)? hawk_rtx_makeintval(rtx, !l):
 | 
						|
				                hawk_rtx_makefltval(rtx, !r);
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_UNROP_BNOT:
 | 
						|
			n = hawk_rtx_valtoint(rtx, left, &l);
 | 
						|
			if (HAWK_UNLIKELY(n <= -1)) goto exit_func;
 | 
						|
 | 
						|
			res = hawk_rtx_makeintval(rtx, ~l);
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_UNROP_PLUS:
 | 
						|
			n = hawk_rtx_valtonum(rtx, left, &l, &r);
 | 
						|
			if (HAWK_UNLIKELY(n <= -1)) goto exit_func;
 | 
						|
 | 
						|
			res = (n == 0)? hawk_rtx_makeintval(rtx, l):
 | 
						|
			                hawk_rtx_makefltval(rtx, r);
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
exit_func:
 | 
						|
	hawk_rtx_refdownval(rtx, left);
 | 
						|
	if (HAWK_UNLIKELY(!res)) ADJERR_LOC(rtx, &nde->loc);
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_incpre (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* left, * res;
 | 
						|
	hawk_val_type_t left_vtype;
 | 
						|
	hawk_int_t inc_val_int;
 | 
						|
	hawk_flt_t inc_val_flt;
 | 
						|
	hawk_nde_exp_t* exp = (hawk_nde_exp_t*)nde;
 | 
						|
 | 
						|
	HAWK_ASSERT(exp->type == HAWK_NDE_EXP_INCPRE);
 | 
						|
	HAWK_ASSERT(exp->left != HAWK_NULL && exp->right == HAWK_NULL);
 | 
						|
 | 
						|
	/* this way of checking if the l-value is assignable is
 | 
						|
	 * ugly as it is dependent on the node types defined in hawk.h
 | 
						|
	 * but let's keep going this way for the time being. */
 | 
						|
	if (exp->left->type < HAWK_NDE_NAMED ||
 | 
						|
	    /*exp->left->type > HAWK_NDE_ARGIDX) XXX */
 | 
						|
	    exp->left->type > HAWK_NDE_POS)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (exp->opcode == HAWK_INCOP_PLUS)
 | 
						|
	{
 | 
						|
		inc_val_int = 1;
 | 
						|
		inc_val_flt = 1.0;
 | 
						|
	}
 | 
						|
	else if (exp->opcode == HAWK_INCOP_MINUS)
 | 
						|
	{
 | 
						|
		inc_val_int = -1;
 | 
						|
		inc_val_flt = -1.0;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		HAWK_ASSERT(!"should never happen - invalid opcode");
 | 
						|
		hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EINTERN);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	HAWK_ASSERT(exp->left->next == HAWK_NULL);
 | 
						|
	left = eval_expression(rtx, exp->left);
 | 
						|
	if (HAWK_UNLIKELY(!left)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, left);
 | 
						|
	left_vtype = HAWK_RTX_GETVALTYPE(rtx, left);
 | 
						|
 | 
						|
	switch (left_vtype)
 | 
						|
	{
 | 
						|
		case HAWK_VAL_INT:
 | 
						|
		{
 | 
						|
			hawk_int_t r = HAWK_RTX_GETINTFROMVAL(rtx, left);
 | 
						|
			res = hawk_rtx_makeintval(rtx, r + inc_val_int);
 | 
						|
			if (HAWK_UNLIKELY(!res))
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, left);
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_VAL_FLT:
 | 
						|
		{
 | 
						|
			hawk_flt_t r = ((hawk_val_flt_t*)left)->val;
 | 
						|
			res = hawk_rtx_makefltval(rtx, r + inc_val_flt);
 | 
						|
			if (HAWK_UNLIKELY(!res))
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, left);
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		default:
 | 
						|
		{
 | 
						|
			hawk_int_t v1;
 | 
						|
			hawk_flt_t v2;
 | 
						|
			int n;
 | 
						|
 | 
						|
			n = hawk_rtx_valtonum(rtx, left, &v1, &v2);
 | 
						|
			if (HAWK_UNLIKELY(n <= -1))
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, left);
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			if (n == 0)
 | 
						|
			{
 | 
						|
				res = hawk_rtx_makeintval(rtx, v1 + inc_val_int);
 | 
						|
			}
 | 
						|
			else /* if (n == 1) */
 | 
						|
			{
 | 
						|
				HAWK_ASSERT(n == 1);
 | 
						|
				res = hawk_rtx_makefltval(rtx, v2 + inc_val_flt);
 | 
						|
			}
 | 
						|
 | 
						|
			if (HAWK_UNLIKELY(!res))
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, left);
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(do_assignment(rtx, exp->left, res) == HAWK_NULL))
 | 
						|
	{
 | 
						|
		hawk_rtx_refdownval(rtx, left);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	hawk_rtx_refdownval(rtx, left);
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_incpst (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* left, * res, * res2;
 | 
						|
	hawk_val_type_t left_vtype;
 | 
						|
	hawk_int_t inc_val_int;
 | 
						|
	hawk_flt_t inc_val_flt;
 | 
						|
	hawk_nde_exp_t* exp = (hawk_nde_exp_t*)nde;
 | 
						|
 | 
						|
	HAWK_ASSERT(exp->type == HAWK_NDE_EXP_INCPST);
 | 
						|
	HAWK_ASSERT(exp->left != HAWK_NULL && exp->right == HAWK_NULL);
 | 
						|
 | 
						|
	/* this way of checking if the l-value is assignable is
 | 
						|
	 * ugly as it is dependent on the node types defined in hawk.h.
 | 
						|
	 * but let's keep going this way for the time being. */
 | 
						|
	if (exp->left->type < HAWK_NDE_NAMED ||
 | 
						|
	    /*exp->left->type > HAWK_NDE_ARGIDX) XXX */
 | 
						|
	    exp->left->type > HAWK_NDE_POS)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EOPERAND);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (exp->opcode == HAWK_INCOP_PLUS)
 | 
						|
	{
 | 
						|
		inc_val_int = 1;
 | 
						|
		inc_val_flt = 1.0;
 | 
						|
	}
 | 
						|
	else if (exp->opcode == HAWK_INCOP_MINUS)
 | 
						|
	{
 | 
						|
		inc_val_int = -1;
 | 
						|
		inc_val_flt = -1.0;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		HAWK_ASSERT(!"should never happen - invalid opcode");
 | 
						|
		hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EINTERN);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	HAWK_ASSERT(exp->left->next == HAWK_NULL);
 | 
						|
	left = eval_expression(rtx, exp->left);
 | 
						|
	if (HAWK_UNLIKELY(!left)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, left);
 | 
						|
 | 
						|
	left_vtype = HAWK_RTX_GETVALTYPE(rtx, left);
 | 
						|
 | 
						|
	switch (left_vtype)
 | 
						|
	{
 | 
						|
		case HAWK_VAL_INT:
 | 
						|
		{
 | 
						|
			hawk_int_t r = HAWK_RTX_GETINTFROMVAL(rtx, left);
 | 
						|
			res = hawk_rtx_makeintval(rtx, r);
 | 
						|
			if (HAWK_UNLIKELY(!res))
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, left);
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			res2 = hawk_rtx_makeintval(rtx, r + inc_val_int);
 | 
						|
			if (HAWK_UNLIKELY(!res2))
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, left);
 | 
						|
				hawk_rtx_freeval(rtx, res, HAWK_RTX_FREEVAL_CACHE);
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_VAL_FLT:
 | 
						|
		{
 | 
						|
			hawk_flt_t r = ((hawk_val_flt_t*)left)->val;
 | 
						|
			res = hawk_rtx_makefltval(rtx, r);
 | 
						|
			if (HAWK_UNLIKELY(!res))
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, left);
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			res2 = hawk_rtx_makefltval(rtx, r + inc_val_flt);
 | 
						|
			if (HAWK_UNLIKELY(!res2))
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, left);
 | 
						|
				hawk_rtx_freeval(rtx, res, HAWK_RTX_FREEVAL_CACHE);
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		default:
 | 
						|
		{
 | 
						|
			hawk_int_t v1;
 | 
						|
			hawk_flt_t v2;
 | 
						|
			int n;
 | 
						|
 | 
						|
			n = hawk_rtx_valtonum(rtx, left, &v1, &v2);
 | 
						|
			if (HAWK_UNLIKELY(n <= -1))
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, left);
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			if (n == 0)
 | 
						|
			{
 | 
						|
				res = hawk_rtx_makeintval(rtx, v1);
 | 
						|
				if (HAWK_UNLIKELY(!res))
 | 
						|
				{
 | 
						|
					hawk_rtx_refdownval(rtx, left);
 | 
						|
					ADJERR_LOC(rtx, &nde->loc);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
 | 
						|
				res2 = hawk_rtx_makeintval(rtx, v1 + inc_val_int);
 | 
						|
				if (HAWK_UNLIKELY(!res2))
 | 
						|
				{
 | 
						|
					hawk_rtx_refdownval(rtx, left);
 | 
						|
					hawk_rtx_freeval(rtx, res, HAWK_RTX_FREEVAL_CACHE);
 | 
						|
					ADJERR_LOC(rtx, &nde->loc);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else /* if (n == 1) */
 | 
						|
			{
 | 
						|
				HAWK_ASSERT(n == 1);
 | 
						|
				res = hawk_rtx_makefltval(rtx, v2);
 | 
						|
				if (HAWK_UNLIKELY(!res))
 | 
						|
				{
 | 
						|
					hawk_rtx_refdownval(rtx, left);
 | 
						|
					ADJERR_LOC(rtx, &nde->loc);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
 | 
						|
				res2 = hawk_rtx_makefltval(rtx, v2 + inc_val_flt);
 | 
						|
				if (HAWK_UNLIKELY(!res2))
 | 
						|
				{
 | 
						|
					hawk_rtx_refdownval(rtx, left);
 | 
						|
					hawk_rtx_freeval(rtx, res, HAWK_RTX_FREEVAL_CACHE);
 | 
						|
					ADJERR_LOC(rtx, &nde->loc);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(do_assignment(rtx, exp->left, res2) == HAWK_NULL))
 | 
						|
	{
 | 
						|
		hawk_rtx_refdownval(rtx, left);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	hawk_rtx_refdownval(rtx, left);
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_cnd (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* tv, * v;
 | 
						|
	hawk_nde_cnd_t* cnd = (hawk_nde_cnd_t*)nde;
 | 
						|
 | 
						|
	HAWK_ASSERT(cnd->test->next == HAWK_NULL);
 | 
						|
 | 
						|
	tv = eval_expression(rtx, cnd->test);
 | 
						|
	if (HAWK_UNLIKELY(!tv)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, tv);
 | 
						|
 | 
						|
	HAWK_ASSERT(cnd->left->next == HAWK_NULL && cnd->right->next == HAWK_NULL);
 | 
						|
	v = (hawk_rtx_valtobool(rtx, tv))? eval_expression(rtx, cnd->left): eval_expression(rtx, cnd->right);
 | 
						|
 | 
						|
	hawk_rtx_refdownval(rtx, tv);
 | 
						|
	return v;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_fncall_fnc (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	/* intrinsic function */
 | 
						|
	hawk_nde_fncall_t* call = (hawk_nde_fncall_t*)nde;
 | 
						|
	/* the parser must make sure that the number of arguments is proper */
 | 
						|
	HAWK_ASSERT(call->nargs >= call->u.fnc.spec.arg.min && call->nargs <= call->u.fnc.spec.arg.max);
 | 
						|
	return hawk_rtx_evalcall(rtx, call, HAWK_NULL, push_arg_from_nde, (void*)call->u.fnc.spec.arg.spec, HAWK_NULL, HAWK_NULL);
 | 
						|
}
 | 
						|
 | 
						|
static HAWK_INLINE hawk_val_t* eval_fncall_fun (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	/* user-defined function */
 | 
						|
	hawk_nde_fncall_t* call = (hawk_nde_fncall_t*)nde;
 | 
						|
	hawk_fun_t* fun;
 | 
						|
	hawk_htb_pair_t* pair;
 | 
						|
 | 
						|
	if (!call->u.fun.fun)
 | 
						|
	{
 | 
						|
		/* there can be multiple runtime instances for a single hawk object.
 | 
						|
		 * changing the parse tree from one runtime instance can affect
 | 
						|
		 * other instances. however i do change the parse tree without protection
 | 
						|
		 * hoping that the pointer assignment is atomic. (call->u.fun.fun = fun).
 | 
						|
		 * i don't mind each instance performs a search duplicately for a short while */
 | 
						|
 | 
						|
		pair = hawk_htb_search(rtx->hawk->tree.funs, call->u.fun.name.ptr, call->u.fun.name.len);
 | 
						|
		if (!pair)
 | 
						|
		{
 | 
						|
			hawk_rtx_seterrfmt(rtx, &nde->loc, HAWK_EFUNNF, HAWK_T("function '%.*js' not found"), call->u.fun.name.len, call->u.fun.name.ptr);
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
 | 
						|
		fun = (hawk_fun_t*)HAWK_HTB_VPTR(pair);
 | 
						|
		HAWK_ASSERT(fun != HAWK_NULL);
 | 
						|
 | 
						|
		/* cache the search result */
 | 
						|
		call->u.fun.fun = fun;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		/* use the cached function */
 | 
						|
		fun = call->u.fun.fun;
 | 
						|
	}
 | 
						|
 | 
						|
	if (call->nargs > fun->nargs && !fun->variadic)
 | 
						|
	{
 | 
						|
		/* TODO: is this correct? what if i want to
 | 
						|
		 *       allow arbitarary numbers of arguments? */
 | 
						|
		hawk_rtx_seterrfmt(rtx, &nde->loc, HAWK_EARGTM, HAWK_T("too many arguments to '%.*js'"), fun->name.len, fun->name.ptr);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	/* push_arg_from_nde() has special handling for references when the function
 | 
						|
	 * argument spec contains 'r' or 'R'.
 | 
						|
	 * a reference is passed to a built-in function as a reference value
 | 
						|
	 * but its evaluation result is passed to user-defined function.
 | 
						|
	 * I pass HAWK_NULL to prevent special handling.
 | 
						|
	 * the value change for a reference variable inside a user-defined function is
 | 
						|
	 * reflected by hawk_rtx_evalcall() specially whereas a built-in function must
 | 
						|
	 * call hawk_rtx_setrefval() to update the reference.
 | 
						|
	 */
 | 
						|
	return hawk_rtx_evalcall(rtx, call, fun, push_arg_from_nde, HAWK_NULL/*fun->argspec*/, HAWK_NULL, HAWK_NULL);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_fncall_var (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_nde_fncall_t* call = (hawk_nde_fncall_t*)nde;
 | 
						|
	hawk_val_t* fv, * rv;
 | 
						|
	hawk_fun_t* fun;
 | 
						|
 | 
						|
	fv = eval_expression(rtx, (hawk_nde_t*)call->u.var.var);
 | 
						|
	if (HAWK_UNLIKELY(!fv)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, fv);
 | 
						|
	fun = hawk_rtx_valtofun(rtx, fv);
 | 
						|
	if (HAWK_UNLIKELY(!fun))
 | 
						|
	{
 | 
						|
		if (hawk_rtx_geterrnum(rtx) == HAWK_EINVAL)
 | 
						|
			hawk_rtx_seterrfmt(rtx, &nde->loc, HAWK_ENOTFUN, HAWK_T("non-function value in %.*js"), call->u.var.var->id.name.len, call->u.var.var->id.name.ptr);
 | 
						|
		ADJERR_LOC(rtx, &nde->loc);
 | 
						|
		rv = HAWK_NULL;
 | 
						|
	}
 | 
						|
	else if (call->nargs > fun->nargs && !fun->variadic)
 | 
						|
	{
 | 
						|
		/* TODO: is this correct? what if i want to
 | 
						|
		*       allow arbitarary numbers of arguments? */
 | 
						|
		hawk_rtx_seterrfmt(rtx, &nde->loc, HAWK_EARGTM, HAWK_T("too many arguments to '%.*js'"), fun->name.len, fun->name.ptr);
 | 
						|
		rv = HAWK_NULL;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		/* pass HAWK_NULL for the argument spec regardless of the actual spec.
 | 
						|
		 * see comments in eval_fncall_fun() for more */
 | 
						|
		rv = hawk_rtx_evalcall(rtx, call, fun, push_arg_from_nde, HAWK_NULL/*fun->argspec*/, HAWK_NULL, HAWK_NULL);
 | 
						|
	}
 | 
						|
	hawk_rtx_refdownval(rtx, fv);
 | 
						|
 | 
						|
	return rv;
 | 
						|
}
 | 
						|
 | 
						|
hawk_val_t* hawk_rtx_evalcall (
 | 
						|
	hawk_rtx_t* rtx, hawk_nde_fncall_t* call, hawk_fun_t* fun,
 | 
						|
	hawk_oow_t(*argpusher)(hawk_rtx_t*,hawk_nde_fncall_t*,void*), void* apdata,
 | 
						|
	void(*errhandler)(void*), void* eharg)
 | 
						|
{
 | 
						|
	hawk_oow_t saved_stack_top, saved_arg_stack_top;
 | 
						|
	hawk_oow_t nargs, i, stack_req;
 | 
						|
	hawk_val_t* v;
 | 
						|
	int n;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * ---------------------
 | 
						|
	 *  lcln               <- stack top
 | 
						|
	 * ---------------------
 | 
						|
	 *  ....
 | 
						|
	 * ---------------------
 | 
						|
	 *  lcl0               local variables are pushed by run_block
 | 
						|
	 * =====================
 | 
						|
	 *  argn
 | 
						|
	 * ---------------------
 | 
						|
	 *  ....
 | 
						|
	 * ---------------------
 | 
						|
	 *  arg1
 | 
						|
	 * ---------------------
 | 
						|
	 *  arg0
 | 
						|
	 * ---------------------
 | 
						|
	 *  nargs
 | 
						|
	 * ---------------------
 | 
						|
	 *  return value
 | 
						|
	 * ---------------------
 | 
						|
	 *  previous stack top
 | 
						|
	 * ---------------------
 | 
						|
	 *  previous stack base  <- stack base
 | 
						|
	 * =====================
 | 
						|
	 *  0 (nargs)            <- stack top
 | 
						|
	 * ---------------------
 | 
						|
	 *  return value
 | 
						|
	 * ---------------------
 | 
						|
	 *  previous stack top
 | 
						|
	 * ---------------------
 | 
						|
	 *  previous stack base  <- stack base
 | 
						|
	 * =====================
 | 
						|
	 *  gbln
 | 
						|
	 * ---------------------
 | 
						|
	 *  ....
 | 
						|
	 * ---------------------
 | 
						|
	 *  gbl0
 | 
						|
	 * ---------------------
 | 
						|
	 */
 | 
						|
 | 
						|
	HAWK_ASSERT(HAWK_SIZEOF(void*) >= HAWK_SIZEOF(rtx->stack_top));
 | 
						|
	HAWK_ASSERT(HAWK_SIZEOF(void*) >= HAWK_SIZEOF(rtx->stack_base));
 | 
						|
 | 
						|
	saved_stack_top = rtx->stack_top;
 | 
						|
 | 
						|
#if defined(DEBUG_RUN)
 | 
						|
	hawk_logbfmt (hawk_rtx_gethawk(rtx), "setting up function stack frame top=%zd base=%zd\n", (hawk_oow_t)rtx->stack_top, (hawk_oow_t)rtx->stack_base);
 | 
						|
#endif
 | 
						|
 | 
						|
	/* make a new stack frame */
 | 
						|
	stack_req = 4 + call->nargs;
 | 
						|
	if (fun && fun->nargs > call->nargs)
 | 
						|
	{
 | 
						|
		/* for variadic functions, fun->nargs can be less than call->nargs.
 | 
						|
		 * for non-variadic functions, the compiler must guarantee that fun->nargs >= call->nargs
 | 
						|
		 * this case can happen for  for non-variadic functions only. */
 | 
						|
		stack_req += fun->nargs - call->nargs;
 | 
						|
	}
 | 
						|
	/* if fun is HAWK_NULL, there is no way for this function to know expected argument numbers.
 | 
						|
	 * the argument pusher must ensure the stack availality before pushing arguments */
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < stack_req))
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &call->loc, HAWK_ESTACK);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	HAWK_RTX_STACK_PUSH(rtx, (void*)rtx->stack_base);
 | 
						|
	HAWK_RTX_STACK_PUSH(rtx, (void*)saved_stack_top);
 | 
						|
	HAWK_RTX_STACK_PUSH(rtx, hawk_val_nil); /* space for return value */
 | 
						|
	HAWK_RTX_STACK_PUSH(rtx, hawk_val_nil); /* space for number of arguments */
 | 
						|
 | 
						|
	saved_arg_stack_top = rtx->stack_top;
 | 
						|
 | 
						|
	/* push all arguments onto the stack */
 | 
						|
	nargs = argpusher(rtx, call, apdata);
 | 
						|
	if (nargs == (hawk_oow_t)-1) goto oops_making_stack_frame;
 | 
						|
 | 
						|
	HAWK_ASSERT(nargs == call->nargs);
 | 
						|
 | 
						|
	if (fun)
 | 
						|
	{
 | 
						|
		/* extra step for normal hawk functions */
 | 
						|
		while (nargs < fun->nargs)
 | 
						|
		{
 | 
						|
			/* push as many nils as the number of missing actual arguments */
 | 
						|
			HAWK_RTX_STACK_PUSH(rtx, hawk_val_nil);
 | 
						|
			nargs++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* entering a new stack frame */
 | 
						|
	rtx->stack_base = saved_stack_top;
 | 
						|
	HAWK_RTX_STACK_NARGS(rtx) = (void*)nargs;
 | 
						|
 | 
						|
#if defined(DEBUG_RUN)
 | 
						|
	hawk_logbfmt (hawk_rtx_gethawk(rtx), "running function body\n");
 | 
						|
#endif
 | 
						|
 | 
						|
	if (fun)
 | 
						|
	{
 | 
						|
		/* normal hawk function */
 | 
						|
		HAWK_ASSERT(fun->body->type == HAWK_NDE_BLK);
 | 
						|
		n = run_block(rtx, (hawk_nde_blk_t*)fun->body);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		n = 0;
 | 
						|
 | 
						|
		/* intrinsic function */
 | 
						|
		HAWK_ASSERT(call->nargs >= call->u.fnc.spec.arg.min && call->nargs <= call->u.fnc.spec.arg.max);
 | 
						|
 | 
						|
		if (call->u.fnc.spec.impl)
 | 
						|
		{
 | 
						|
			n = call->u.fnc.spec.impl(rtx, &call->u.fnc.info);
 | 
						|
			if (HAWK_UNLIKELY(n <= -1)) ADJERR_LOC(rtx, &call->loc);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* refdown args in the rtx.stack */
 | 
						|
	nargs = (hawk_oow_t)HAWK_RTX_STACK_NARGS(rtx);
 | 
						|
#if defined(DEBUG_RUN)
 | 
						|
	hawk_logbfmt (hawk_rtx_gethawk(rtx), "block rtx complete nargs = %d\n", (int)nargs);
 | 
						|
#endif
 | 
						|
 | 
						|
	i = 0;
 | 
						|
	if (fun && fun->argspec && call->nargs > 0)  /* hawk_rtx_callfun() sets up a fake call structure with call->nargs > 0 but call->args == HAWK_NULL */
 | 
						|
	{
 | 
						|
		/* set back the values for pass-by-reference parameters of normal functions.
 | 
						|
		 * the intrinsic functions are not handled here but their implementation would
 | 
						|
		 * call hawk_rtx_setrefval() */
 | 
						|
 | 
						|
		/* even if fun->argspec exists, call->nargs may still be 0. so i test if call->nargs > 0.
 | 
						|
		 *   function x(a1, &a2) {}
 | 
						|
		 *   BEGIN { x(); }
 | 
						|
		 * all parameters are @nils in this case. nargs and fun->nargs are 2 but call->nargs is 0.
 | 
						|
		 */
 | 
						|
 | 
						|
		if (call->args)
 | 
						|
		{
 | 
						|
			hawk_oow_t cur_stack_base = rtx->stack_base;
 | 
						|
			hawk_oow_t prev_stack_base = (hawk_oow_t)rtx->stack[rtx->stack_base + 0];
 | 
						|
			hawk_nde_t* p = call->args;
 | 
						|
 | 
						|
			for (; i < call->nargs; i++)
 | 
						|
			{
 | 
						|
				if (n >= 0 && i < fun->argspeclen && (fun->argspec[i] == 'r' || fun->argspec[i] == 'R'))
 | 
						|
				{
 | 
						|
					/* if the function call is successful, update the call-by-reference arguments
 | 
						|
					 * with hawk_rtx_setrefval() */
 | 
						|
 | 
						|
					hawk_val_t** ref;
 | 
						|
					hawk_val_ref_t refv;
 | 
						|
					hawk_val_t* av;
 | 
						|
					int r;
 | 
						|
 | 
						|
					av = HAWK_RTX_STACK_ARG(rtx, i);
 | 
						|
					if (HAWK_RTX_GETVALTYPE(rtx, av) == HAWK_VAL_REF)
 | 
						|
					{
 | 
						|
						/* the argument still has the reference type.
 | 
						|
						 * this means, the argument has not been set.
 | 
						|
						 *
 | 
						|
						 *   function f1(&a, &b) { b = 20 }
 | 
						|
						 *
 | 
						|
						 * since a is not set in f1, the value for a is still the pushed value which is a reference
 | 
						|
						 */
 | 
						|
 | 
						|
						/* ---- DO NOTHING ---- */
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						/* if an argument passed is a local variable or a parameter to the previous caller,
 | 
						|
						 * the argument node information stored is relative to the previous stack frame.
 | 
						|
						 * i revert rtx->stack_base to the previous stack frame base before calling
 | 
						|
						 * get_reference() and restors it back to the current base. this tactic
 | 
						|
						 * is very ugly because the assumption for this is dependent on get_reference()
 | 
						|
						 * implementation */
 | 
						|
						rtx->stack_base = prev_stack_base; /* UGLY */
 | 
						|
						r = get_reference(rtx, p, &ref);
 | 
						|
						rtx->stack_base = cur_stack_base; /* UGLY */
 | 
						|
 | 
						|
						/* if argspec is 'r', get_reference() must succeed all the time.
 | 
						|
						 * if argspec is 'R', it may fail. if it happens, don't copy the value */
 | 
						|
						if (HAWK_LIKELY(r >= 0))
 | 
						|
						{
 | 
						|
							HAWK_RTX_INIT_REF_VAL (&refv, p->type - HAWK_NDE_NAMED, ref, 9); /* initialize a fake reference variable. 9 chosen randomly */
 | 
						|
							if (HAWK_UNLIKELY(hawk_rtx_setrefval(rtx, &refv, av) <= -1))
 | 
						|
							{
 | 
						|
								n = -1;
 | 
						|
								ADJERR_LOC(rtx, &call->loc);
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				hawk_rtx_refdownval(rtx, HAWK_RTX_STACK_ARG(rtx,i));
 | 
						|
				p = p->next;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (call->arg_base > 0) /* special case. set by hawk::call() */
 | 
						|
		{
 | 
						|
			/*
 | 
						|
			 *  function f1(a,&b) { b *= 20; }
 | 
						|
			 *  BEGIN { q = 4; hawk::call(r, "f1", 20, q); print q; }
 | 
						|
			 *
 | 
						|
			 * the fourth argument to hawk::call() must map to the second argument to f1().
 | 
						|
			 * hawk::call() accepts the third to the last arguments as reference if possible.
 | 
						|
			 * this function attempts to copy back the pass-by-reference values to
 | 
						|
			 * one stack frame up.
 | 
						|
			 *
 | 
						|
			 *  f1(1, 2) is an error as 2 is not referenceable.
 | 
						|
			 *  hakw::call(r, "f1", 1, 2) is not an error but can't capture changes made inside f1.
 | 
						|
			 */
 | 
						|
			for (; i < call->nargs; i++)
 | 
						|
			{
 | 
						|
				if (n >= 0 && (fun->argspec[i] == 'r' || fun->argspec[i] == 'R'))
 | 
						|
				{
 | 
						|
					hawk_val_t* v, * av;
 | 
						|
 | 
						|
					av = HAWK_RTX_STACK_ARG(rtx, i);
 | 
						|
					if (HAWK_RTX_GETVALTYPE(rtx, av) == HAWK_VAL_REF)
 | 
						|
					{
 | 
						|
						/* ---- DO NOTHING ---- */
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						v = rtx->stack[call->arg_base + i]; /* UGLY */
 | 
						|
						if (HAWK_RTX_GETVALTYPE(rtx, v) == HAWK_VAL_REF)
 | 
						|
						{
 | 
						|
							if (HAWK_UNLIKELY(hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)v, av) <= -1))
 | 
						|
							{
 | 
						|
								n = -1;
 | 
						|
								ADJERR_LOC(rtx, &call->loc);
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				hawk_rtx_refdownval(rtx, HAWK_RTX_STACK_ARG(rtx,i));
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for (; i < nargs; i++)
 | 
						|
	{
 | 
						|
		hawk_rtx_refdownval(rtx, HAWK_RTX_STACK_ARG(rtx,i));
 | 
						|
	}
 | 
						|
 | 
						|
#if defined(DEBUG_RUN)
 | 
						|
	hawk_logbfmt (hawk_rtx_gethawk(rtx), "got return value\n");
 | 
						|
#endif
 | 
						|
 | 
						|
	v = HAWK_RTX_STACK_RETVAL(rtx);
 | 
						|
	if (HAWK_UNLIKELY(n <= -1))
 | 
						|
	{
 | 
						|
		if (hawk_rtx_geterrnum(rtx) == HAWK_ENOERR && errhandler != HAWK_NULL)
 | 
						|
		{
 | 
						|
			/* errhandler is passed only when hawk_rtx_evalcall() is
 | 
						|
			 * invoked from hawk_rtx_call(). Under this
 | 
						|
			 * circumstance, this stack frame is the first
 | 
						|
			 * activated and the stack base is the first element
 | 
						|
			 * after the global variables. so HAWK_RTX_STACK_RETVAL(rtx)
 | 
						|
			 * effectively becomes HAWK_RTX_STACK_RETVAL_GBL(rtx).
 | 
						|
			 * As hawk_rtx_evalcall() returns HAWK_NULL on error and
 | 
						|
			 * the reference count of HAWK_RTX_STACK_RETVAL(rtx) should be
 | 
						|
			 * decremented, it can't get the return value
 | 
						|
			 * if it turns out to be terminated by exit().
 | 
						|
			 * The return value could be destroyed by then.
 | 
						|
			 * Unlikely, rtx_bpae_loop() just checks if rtx->errinf.num
 | 
						|
			 * is HAWK_ENOERR and gets HAWK_RTX_STACK_RETVAL_GBL(rtx)
 | 
						|
			 * to determine if it is terminated by exit().
 | 
						|
			 *
 | 
						|
			 * The handler capture_retval_on_exit()
 | 
						|
			 * increments the reference of HAWK_RTX_STACK_RETVAL(rtx)
 | 
						|
			 * and stores the pointer into accompanying space.
 | 
						|
			 * This way, the return value is preserved upon
 | 
						|
			 * termination by exit() out to the caller.
 | 
						|
			 */
 | 
						|
			errhandler (eharg);
 | 
						|
		}
 | 
						|
 | 
						|
		/* if the earlier operations failed and this function
 | 
						|
		 * has to return a error, the return value is just
 | 
						|
		 * destroyed and replaced by nil */
 | 
						|
		hawk_rtx_refdownval(rtx, v);
 | 
						|
		HAWK_RTX_STACK_RETVAL(rtx) = hawk_val_nil;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		/* this trick has been mentioned in rtx_return.
 | 
						|
		 * adjust the reference count of the return value.
 | 
						|
		 * the value must not be freed even if the reference count
 | 
						|
		 * reached zero because its reference has been incremented
 | 
						|
		 * in rtx_return or directly by hawk_rtx_setretval()
 | 
						|
		 * regardless of its reference count. */
 | 
						|
		hawk_rtx_refdownval_nofree(rtx, v);
 | 
						|
	}
 | 
						|
 | 
						|
	rtx->stack_top =  (hawk_oow_t)rtx->stack[rtx->stack_base + 1];
 | 
						|
	rtx->stack_base = (hawk_oow_t)rtx->stack[rtx->stack_base + 0];
 | 
						|
 | 
						|
	if (rtx->exit_level == EXIT_FUNCTION) rtx->exit_level = EXIT_NONE;
 | 
						|
 | 
						|
#if defined(DEBUG_RUN)
 | 
						|
	hawk_logbfmt (hawk_rtx_gethawk(rtx), "returning from function top=%zd, base=%zd\n", (hawk_oow_t)rtx->stack_top, (hawk_oow_t)rtx->stack_base);
 | 
						|
#endif
 | 
						|
	return (n <= -1)? HAWK_NULL: v;
 | 
						|
 | 
						|
oops_making_stack_frame:
 | 
						|
	while (rtx->stack_top > saved_arg_stack_top)
 | 
						|
	{
 | 
						|
		/* call hawk_rtx_refdownval() for all arguments.
 | 
						|
		 * it is safe because nil or quickint is immune to excessive hawk_rtx_refdownval() calls */
 | 
						|
		hawk_rtx_refdownval(rtx, rtx->stack[rtx->stack_top - 1]);
 | 
						|
		HAWK_RTX_STACK_POP (rtx);
 | 
						|
	}
 | 
						|
	HAWK_ASSERT(rtx->stack_top - saved_stack_top == 4);
 | 
						|
	while (rtx->stack_top > saved_stack_top)
 | 
						|
	{
 | 
						|
		/* the stack frame prologue does not have a reference-counted value
 | 
						|
		 * before being entered. so no hawk_rtx_refdownval().
 | 
						|
		 * three slots contains raw integers for internal use.. only one
 | 
						|
		 * slot that contains the return value would be reference counted
 | 
						|
		 * after it is set to a reference counted value. here, it never happens */
 | 
						|
		HAWK_RTX_STACK_POP (rtx);
 | 
						|
	}
 | 
						|
	ADJERR_LOC(rtx, &call->loc);
 | 
						|
	return HAWK_NULL;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_oow_t push_arg_from_vals (hawk_rtx_t* rtx, hawk_nde_fncall_t* call, void* data)
 | 
						|
{
 | 
						|
	struct pafv_t* pafv = (struct pafv_t*)data;
 | 
						|
	hawk_oow_t nargs = 0;
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < pafv->nargs))
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &call->loc, HAWK_ESTACK);
 | 
						|
		return (hawk_oow_t)-1;
 | 
						|
	}
 | 
						|
 | 
						|
	for (nargs = 0; nargs < pafv->nargs; nargs++)
 | 
						|
	{
 | 
						|
		if (pafv->argspec && (pafv->argspec[nargs] == 'r' || pafv->argspec[nargs] == 'R'))
 | 
						|
		{
 | 
						|
			hawk_val_t** ref;
 | 
						|
			hawk_val_t* v;
 | 
						|
 | 
						|
			ref = (hawk_val_t**)&pafv->args[nargs];
 | 
						|
			v = hawk_rtx_makerefval(rtx, HAWK_VAL_REF_LCL, ref); /* this type(HAWK_VAL_REF_LCL) is fake */
 | 
						|
			if (HAWK_UNLIKELY(!v))
 | 
						|
			{
 | 
						|
				ADJERR_LOC(rtx, &call->loc);
 | 
						|
				return (hawk_oow_t)-1;
 | 
						|
			}
 | 
						|
 | 
						|
			HAWK_RTX_STACK_PUSH(rtx, v);
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			HAWK_RTX_STACK_PUSH(rtx, pafv->args[nargs]);
 | 
						|
			hawk_rtx_refupval(rtx, pafv->args[nargs]);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nargs;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_oow_t push_arg_from_nde (hawk_rtx_t* rtx, hawk_nde_fncall_t* call, void* data)
 | 
						|
{
 | 
						|
	hawk_nde_t* p;
 | 
						|
	hawk_val_t* v;
 | 
						|
	hawk_oow_t nargs;
 | 
						|
	const hawk_ooch_t* arg_spec = (const hawk_ooch_t*)data;
 | 
						|
	hawk_oow_t spec_len;
 | 
						|
 | 
						|
	if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < call->nargs))
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &call->loc, HAWK_ESTACK);
 | 
						|
		return (hawk_oow_t)-1;
 | 
						|
	}
 | 
						|
 | 
						|
	/* in practice, this function gets NULL for a user-defined function regardless of its actual spec.
 | 
						|
	 * it may get a non-NULL arg_spec for builtin/module functions */
 | 
						|
	spec_len = arg_spec? hawk_count_oocstr(arg_spec): 0;
 | 
						|
	for (p = call->args, nargs = 0; p; p = p->next, nargs++)
 | 
						|
	{
 | 
						|
		hawk_ooch_t spec;
 | 
						|
 | 
						|
		/* if not sufficient number of spec characters given, take the last value and use it.
 | 
						|
		 * as said above, arg_spec is provided for the implicit functions only.
 | 
						|
		 * so the logic taking the last value at run-time is elsewhere (e.g hawk_rtx_evalcall()). */
 | 
						|
		spec = (spec_len <= 0)? '\0': arg_spec[((nargs < spec_len)? nargs: spec_len - 1)];
 | 
						|
 | 
						|
		switch (spec)
 | 
						|
		{
 | 
						|
			case 'R': /* make reference if a referenceable is given. otherwise accept a normal value - useful for hawk::call() */
 | 
						|
			case 'r': /* make reference. a non-referenceable value is rejected */
 | 
						|
			{
 | 
						|
				hawk_val_t** ref;
 | 
						|
 | 
						|
				if (get_reference(rtx, p, &ref) <= -1)
 | 
						|
				{
 | 
						|
					if (spec == 'R') goto normal_arg;
 | 
						|
					return (hawk_oow_t)-1; /* return -1 without unwinding stack as hawk_rtx_evalcall() does it */
 | 
						|
				}
 | 
						|
 | 
						|
				/* 'p->type - HAWK_NDE_NAMED' must produce a relevant HAWK_VAL_REF_XXX value. */
 | 
						|
				v = hawk_rtx_makerefval(rtx, p->type - HAWK_NDE_NAMED, ref);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			case 'x':
 | 
						|
				/* a regular expression is passed to the function as it is */
 | 
						|
				v = eval_expression0(rtx, p);
 | 
						|
				break;
 | 
						|
 | 
						|
			default:
 | 
						|
			normal_arg:
 | 
						|
				v = eval_expression(rtx, p);
 | 
						|
				break;
 | 
						|
		}
 | 
						|
 | 
						|
		if (HAWK_UNLIKELY(!v)) return (hawk_oow_t)-1; /* return -1 without unwinding stack as hawk_rtx_evalcall() does it */
 | 
						|
 | 
						|
		HAWK_RTX_STACK_PUSH(rtx, v);
 | 
						|
		hawk_rtx_refupval(rtx, v);
 | 
						|
	}
 | 
						|
 | 
						|
	HAWK_ASSERT(call->nargs == nargs);
 | 
						|
	return nargs;
 | 
						|
}
 | 
						|
 | 
						|
static int get_reference (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_val_t*** ref)
 | 
						|
{
 | 
						|
	hawk_nde_var_t* tgt = (hawk_nde_var_t*)nde;
 | 
						|
	hawk_val_t** tmp;
 | 
						|
 | 
						|
	/* refer to eval_indexed for application of a similar concept */
 | 
						|
 | 
						|
	switch (nde->type)
 | 
						|
	{
 | 
						|
		case HAWK_NDE_NAMED:
 | 
						|
		{
 | 
						|
			hawk_htb_pair_t* pair;
 | 
						|
 | 
						|
			pair = hawk_htb_search(rtx->named, tgt->id.name.ptr, tgt->id.name.len);
 | 
						|
			if (pair == HAWK_NULL)
 | 
						|
			{
 | 
						|
				/* it is bad that the named variable has to be created here.
 | 
						|
				 * would there be any better ways to avoid this? */
 | 
						|
				pair = hawk_htb_upsert(rtx->named, tgt->id.name.ptr, tgt->id.name.len, hawk_val_nil, 0);
 | 
						|
				if (!pair)
 | 
						|
				{
 | 
						|
					ADJERR_LOC(rtx, &nde->loc);
 | 
						|
					return -1;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			*ref = (hawk_val_t**)&HAWK_HTB_VPTR(pair);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
 | 
						|
		case HAWK_NDE_GBL:
 | 
						|
			/* *ref = (hawk_val_t**)&HAWK_RTX_STACK_GBL(rtx,tgt->id.idxa); */
 | 
						|
			*ref = (hawk_val_t**)((hawk_oow_t)tgt->id.idxa);
 | 
						|
			return 0;
 | 
						|
 | 
						|
		case HAWK_NDE_LCL:
 | 
						|
			*ref = (hawk_val_t**)&HAWK_RTX_STACK_LCL(rtx,tgt->id.idxa);
 | 
						|
			return 0;
 | 
						|
 | 
						|
		case HAWK_NDE_ARG:
 | 
						|
			*ref = (hawk_val_t**)&HAWK_RTX_STACK_ARG(rtx,tgt->id.idxa);
 | 
						|
			return 0;
 | 
						|
 | 
						|
		case HAWK_NDE_NAMEDIDX:
 | 
						|
		case HAWK_NDE_GBLIDX:
 | 
						|
		case HAWK_NDE_LCLIDX:
 | 
						|
		case HAWK_NDE_ARGIDX:
 | 
						|
			tmp = get_reference_indexed(rtx, tgt);
 | 
						|
			if (HAWK_UNLIKELY(!tmp)) return -1;
 | 
						|
			*ref = tmp;
 | 
						|
			return 0;
 | 
						|
 | 
						|
		case HAWK_NDE_POS:
 | 
						|
		{
 | 
						|
			int n;
 | 
						|
			hawk_int_t lv;
 | 
						|
			hawk_val_t* v;
 | 
						|
 | 
						|
			/* the position number is returned for the positional
 | 
						|
			 * variable unlike other reference types. */
 | 
						|
			v = eval_expression(rtx, ((hawk_nde_pos_t*)nde)->val);
 | 
						|
			if (HAWK_UNLIKELY(!v)) return -1;
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
			n = hawk_rtx_valtoint(rtx, v, &lv);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
 | 
						|
			if (HAWK_UNLIKELY(n <= -1))
 | 
						|
			{
 | 
						|
				hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EPOSIDX);
 | 
						|
				return -1;
 | 
						|
			}
 | 
						|
 | 
						|
			if (!IS_VALID_POSIDX(lv))
 | 
						|
			{
 | 
						|
				hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EPOSIDX);
 | 
						|
				return -1;
 | 
						|
			}
 | 
						|
 | 
						|
			*ref = (hawk_val_t**)((hawk_oow_t)lv);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
 | 
						|
		default:
 | 
						|
			hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_ENOTREF);
 | 
						|
			return -1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t** get_reference_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var)
 | 
						|
{
 | 
						|
	hawk_map_t* map;
 | 
						|
	hawk_ooch_t* str = HAWK_NULL;
 | 
						|
	hawk_oow_t len;
 | 
						|
	hawk_ooch_t idxbuf[HAWK_IDX_BUF_SIZE];
 | 
						|
 | 
						|
	hawk_arr_t* arr;
 | 
						|
	hawk_ooi_t idx;
 | 
						|
 | 
						|
	hawk_val_t* v;
 | 
						|
	hawk_val_type_t vtype;
 | 
						|
	hawk_nde_t* remidx;
 | 
						|
 | 
						|
	HAWK_ASSERT(var->idx != HAWK_NULL);
 | 
						|
 | 
						|
	v = fetch_topval_from_var(rtx, var);
 | 
						|
	vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | 
						|
 | 
						|
	switch (vtype)
 | 
						|
	{
 | 
						|
		case HAWK_VAL_NIL:
 | 
						|
			v = assign_newmapval_to_var(rtx, var);
 | 
						|
			if (HAWK_UNLIKELY(!v)) goto oops;
 | 
						|
			vtype = HAWK_VAL_MAP;
 | 
						|
			goto val_map_init;
 | 
						|
 | 
						|
		case HAWK_VAL_MAP:
 | 
						|
		val_map_init:
 | 
						|
			len = HAWK_COUNTOF(idxbuf);
 | 
						|
			str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx, HAWK_NULL);
 | 
						|
			if (HAWK_UNLIKELY(!str)) goto oops;
 | 
						|
			map = ((hawk_val_map_t*)v)->map;
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_VAL_ARR:
 | 
						|
			idx = idxnde_to_int(rtx, var->idx, &remidx);
 | 
						|
			if (HAWK_UNLIKELY(idx <= -1)) goto oops;
 | 
						|
			arr = ((hawk_val_arr_t*)v)->arr;
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			hawk_rtx_seterrnum(rtx, &var->loc, HAWK_ENOTIDXACC);
 | 
						|
			goto oops;
 | 
						|
	}
 | 
						|
 | 
						|
#if defined(HAWK_ENABLE_GC)
 | 
						|
	while (remidx)
 | 
						|
	{
 | 
						|
		hawk_val_type_t container_vtype;
 | 
						|
 | 
						|
		if (vtype == HAWK_VAL_MAP)
 | 
						|
		{
 | 
						|
			hawk_map_pair_t* pair;
 | 
						|
			pair = hawk_map_search(map, str, len);
 | 
						|
			v = pair? (hawk_val_t*)HAWK_MAP_VPTR(pair): hawk_val_nil;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			v = (idx < HAWK_ARR_SIZE(arr) && HAWK_ARR_SLOT(arr, idx))? ((hawk_val_t*)HAWK_ARR_DPTR(arr, idx)): hawk_val_nil;
 | 
						|
		}
 | 
						|
		container_vtype = vtype;
 | 
						|
		vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | 
						|
 | 
						|
		switch (vtype)
 | 
						|
		{
 | 
						|
			case HAWK_VAL_MAP:
 | 
						|
			val_map:
 | 
						|
				if (str && str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
				len = HAWK_COUNTOF(idxbuf);
 | 
						|
				str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx, HAWK_NULL);
 | 
						|
				if (HAWK_UNLIKELY(!str)) goto oops;
 | 
						|
				map = ((hawk_val_map_t*)v)->map;
 | 
						|
				break;
 | 
						|
 | 
						|
			case HAWK_VAL_ARR:
 | 
						|
			val_arr:
 | 
						|
				idx = idxnde_to_int(rtx, remidx, &remidx);
 | 
						|
				if (HAWK_UNLIKELY(idx <= -1)) goto oops;
 | 
						|
				arr = ((hawk_val_arr_t*)v)->arr;
 | 
						|
				break;
 | 
						|
 | 
						|
			default:
 | 
						|
				if (vtype == HAWK_VAL_NIL /* || (rtx->hawk->opt.trait & HAWK_FLEXMAP) no flexmap because this is in a 'get' context */)
 | 
						|
				{
 | 
						|
					if (container_vtype == HAWK_VAL_MAP)
 | 
						|
					{
 | 
						|
						v = assign_newmapval_in_map(rtx, map, str, len);
 | 
						|
						if (HAWK_UNLIKELY(!v)) { ADJERR_LOC(rtx, &var->loc); goto oops; }
 | 
						|
						vtype = HAWK_VAL_MAP;
 | 
						|
						goto val_map;
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						v = assign_newarrval_in_arr(rtx, arr, idx);
 | 
						|
						if (HAWK_UNLIKELY(!v)) { ADJERR_LOC(rtx, &var->loc); goto oops; }
 | 
						|
						vtype = HAWK_VAL_ARR;
 | 
						|
						goto val_arr;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				hawk_rtx_seterrnum(rtx, &var->loc, HAWK_ENOTIDXACC);
 | 
						|
				goto oops;
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	if (vtype == HAWK_VAL_MAP)
 | 
						|
	{
 | 
						|
		hawk_map_pair_t* pair;
 | 
						|
		pair = hawk_map_search(map, str, len);
 | 
						|
		if (!pair)
 | 
						|
		{
 | 
						|
			/* if the value doesn't exist for the given key, insert a nil for it to create a placeholder for the reference */
 | 
						|
			pair = hawk_map_upsert(map, str, len, hawk_val_nil, 0);
 | 
						|
			if (HAWK_UNLIKELY(!pair)) { ADJERR_LOC(rtx, &var->loc); goto oops; }
 | 
						|
			HAWK_ASSERT(HAWK_MAP_VPTR(pair) == hawk_val_nil);
 | 
						|
			/* no reference count increment as hawk_val_nil is upserted
 | 
						|
			hawk_rtx_refupval(rtx, HAWK_MAP_VPTR(pair)); */
 | 
						|
		}
 | 
						|
 | 
						|
		if (str && str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
		return (hawk_val_t**)&HAWK_MAP_VPTR(pair);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (str && str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
		if (idx >= HAWK_ARR_SIZE(arr) || !HAWK_ARR_SLOT(arr, idx))
 | 
						|
		{
 | 
						|
			/* if the value doesn't exist for the given index, insert a nil at that position to create a placeholder for the reference */
 | 
						|
			if (HAWK_UNLIKELY(hawk_arr_upsert (arr, idx, hawk_val_nil, 0) == HAWK_ARR_NIL)) { ADJERR_LOC(rtx, &var->loc);  goto oops; }
 | 
						|
		}
 | 
						|
		return (hawk_val_t**)&HAWK_ARR_DPTR(arr, idx);
 | 
						|
	}
 | 
						|
 | 
						|
oops:
 | 
						|
	if (str && str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
	return HAWK_NULL;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_char (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* val;
 | 
						|
	val = hawk_rtx_makecharval(rtx, ((hawk_nde_char_t*)nde)->val);
 | 
						|
	if (HAWK_UNLIKELY(!val)) ADJERR_LOC(rtx, &nde->loc);
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_bchr (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* val;
 | 
						|
	val = hawk_rtx_makebchrval(rtx, ((hawk_nde_bchr_t*)nde)->val);
 | 
						|
	if (HAWK_UNLIKELY(!val)) ADJERR_LOC(rtx, &nde->loc);
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_int (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* val;
 | 
						|
	val = hawk_rtx_makeintval(rtx, ((hawk_nde_int_t*)nde)->val);
 | 
						|
	if (HAWK_UNLIKELY(!val)) ADJERR_LOC(rtx, &nde->loc);
 | 
						|
	else if (HAWK_VTR_IS_POINTER(val)) ((hawk_val_int_t*)val)->nde = nde;
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_flt (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* val;
 | 
						|
	val = hawk_rtx_makefltval(rtx, ((hawk_nde_flt_t*)nde)->val);
 | 
						|
	if (HAWK_UNLIKELY(!val)) ADJERR_LOC(rtx, &nde->loc);
 | 
						|
	else ((hawk_val_flt_t*)val)->nde = nde;
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_str (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* val;
 | 
						|
	val = hawk_rtx_makestrvalwithoochars(rtx, ((hawk_nde_str_t*)nde)->ptr, ((hawk_nde_str_t*)nde)->len);
 | 
						|
	if (HAWK_UNLIKELY(!val)) ADJERR_LOC(rtx, &nde->loc);
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_mbs (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* val;
 | 
						|
	val = hawk_rtx_makembsvalwithbchars(rtx, ((hawk_nde_mbs_t*)nde)->ptr, ((hawk_nde_mbs_t*)nde)->len);
 | 
						|
	if (HAWK_UNLIKELY(!val)) ADJERR_LOC(rtx, &nde->loc);
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_rex (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* val;
 | 
						|
	val = hawk_rtx_makerexval(rtx, &((hawk_nde_rex_t*)nde)->str, ((hawk_nde_rex_t*)nde)->code);
 | 
						|
	if (HAWK_UNLIKELY(!val)) ADJERR_LOC(rtx, &nde->loc);
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_xnil (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	return hawk_rtx_makenilval(rtx); /* this never fails */
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_xargc (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_int_t nargs = (hawk_int_t)hawk_rtx_getnargs(rtx);
 | 
						|
	return hawk_rtx_makeintval(rtx, nargs);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_xargv (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	/* this create a new array. referencing @argv without a subscript
 | 
						|
	 * slows hawk. TODO: fix this issue */
 | 
						|
	hawk_oow_t nargs, i;
 | 
						|
	hawk_val_t* v;
 | 
						|
 | 
						|
	nargs = hawk_rtx_getnargs(rtx);
 | 
						|
	v = hawk_rtx_makearrval(rtx, nargs);
 | 
						|
	if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx,v);
 | 
						|
	for (i = 0; i < nargs; i++)
 | 
						|
	{
 | 
						|
		if (HAWK_UNLIKELY(!hawk_rtx_setarrvalfld(rtx, v, i, hawk_rtx_getarg(rtx, i))))
 | 
						|
		{
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	hawk_rtx_refdownval_nofree(rtx,v);
 | 
						|
	return v;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_xargvidx (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_nde_xargvidx_t* xarg;
 | 
						|
	hawk_val_t* v;
 | 
						|
	hawk_int_t pos;
 | 
						|
	int n;
 | 
						|
 | 
						|
	xarg = (hawk_nde_xargvidx_t*)nde;
 | 
						|
 | 
						|
	v = eval_expression(rtx, xarg->pos);
 | 
						|
	if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, v);
 | 
						|
	n = hawk_rtx_valtoint(rtx, v, &pos);
 | 
						|
	hawk_rtx_refdownval(rtx, v);
 | 
						|
	if (n <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &xarg->pos->loc, HAWK_EPOSIDX);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return (pos < 0 || pos >= hawk_rtx_getnargs(rtx))? hawk_rtx_makenilval(rtx): hawk_rtx_getarg(rtx, pos);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_fun (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_val_t* val;
 | 
						|
	hawk_fun_t* fun;
 | 
						|
 | 
						|
	fun = ((hawk_nde_fun_t*)nde)->funptr;
 | 
						|
	if (!fun)
 | 
						|
	{
 | 
						|
		hawk_htb_pair_t* pair;
 | 
						|
		/* for a program like this,
 | 
						|
			BEGIN { @local x; abc(); x = abc; x(); } function abc() { print "abc"; }
 | 
						|
		 * abc is defined after BEGIN but is know to be a function inside BEGIN.
 | 
						|
		 * the funptr field in the node can be HAWK_NULL */
 | 
						|
 | 
						|
		/* TODO: support builtin functions?, support module functions? */
 | 
						|
		pair = hawk_htb_search(rtx->hawk->tree.funs, ((hawk_nde_fun_t*)nde)->name.ptr, ((hawk_nde_fun_t*)nde)->name.len);
 | 
						|
		if (!pair)
 | 
						|
		{
 | 
						|
			/* it's unlikely to be not found in the function table for the parser structure. but keep this code in case */
 | 
						|
			hawk_rtx_seterrfmt(rtx, &nde->loc, HAWK_EFUNNF, HAWK_T("function '%.*js' not found"), ((hawk_nde_fun_t*)nde)->name.len, ((hawk_nde_fun_t*)nde)->name.ptr);
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
 | 
						|
		fun = (hawk_fun_t*)HAWK_HTB_VPTR(pair);
 | 
						|
		HAWK_ASSERT(fun != HAWK_NULL);
 | 
						|
	}
 | 
						|
 | 
						|
	val = hawk_rtx_makefunval(rtx, fun);
 | 
						|
	if (HAWK_UNLIKELY(!val)) ADJERR_LOC(rtx, &nde->loc);
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_named (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_htb_pair_t* pair;
 | 
						|
	pair = hawk_htb_search(rtx->named, ((hawk_nde_var_t*)nde)->id.name.ptr, ((hawk_nde_var_t*)nde)->id.name.len);
 | 
						|
	return (pair == HAWK_NULL)? hawk_val_nil: HAWK_HTB_VPTR(pair);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_gbl (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	return HAWK_RTX_STACK_GBL(rtx, ((hawk_nde_var_t*)nde)->id.idxa);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_lcl (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	return HAWK_RTX_STACK_LCL(rtx, ((hawk_nde_var_t*)nde)->id.idxa);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_arg (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	return HAWK_RTX_STACK_ARG(rtx, ((hawk_nde_var_t*)nde)->id.idxa);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var)
 | 
						|
{
 | 
						|
	hawk_map_t* map; /* containing map */
 | 
						|
	hawk_ooch_t* str = HAWK_NULL;
 | 
						|
	hawk_oow_t len;
 | 
						|
	hawk_ooch_t idxbuf[HAWK_IDX_BUF_SIZE];
 | 
						|
 | 
						|
	hawk_arr_t* arr; /* containing array */
 | 
						|
	hawk_ooi_t idx;
 | 
						|
 | 
						|
	hawk_nde_t* remidx;
 | 
						|
 | 
						|
	hawk_val_t* v;
 | 
						|
	hawk_val_type_t vtype;
 | 
						|
 | 
						|
	v = fetch_topval_from_var(rtx, var);
 | 
						|
	vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | 
						|
 | 
						|
	HAWK_ASSERT(var->idx != HAWK_NULL);
 | 
						|
 | 
						|
	switch (vtype)
 | 
						|
	{
 | 
						|
		case HAWK_VAL_NIL:
 | 
						|
			v = assign_newmapval_to_var(rtx, var);
 | 
						|
			if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
			vtype = HAWK_VAL_MAP;
 | 
						|
			goto init_val_map;
 | 
						|
 | 
						|
		case HAWK_VAL_MAP:
 | 
						|
		init_val_map:
 | 
						|
			len = HAWK_COUNTOF(idxbuf);
 | 
						|
			str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx, HAWK_NULL);
 | 
						|
			if (HAWK_UNLIKELY(!str)) goto oops;
 | 
						|
			map = ((hawk_val_map_t*)v)->map;
 | 
						|
			break;
 | 
						|
 | 
						|
		case HAWK_VAL_ARR:
 | 
						|
			idx = idxnde_to_int(rtx, var->idx, &remidx);
 | 
						|
			if (idx <= -1) goto oops;
 | 
						|
			arr = ((hawk_val_arr_t*)v)->arr;
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			hawk_rtx_seterrnum(rtx, &var->loc, HAWK_ENOTIDXACC);
 | 
						|
			return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
#if defined(HAWK_ENABLE_GC)
 | 
						|
	while (remidx)
 | 
						|
	{
 | 
						|
		hawk_val_type_t container_vtype;
 | 
						|
 | 
						|
		if (vtype == HAWK_VAL_MAP)
 | 
						|
		{
 | 
						|
			hawk_map_pair_t* pair;
 | 
						|
			pair = hawk_map_search(map, str, len);
 | 
						|
			v = pair? (hawk_val_t*)HAWK_MAP_VPTR(pair): hawk_val_nil;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			v = (idx < HAWK_ARR_SIZE(arr) && HAWK_ARR_SLOT(arr, idx))? ((hawk_val_t*)HAWK_ARR_DPTR(arr, idx)): hawk_val_nil;
 | 
						|
		}
 | 
						|
		container_vtype = vtype;
 | 
						|
		vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | 
						|
 | 
						|
		switch (vtype)
 | 
						|
		{
 | 
						|
			case HAWK_VAL_MAP:
 | 
						|
			val_map:
 | 
						|
				if (str && str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
				len = HAWK_COUNTOF(idxbuf);
 | 
						|
				str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx, HAWK_NULL);
 | 
						|
				if (HAWK_UNLIKELY(!str)) goto oops;
 | 
						|
				map = ((hawk_val_map_t*)v)->map;
 | 
						|
				break;
 | 
						|
 | 
						|
			case HAWK_VAL_ARR:
 | 
						|
			val_arr:
 | 
						|
				idx = idxnde_to_int(rtx, remidx, &remidx);
 | 
						|
				if (HAWK_UNLIKELY(idx <= -1)) goto oops;
 | 
						|
				arr = ((hawk_val_arr_t*)v)->arr;
 | 
						|
				break;
 | 
						|
 | 
						|
			default:
 | 
						|
				if (vtype == HAWK_VAL_NIL /* || (rtx->hawk->opt.trait & HAWK_FLEXMAP) no flexmap because this is in a 'get' context */)
 | 
						|
				{
 | 
						|
					if (container_vtype == HAWK_VAL_MAP)
 | 
						|
					{
 | 
						|
						v = assign_newmapval_in_map(rtx, map, str, len);
 | 
						|
						if (HAWK_UNLIKELY(!v)) { ADJERR_LOC(rtx, &var->loc); goto oops; }
 | 
						|
						vtype = HAWK_VAL_MAP;
 | 
						|
						goto val_map;
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						v = assign_newarrval_in_arr(rtx, arr, idx);
 | 
						|
						if (HAWK_UNLIKELY(!v)) { ADJERR_LOC(rtx, &var->loc); goto oops; }
 | 
						|
						vtype = HAWK_VAL_ARR;
 | 
						|
						goto val_arr;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				hawk_rtx_seterrnum(rtx, &var->loc, HAWK_ENOTIDXACC);
 | 
						|
				goto oops;
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	if (vtype == HAWK_VAL_MAP)
 | 
						|
	{
 | 
						|
		hawk_map_pair_t* pair;
 | 
						|
		pair = hawk_map_search(map, str, len);
 | 
						|
		if (str && str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
		return pair? (hawk_val_t*)HAWK_MAP_VPTR(pair): hawk_val_nil;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		/* return nil if the index is out of range or the element at the index is not set.
 | 
						|
		 * no check for a negative index as it's guaranteed to be positive by idxnde_to_int() */
 | 
						|
		if (str && str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
		return (idx < HAWK_ARR_SIZE(arr) && HAWK_ARR_SLOT(arr, idx))? ((hawk_val_t*)HAWK_ARR_DPTR(arr, idx)): hawk_val_nil;
 | 
						|
	}
 | 
						|
 | 
						|
oops:
 | 
						|
	if (str && str != idxbuf) hawk_rtx_freemem(rtx, str);
 | 
						|
	return HAWK_NULL;
 | 
						|
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_namedidx (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	return eval_indexed(rtx, (hawk_nde_var_t*)nde);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_gblidx (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	return eval_indexed(rtx, (hawk_nde_var_t*)nde);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_lclidx (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	return eval_indexed(rtx, (hawk_nde_var_t*)nde);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_argidx (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	return eval_indexed(rtx, (hawk_nde_var_t*)nde);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_pos (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_nde_pos_t* pos = (hawk_nde_pos_t*)nde;
 | 
						|
	hawk_val_t* v;
 | 
						|
	hawk_int_t lv;
 | 
						|
	int n;
 | 
						|
 | 
						|
	v = eval_expression(rtx, pos->val);
 | 
						|
	if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, v);
 | 
						|
	n = hawk_rtx_valtoint(rtx, v, &lv);
 | 
						|
	hawk_rtx_refdownval(rtx, v);
 | 
						|
	if (n <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EPOSIDX);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (lv < 0)
 | 
						|
	{
 | 
						|
		hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EPOSIDX);
 | 
						|
		return HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	v = POS_VAL(rtx, lv);
 | 
						|
#if 0
 | 
						|
	if (lv == 0) v = rtx->inrec.d0;
 | 
						|
	else if (lv > 0 && lv <= (hawk_int_t)rtx->inrec.nflds)
 | 
						|
		v = rtx->inrec.flds[lv-1].val;
 | 
						|
	else v = hawk_val_zls; /*hawk_val_nil;*/
 | 
						|
#endif
 | 
						|
 | 
						|
	return v;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* __eval_getline (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_nde_getline_t* p;
 | 
						|
	hawk_val_t* v = HAWK_NULL, * tmp;
 | 
						|
	hawk_oocs_t dst;
 | 
						|
	hawk_ooecs_t* buf;
 | 
						|
	int n, x;
 | 
						|
 | 
						|
	p = (hawk_nde_getline_t*)nde;
 | 
						|
 | 
						|
	HAWK_ASSERT(
 | 
						|
		(p->in_type == HAWK_IN_PIPE && p->in != HAWK_NULL) ||
 | 
						|
		(p->in_type == HAWK_IN_RWPIPE && p->in != HAWK_NULL) ||
 | 
						|
		(p->in_type == HAWK_IN_FILE && p->in != HAWK_NULL) ||
 | 
						|
		(p->in_type == HAWK_IN_CONSOLE && p->in == HAWK_NULL));
 | 
						|
 | 
						|
	if (p->in)
 | 
						|
	{
 | 
						|
		v = io_nde_to_str(rtx, p->in, &dst, 0);
 | 
						|
		if (!v || dst.len <= 0)
 | 
						|
		{
 | 
						|
			hawk_rtx_freevaloocstr(rtx, v, dst.ptr);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			n = -1;
 | 
						|
			goto skip_read;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		dst.ptr = (hawk_ooch_t*)HAWK_T("");
 | 
						|
		dst.len = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	buf = &rtx->inrec.lineg;
 | 
						|
read_console_again:
 | 
						|
	hawk_ooecs_clear (&rtx->inrec.lineg);
 | 
						|
 | 
						|
	n = hawk_rtx_readio(rtx, p->in_type, dst.ptr, buf);
 | 
						|
 | 
						|
	if (v)
 | 
						|
	{
 | 
						|
		hawk_rtx_freevaloocstr(rtx, v, dst.ptr);
 | 
						|
		hawk_rtx_refdownval(rtx, v);
 | 
						|
	}
 | 
						|
 | 
						|
	if (n <= 0)
 | 
						|
	{
 | 
						|
		/* make getline return -1 */
 | 
						|
		if (p->var)
 | 
						|
		{
 | 
						|
			/* it's important to call do_assignment(). consider an expression like this:
 | 
						|
			 *   getline x[++j]
 | 
						|
			 * withtout do_assignment(), ++j is skipped when getline returns 0. */
 | 
						|
			tmp = do_assignment(rtx, p->var, hawk_val_zls);
 | 
						|
			if (HAWK_UNLIKELY(!tmp)) return HAWK_NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else /*if (n > 0)*/
 | 
						|
	{
 | 
						|
		if (p->in_type == HAWK_IN_CONSOLE)
 | 
						|
		{
 | 
						|
			HAWK_ASSERT(p->in == HAWK_NULL);
 | 
						|
			if (rtx->nrflt.limit > 0)
 | 
						|
			{
 | 
						|
				/* record filter based on record number(NR) */
 | 
						|
				if (((rtx->gbl.nr / rtx->nrflt.limit) % rtx->nrflt.size) != rtx->nrflt.rank)
 | 
						|
				{
 | 
						|
					if (update_fnr(rtx, rtx->gbl.fnr + 1, rtx->gbl.nr + 1) <= -1) return HAWK_NULL;
 | 
						|
					/* this jump is a bit dirty. the 'if' block below hawk_rtx_readio()
 | 
						|
					 * will never be true. but this makes code confusing */
 | 
						|
					goto read_console_again;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (!p->var)
 | 
						|
		{
 | 
						|
			/* set $0 with the input value */
 | 
						|
			x = hawk_rtx_setrec(rtx, 0, HAWK_OOECS_OOCS(buf), 1);
 | 
						|
			if (x <= -1) return HAWK_NULL;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			hawk_val_t* v;
 | 
						|
 | 
						|
			/* treat external input numerically if it can compose a number. */
 | 
						|
			/*v = hawk_rtx_makestrvalwithoocs(rtx, HAWK_OOECS_OOCS(buf));*/
 | 
						|
			v = hawk_rtx_makenumorstrvalwithoochars(rtx, HAWK_OOECS_PTR(buf), HAWK_OOECS_LEN(buf));
 | 
						|
			if (HAWK_UNLIKELY(!v))
 | 
						|
			{
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
			tmp = do_assignment(rtx, p->var, v);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			if (HAWK_UNLIKELY(!tmp)) return HAWK_NULL;
 | 
						|
		}
 | 
						|
 | 
						|
		/* update FNR & NR if reading from console */
 | 
						|
		if (p->in_type == HAWK_IN_CONSOLE &&
 | 
						|
		    update_fnr(rtx, rtx->gbl.fnr + 1, rtx->gbl.nr + 1) <= -1)
 | 
						|
		{
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
skip_read:
 | 
						|
	tmp = hawk_rtx_makeintval(rtx, n);
 | 
						|
	if (HAWK_UNLIKELY(!tmp)) ADJERR_LOC(rtx, &nde->loc);
 | 
						|
	return tmp;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* __eval_getbline (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	hawk_nde_getline_t* p;
 | 
						|
	hawk_val_t* v = HAWK_NULL, * tmp;
 | 
						|
	hawk_oocs_t dst;
 | 
						|
	hawk_becs_t* buf;
 | 
						|
	int n;
 | 
						|
 | 
						|
	p = (hawk_nde_getline_t*)nde;
 | 
						|
 | 
						|
	HAWK_ASSERT(
 | 
						|
		(p->in_type == HAWK_IN_PIPE && p->in != HAWK_NULL) ||
 | 
						|
		(p->in_type == HAWK_IN_RWPIPE && p->in != HAWK_NULL) ||
 | 
						|
		(p->in_type == HAWK_IN_FILE && p->in != HAWK_NULL) ||
 | 
						|
		(p->in_type == HAWK_IN_CONSOLE && p->in == HAWK_NULL));
 | 
						|
 | 
						|
	if (p->in)
 | 
						|
	{
 | 
						|
		v = io_nde_to_str(rtx, p->in, &dst, 0);
 | 
						|
		if (!v || dst.len <= 0)
 | 
						|
		{
 | 
						|
			hawk_rtx_freevaloocstr(rtx, v, dst.ptr);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			n = -1;
 | 
						|
			goto skip_read;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		dst.ptr = (hawk_ooch_t*)HAWK_T("");
 | 
						|
		dst.len = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	buf = &rtx->inrec.linegb;
 | 
						|
read_console_again:
 | 
						|
	hawk_becs_clear (&rtx->inrec.linegb);
 | 
						|
 | 
						|
	n = hawk_rtx_readiobytes(rtx, p->in_type, dst.ptr, buf);
 | 
						|
 | 
						|
	if (v)
 | 
						|
	{
 | 
						|
		hawk_rtx_freevaloocstr(rtx, v, dst.ptr);
 | 
						|
		hawk_rtx_refdownval(rtx, v);
 | 
						|
	}
 | 
						|
 | 
						|
	if (n <= 0)
 | 
						|
	{
 | 
						|
		/* make getline return -1 or 0*/
 | 
						|
		if (p->var)
 | 
						|
		{
 | 
						|
			tmp = do_assignment(rtx, p->var, v);
 | 
						|
			if (tmp == HAWK_NULL) return HAWK_NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else /*if (n > 0)*/
 | 
						|
	{
 | 
						|
		if (p->in_type == HAWK_IN_CONSOLE)
 | 
						|
		{
 | 
						|
			HAWK_ASSERT(p->in == HAWK_NULL);
 | 
						|
			if (rtx->nrflt.limit > 0)
 | 
						|
			{
 | 
						|
				/* record filter based on record number(NR) */
 | 
						|
				if (((rtx->gbl.nr / rtx->nrflt.limit) % rtx->nrflt.size) != rtx->nrflt.rank)
 | 
						|
				{
 | 
						|
					if (update_fnr(rtx, rtx->gbl.fnr + 1, rtx->gbl.nr + 1) <= -1) return HAWK_NULL;
 | 
						|
					/* this jump is a bit dirty. the 'if' block below hawk_rtx_readio()
 | 
						|
					 * will never be true. but this makes code confusing */
 | 
						|
					goto read_console_again;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (p->var == HAWK_NULL)
 | 
						|
		{
 | 
						|
			/* set $0 with the input value */
 | 
						|
			/*x = hawk_rtx_setbrec(rtx, 0, HAWK_BECS_BCS(buf));
 | 
						|
			if (x <= -1) return HAWK_NULL;*/
 | 
						|
/* TODO: can i support this? */
 | 
						|
			hawk_rtx_seterrfmt(rtx, &nde->loc, HAWK_ENOIMPL, HAWK_T("getbline without a variable not supported"));
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			hawk_val_t* v;
 | 
						|
 | 
						|
			/* treat external input numerically if it can compose a number. */
 | 
						|
			/*v = hawk_rtx_makembsvalwithbcs(rtx, HAWK_BECS_BCS(buf));*/
 | 
						|
			v = hawk_rtx_makenumormbsvalwithbchars(rtx, HAWK_BECS_PTR(buf), HAWK_BECS_LEN(buf));
 | 
						|
			if (v == HAWK_NULL)
 | 
						|
			{
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
			tmp = do_assignment(rtx, p->var, v);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			if (tmp == HAWK_NULL) return HAWK_NULL;
 | 
						|
		}
 | 
						|
 | 
						|
		/* update FNR & NR if reading from console */
 | 
						|
		if (p->in_type == HAWK_IN_CONSOLE &&
 | 
						|
		    update_fnr(rtx, rtx->gbl.fnr + 1, rtx->gbl.nr + 1) <= -1)
 | 
						|
		{
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
skip_read:
 | 
						|
	tmp = hawk_rtx_makeintval(rtx, n);
 | 
						|
	if (!tmp) ADJERR_LOC(rtx, &nde->loc);
 | 
						|
	return tmp;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_getline (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	return ((hawk_nde_getline_t*)nde)->mbs? __eval_getbline(rtx, nde): __eval_getline(rtx, nde);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_print (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	int n = run_print(rtx, (hawk_nde_print_t*)nde);
 | 
						|
	if (n == PRINT_IOERR) n = -1; /* let print return -1 */
 | 
						|
	else if (n <= -1) return HAWK_NULL;
 | 
						|
	return hawk_rtx_makeintval(rtx, n);
 | 
						|
}
 | 
						|
 | 
						|
static hawk_val_t* eval_printf (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | 
						|
{
 | 
						|
	int n = run_printf(rtx, (hawk_nde_print_t*)nde);
 | 
						|
	if (n == PRINT_IOERR) n = -1; /* let print return -1 */
 | 
						|
	else if (n <= -1) return HAWK_NULL;
 | 
						|
	return hawk_rtx_makeintval(rtx, n);
 | 
						|
}
 | 
						|
 | 
						|
static int read_record (hawk_rtx_t* rtx)
 | 
						|
{
 | 
						|
	hawk_ooi_t n;
 | 
						|
	hawk_ooecs_t* buf;
 | 
						|
 | 
						|
read_again:
 | 
						|
	if (hawk_rtx_clrrec(rtx, 0) <= -1) return -1;
 | 
						|
 | 
						|
	buf = &rtx->inrec.line;
 | 
						|
	n = hawk_rtx_readio(rtx, HAWK_IN_CONSOLE, HAWK_T(""), buf);
 | 
						|
	if (n <= -1)
 | 
						|
	{
 | 
						|
		hawk_rtx_clrrec(rtx, 0);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
#if defined(DEBUG_RUN)
 | 
						|
	hawk_logbfmt (hawk_rtx_gethawk(rtx), "record len = %d str=[%.*js]\n", (int)HAWK_OOECS_LEN(buf), HAWK_OOECS_LEN(buf), HAWK_OOECS_PTR(buf));
 | 
						|
#endif
 | 
						|
	if (n == 0)
 | 
						|
	{
 | 
						|
		HAWK_ASSERT(HAWK_OOECS_LEN(buf) == 0);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if (rtx->nrflt.limit > 0)
 | 
						|
	{
 | 
						|
		if (((rtx->gbl.nr / rtx->nrflt.limit) % rtx->nrflt.size) != rtx->nrflt.rank)
 | 
						|
		{
 | 
						|
			if (update_fnr(rtx, rtx->gbl.fnr + 1, rtx->gbl.nr + 1) <= -1) return -1;
 | 
						|
			goto read_again;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (hawk_rtx_setrec(rtx, 0, HAWK_OOECS_OOCS(buf), 1) <= -1 ||
 | 
						|
	    update_fnr(rtx, rtx->gbl.fnr + 1, rtx->gbl.nr + 1) <= -1) return -1;
 | 
						|
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_ooch_t* idxnde_to_str (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_ooch_t* buf, hawk_oow_t* len, hawk_nde_t** remidx, hawk_int_t* firstidxint)
 | 
						|
{
 | 
						|
	hawk_ooch_t* str;
 | 
						|
	hawk_val_t* idx;
 | 
						|
	hawk_int_t idxint;
 | 
						|
 | 
						|
	HAWK_ASSERT(nde != HAWK_NULL);
 | 
						|
 | 
						|
	if (!nde->next)
 | 
						|
	{
 | 
						|
		hawk_rtx_valtostr_out_t out;
 | 
						|
 | 
						|
		/* single node index */
 | 
						|
		idx = eval_expression(rtx, nde);
 | 
						|
		if (HAWK_UNLIKELY(!idx)) return HAWK_NULL;
 | 
						|
 | 
						|
		hawk_rtx_refupval(rtx, idx);
 | 
						|
 | 
						|
		if (firstidxint)
 | 
						|
		{
 | 
						|
			if (hawk_rtx_valtoint(rtx, idx, &idxint) <= -1)
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, idx);
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		str = HAWK_NULL;
 | 
						|
 | 
						|
		if (buf)
 | 
						|
		{
 | 
						|
			/* try with a fixed-size buffer if given */
 | 
						|
			out.type = HAWK_RTX_VALTOSTR_CPLCPY;
 | 
						|
			out.u.cplcpy.ptr = buf;
 | 
						|
			out.u.cplcpy.len = *len;
 | 
						|
 | 
						|
			if (hawk_rtx_valtostr(rtx, idx, &out) >= 0)
 | 
						|
			{
 | 
						|
				str = out.u.cplcpy.ptr;
 | 
						|
				*len = out.u.cplcpy.len;
 | 
						|
				HAWK_ASSERT(str == buf);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (!str)
 | 
						|
		{
 | 
						|
			/* if no fixed-size buffer was given or the fixed-size
 | 
						|
			 * conversion failed, switch to the dynamic mode */
 | 
						|
			out.type = HAWK_RTX_VALTOSTR_CPLDUP;
 | 
						|
			if (hawk_rtx_valtostr(rtx, idx, &out) <= -1)
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, idx);
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			str = out.u.cpldup.ptr;
 | 
						|
			*len = out.u.cpldup.len;
 | 
						|
		}
 | 
						|
 | 
						|
		hawk_rtx_refdownval(rtx, idx);
 | 
						|
		*remidx = HAWK_NULL;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		/* multidimensional index - e.g. [1,2,3] */
 | 
						|
		hawk_ooecs_t idxstr;
 | 
						|
		hawk_oocs_t tmp;
 | 
						|
		hawk_rtx_valtostr_out_t out;
 | 
						|
		hawk_nde_t* xnde;
 | 
						|
		int first = 1;
 | 
						|
 | 
						|
		out.type = HAWK_RTX_VALTOSTR_STRPCAT;
 | 
						|
		out.u.strpcat = &idxstr;
 | 
						|
 | 
						|
		if (hawk_ooecs_init(&idxstr, hawk_rtx_getgem(rtx), DEF_BUF_CAPA) <= -1)
 | 
						|
		{
 | 
						|
			ADJERR_LOC(rtx, &nde->loc);
 | 
						|
			return HAWK_NULL;
 | 
						|
		}
 | 
						|
 | 
						|
		xnde = nde;
 | 
						|
#if defined(HAWK_ENABLE_GC)
 | 
						|
		while (nde && nde->type != HAWK_NDE_NULL)
 | 
						|
#else
 | 
						|
		while (nde)
 | 
						|
#endif
 | 
						|
		{
 | 
						|
			idx = eval_expression(rtx, nde);
 | 
						|
			if (HAWK_UNLIKELY(!idx))
 | 
						|
			{
 | 
						|
				hawk_ooecs_fini(&idxstr);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, idx);
 | 
						|
 | 
						|
			if (firstidxint && first)
 | 
						|
			{
 | 
						|
				if (hawk_rtx_valtoint(rtx, idx, &idxint) <= -1)
 | 
						|
				{
 | 
						|
					hawk_rtx_refdownval(rtx, idx);
 | 
						|
					hawk_ooecs_fini(&idxstr);
 | 
						|
					ADJERR_LOC(rtx, &nde->loc);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
 | 
						|
				first = 0;
 | 
						|
			}
 | 
						|
 | 
						|
			if (xnde != nde && hawk_ooecs_ncat(&idxstr, rtx->gbl.subsep.ptr, rtx->gbl.subsep.len) == (hawk_oow_t)-1)
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, idx);
 | 
						|
				hawk_ooecs_fini(&idxstr);
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			if (hawk_rtx_valtostr(rtx, idx, &out) <= -1)
 | 
						|
			{
 | 
						|
				hawk_rtx_refdownval(rtx, idx);
 | 
						|
				hawk_ooecs_fini(&idxstr);
 | 
						|
				ADJERR_LOC(rtx, &nde->loc);
 | 
						|
				return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refdownval(rtx, idx);
 | 
						|
			nde = nde->next;
 | 
						|
		}
 | 
						|
 | 
						|
		hawk_ooecs_yield(&idxstr, &tmp, 0);
 | 
						|
		str = tmp.ptr;
 | 
						|
		*len = tmp.len;
 | 
						|
 | 
						|
		hawk_ooecs_fini(&idxstr);
 | 
						|
 | 
						|
		/* if nde is not HAWK_NULL, it should be of the HAWK_NDE_NULL type */
 | 
						|
		*remidx = nde? nde->next: nde;
 | 
						|
	}
 | 
						|
 | 
						|
	if (firstidxint) *firstidxint = idxint;
 | 
						|
	return str;
 | 
						|
}
 | 
						|
 | 
						|
static hawk_ooi_t idxnde_to_int (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_nde_t** remidx)
 | 
						|
{
 | 
						|
	hawk_int_t v;
 | 
						|
	hawk_val_t* tmp;
 | 
						|
	int n;
 | 
						|
 | 
						|
	if (nde->next && nde->next->type != HAWK_NDE_NULL)
 | 
						|
	{
 | 
						|
		/* multidimensional indices inside a single brakcet is not allowed for an array */
 | 
						|
		hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EARRIDXMULTI);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	tmp = eval_expression(rtx, nde);
 | 
						|
	if (HAWK_UNLIKELY(!tmp)) return -1;
 | 
						|
 | 
						|
	hawk_rtx_refupval(rtx, tmp);
 | 
						|
	n = hawk_rtx_valtoint(rtx, tmp, &v);
 | 
						|
	hawk_rtx_refdownval(rtx, tmp);
 | 
						|
	if (HAWK_UNLIKELY(n <= -1))
 | 
						|
	{
 | 
						|
		ADJERR_LOC(rtx, &nde->loc);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (v < 0 || v > HAWK_INT_MAX)
 | 
						|
	{
 | 
						|
		/* array index out of permitted range  */
 | 
						|
		hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EARRIDXRANGE);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	*remidx = nde->next? nde->next->next: HAWK_NULL;
 | 
						|
	return (hawk_ooi_t)v;
 | 
						|
}
 | 
						|
 | 
						|
/* ========================================================================= */
 | 
						|
 | 
						|
hawk_ooch_t* hawk_rtx_format (
 | 
						|
	hawk_rtx_t* rtx, hawk_ooecs_t* out, hawk_ooecs_t* fbu,
 | 
						|
	const hawk_ooch_t* fmt, hawk_oow_t fmt_len,
 | 
						|
	hawk_oow_t nargs_on_stack, hawk_nde_t* args, hawk_oow_t* len)
 | 
						|
{
 | 
						|
	hawk_oow_t i;
 | 
						|
	hawk_oow_t stack_arg_idx = 1;
 | 
						|
	hawk_val_t* val;
 | 
						|
 | 
						|
#define OUT_CHAR(c) do { if (hawk_ooecs_ccat(out, (c)) == (hawk_oow_t)-1) return HAWK_NULL; } while(0)
 | 
						|
 | 
						|
#define OUT_STR(ptr,len) do { if (hawk_ooecs_ncat(out, (ptr), (len)) == (hawk_oow_t)-1) return HAWK_NULL; } while(0)
 | 
						|
 | 
						|
#define FMT_CHAR(c) do { if (hawk_ooecs_ccat(fbu, (c)) == (hawk_oow_t)-1) return HAWK_NULL; } while(0)
 | 
						|
 | 
						|
#define FMT_STR(ptr,len) do { if (hawk_ooecs_ncat(fbu, (ptr), (len)) == (hawk_oow_t)-1) return HAWK_NULL; } while(0)
 | 
						|
 | 
						|
#define GROW(buf) do { \
 | 
						|
	if ((buf)->ptr) \
 | 
						|
	{ \
 | 
						|
		hawk_rtx_freemem(rtx, (buf)->ptr); \
 | 
						|
		(buf)->ptr = HAWK_NULL; \
 | 
						|
	} \
 | 
						|
	(buf)->len += (buf)->inc; \
 | 
						|
	(buf)->ptr = (hawk_ooch_t*)hawk_rtx_allocmem(rtx, (buf)->len * HAWK_SIZEOF(hawk_ooch_t)); \
 | 
						|
	if ((buf)->ptr == HAWK_NULL) \
 | 
						|
	{ \
 | 
						|
		(buf)->len = 0; \
 | 
						|
		return HAWK_NULL; \
 | 
						|
	} \
 | 
						|
}  while(0)
 | 
						|
 | 
						|
#define GROW_WITH_INC(buf,incv) do { \
 | 
						|
	if ((buf)->ptr) \
 | 
						|
	{ \
 | 
						|
		hawk_rtx_freemem(rtx, (buf)->ptr); \
 | 
						|
		(buf)->ptr = HAWK_NULL; \
 | 
						|
	} \
 | 
						|
	(buf)->len += ((incv) > (buf)->inc)? (incv): (buf)->inc; \
 | 
						|
	(buf)->ptr = (hawk_ooch_t*)hawk_rtx_allocmem(rtx, (buf)->len * HAWK_SIZEOF(hawk_ooch_t)); \
 | 
						|
	if ((buf)->ptr == HAWK_NULL) \
 | 
						|
	{ \
 | 
						|
		(buf)->len = 0; \
 | 
						|
		return HAWK_NULL; \
 | 
						|
	} \
 | 
						|
} while(0)
 | 
						|
 | 
						|
	/* run->format.tmp.ptr should have been assigned a pointer to a block of memory before this function has been called */
 | 
						|
	HAWK_ASSERT(rtx->format.tmp.ptr != HAWK_NULL);
 | 
						|
 | 
						|
	if (nargs_on_stack == (hawk_oow_t)-1)
 | 
						|
	{
 | 
						|
		/* dirty hack to support a single value argument instead of a tree node */
 | 
						|
		val = (hawk_val_t*)args;
 | 
						|
		nargs_on_stack = 2; /* indicate 2 arguments of a formatting specifier and the given value */
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		val = HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (out == HAWK_NULL) out = &rtx->format.out;
 | 
						|
	if (fbu == HAWK_NULL) fbu = &rtx->format.fmt;
 | 
						|
 | 
						|
	hawk_ooecs_clear (out);
 | 
						|
	hawk_ooecs_clear (fbu);
 | 
						|
 | 
						|
	for (i = 0; i < fmt_len; i++)
 | 
						|
	{
 | 
						|
		hawk_int_t wp[2];
 | 
						|
		int wp_idx;
 | 
						|
#define WP_WIDTH     0
 | 
						|
#define WP_PRECISION 1
 | 
						|
 | 
						|
		int flags;
 | 
						|
#define FLAG_SPACE (1 << 0)
 | 
						|
#define FLAG_HASH  (1 << 1)
 | 
						|
#define FLAG_ZERO  (1 << 2)
 | 
						|
#define FLAG_PLUS  (1 << 3)
 | 
						|
#define FLAG_MINUS (1 << 4)
 | 
						|
 | 
						|
		if (HAWK_OOECS_LEN(fbu) == 0)
 | 
						|
		{
 | 
						|
			/* format specifier is empty */
 | 
						|
			if (fmt[i] == HAWK_T('%'))
 | 
						|
			{
 | 
						|
				/* add % to format specifier (fbu) */
 | 
						|
				FMT_CHAR(fmt[i]);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				/* normal output */
 | 
						|
				OUT_CHAR(fmt[i]);
 | 
						|
			}
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		/* handle flags */
 | 
						|
		flags = 0;
 | 
						|
		while (i < fmt_len)
 | 
						|
		{
 | 
						|
			switch (fmt[i])
 | 
						|
			{
 | 
						|
				case HAWK_T(' '):
 | 
						|
					flags |= FLAG_SPACE;
 | 
						|
					break;
 | 
						|
				case HAWK_T('#'):
 | 
						|
					flags |= FLAG_HASH;
 | 
						|
					break;
 | 
						|
				case HAWK_T('0'):
 | 
						|
					flags |= FLAG_ZERO;
 | 
						|
					break;
 | 
						|
				case HAWK_T('+'):
 | 
						|
					flags |= FLAG_PLUS;
 | 
						|
					break;
 | 
						|
				case HAWK_T('-'):
 | 
						|
					flags |= FLAG_MINUS;
 | 
						|
					break;
 | 
						|
				default:
 | 
						|
					goto wp_mod_init;
 | 
						|
			}
 | 
						|
 | 
						|
			FMT_CHAR(fmt[i]); i++;
 | 
						|
		}
 | 
						|
 | 
						|
wp_mod_init:
 | 
						|
		wp[WP_WIDTH] = 0; /* width */
 | 
						|
		wp[WP_PRECISION] = -1; /* precision */
 | 
						|
		wp_idx = WP_WIDTH; /* width first */
 | 
						|
 | 
						|
wp_mod_main:
 | 
						|
		if (i < fmt_len && fmt[i] == HAWK_T('*'))
 | 
						|
		{
 | 
						|
			/* variable width/precision modifier.
 | 
						|
			 * take the width/precision from a parameter and
 | 
						|
			 * transform it to a fixed length format */
 | 
						|
			hawk_val_t* v;
 | 
						|
			int n;
 | 
						|
 | 
						|
			if (!args)
 | 
						|
			{
 | 
						|
				if (stack_arg_idx >= nargs_on_stack)
 | 
						|
				{
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
				v = hawk_rtx_getarg(rtx, stack_arg_idx);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (val)
 | 
						|
				{
 | 
						|
					if (stack_arg_idx >= nargs_on_stack)
 | 
						|
					{
 | 
						|
						hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					v = val;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					v = eval_expression(rtx, args);
 | 
						|
					if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
			n = hawk_rtx_valtoint(rtx, v, &wp[wp_idx]);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			if (HAWK_UNLIKELY(n <= -1)) return HAWK_NULL;
 | 
						|
 | 
						|
			do
 | 
						|
			{
 | 
						|
				n = hawk_fmt_intmax_to_oocstr(
 | 
						|
					rtx->format.tmp.ptr,
 | 
						|
					rtx->format.tmp.len,
 | 
						|
					wp[wp_idx],
 | 
						|
					10 | HAWK_FMT_INTMAX_NOTRUNC | HAWK_FMT_INTMAX_NONULL,
 | 
						|
					-1,
 | 
						|
					HAWK_T('\0'),
 | 
						|
					HAWK_NULL
 | 
						|
				);
 | 
						|
				if (n <= -1)
 | 
						|
				{
 | 
						|
					/* -n is the number of characters required
 | 
						|
					 * including terminating null  */
 | 
						|
					GROW_WITH_INC (&rtx->format.tmp, -n);
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			while (1);
 | 
						|
 | 
						|
			FMT_STR(rtx->format.tmp.ptr, n);
 | 
						|
 | 
						|
			if (!args || val) stack_arg_idx++;
 | 
						|
			else args = args->next;
 | 
						|
			i++;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			/* fixed width/precision modifier */
 | 
						|
			if (i < fmt_len && hawk_is_ooch_digit(fmt[i]))
 | 
						|
			{
 | 
						|
				wp[wp_idx] = 0;
 | 
						|
				do
 | 
						|
				{
 | 
						|
					wp[wp_idx] = wp[wp_idx] * 10 + fmt[i] - HAWK_T('0');
 | 
						|
					FMT_CHAR(fmt[i]); i++;
 | 
						|
				}
 | 
						|
				while (i < fmt_len && hawk_is_ooch_digit(fmt[i]));
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (wp_idx == WP_WIDTH && i < fmt_len && fmt[i] == HAWK_T('.'))
 | 
						|
		{
 | 
						|
			FMT_CHAR(fmt[i]); i++;
 | 
						|
			wp[WP_PRECISION] = 0;
 | 
						|
			wp_idx = WP_PRECISION; /* change index to precision */
 | 
						|
			goto wp_mod_main;
 | 
						|
		}
 | 
						|
 | 
						|
		if (i >= fmt_len) break;
 | 
						|
 | 
						|
		if (wp[WP_WIDTH] < 0)
 | 
						|
		{
 | 
						|
			wp[WP_WIDTH] = -wp[WP_WIDTH];
 | 
						|
			flags |= FLAG_MINUS;
 | 
						|
		}
 | 
						|
 | 
						|
		if (fmt[i] == 'd' || fmt[i] == 'i' ||
 | 
						|
		    fmt[i] == 'x' || fmt[i] == 'X' ||
 | 
						|
		    fmt[i] == 'b' || fmt[i] == 'B' ||
 | 
						|
		    fmt[i] == 'o' || fmt[i] == 'u')
 | 
						|
		{
 | 
						|
			hawk_val_t* v;
 | 
						|
			hawk_int_t l;
 | 
						|
			int n;
 | 
						|
 | 
						|
			int fmt_flags;
 | 
						|
			int fmt_uint = 0;
 | 
						|
			int fmt_width;
 | 
						|
			hawk_ooch_t fmt_fill = HAWK_T('\0');
 | 
						|
			const hawk_ooch_t* fmt_prefix = HAWK_NULL;
 | 
						|
 | 
						|
			if (!args)
 | 
						|
			{
 | 
						|
				if (stack_arg_idx >= nargs_on_stack)
 | 
						|
				{
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
				v = hawk_rtx_getarg(rtx, stack_arg_idx);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (val)
 | 
						|
				{
 | 
						|
					if (stack_arg_idx >= nargs_on_stack)
 | 
						|
					{
 | 
						|
						hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					v = val;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					v = eval_expression(rtx, args);
 | 
						|
					if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
			n = hawk_rtx_valtoint(rtx, v, &l);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			if (HAWK_UNLIKELY(n <= -1)) return HAWK_NULL;
 | 
						|
 | 
						|
			fmt_flags = HAWK_FMT_INTMAX_NOTRUNC | HAWK_FMT_INTMAX_NONULL;
 | 
						|
 | 
						|
			if (l == 0 && wp_idx == WP_PRECISION && wp[WP_PRECISION] == 0)
 | 
						|
			{
 | 
						|
				/* printf ("%.d", 0); printf ("%.0d", 0); printf ("%.*d", 0, 0); */
 | 
						|
				/* A zero value with a precision of zero produces no character. */
 | 
						|
				fmt_flags |= HAWK_FMT_INTMAX_NOZERO;
 | 
						|
			}
 | 
						|
 | 
						|
			if (wp[WP_WIDTH] > 0)
 | 
						|
			{
 | 
						|
				/* justification for width greater than 0 */
 | 
						|
				if (flags & FLAG_ZERO)
 | 
						|
				{
 | 
						|
					if (flags & FLAG_MINUS)
 | 
						|
					{
 | 
						|
						 /* FLAG_MINUS wins if both FLAG_ZERO
 | 
						|
						  * and FLAG_MINUS are specified. */
 | 
						|
						fmt_fill = HAWK_T(' ');
 | 
						|
						if (flags & FLAG_MINUS)
 | 
						|
						{
 | 
						|
							/* left justification. need to fill the right side */
 | 
						|
							fmt_flags |= HAWK_FMT_INTMAX_FILLRIGHT;
 | 
						|
						}
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						if (wp_idx != WP_PRECISION) /* if precision is not specified, wp_idx is at WP_WIDTH */
 | 
						|
						{
 | 
						|
							/* precision not specified.
 | 
						|
							 * FLAG_ZERO can take effect */
 | 
						|
							fmt_fill = HAWK_T('0');
 | 
						|
							fmt_flags |= HAWK_FMT_INTMAX_FILLCENTER;
 | 
						|
						}
 | 
						|
						else
 | 
						|
						{
 | 
						|
							fmt_fill = HAWK_T(' ');
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					fmt_fill = HAWK_T(' ');
 | 
						|
					if (flags & FLAG_MINUS)
 | 
						|
					{
 | 
						|
						/* left justification. need to fill the right side */
 | 
						|
						fmt_flags |= HAWK_FMT_INTMAX_FILLRIGHT;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			switch (fmt[i])
 | 
						|
			{
 | 
						|
				case 'B':
 | 
						|
				case 'b':
 | 
						|
					fmt_flags |= 2;
 | 
						|
					fmt_uint = 1;
 | 
						|
					if (l && (flags & FLAG_HASH))
 | 
						|
					{
 | 
						|
						/* A nonzero value is prefixed with 0b */
 | 
						|
						fmt_prefix = HAWK_T("0b");
 | 
						|
					}
 | 
						|
					break;
 | 
						|
 | 
						|
				case 'X':
 | 
						|
					fmt_flags |= HAWK_FMT_INTMAX_UPPERCASE;
 | 
						|
				case 'x':
 | 
						|
					fmt_flags |= 16;
 | 
						|
					fmt_uint = 1;
 | 
						|
					if (l && (flags & FLAG_HASH))
 | 
						|
					{
 | 
						|
						/* A nonzero value is prefixed with 0x */
 | 
						|
						fmt_prefix = HAWK_T("0x");
 | 
						|
					}
 | 
						|
					break;
 | 
						|
 | 
						|
				case 'o':
 | 
						|
					fmt_flags |= 8;
 | 
						|
					fmt_uint = 1;
 | 
						|
					if (flags & FLAG_HASH)
 | 
						|
					{
 | 
						|
						/* Force a leading zero digit including zero.
 | 
						|
						 * 0 with FLAG_HASH and precision 0 still emits '0'.
 | 
						|
						 * On the contrary, 'X' and 'x' emit no digits
 | 
						|
						 * for 0 with FLAG_HASH and precision 0. */
 | 
						|
						fmt_flags |= HAWK_FMT_INTMAX_ZEROLEAD;
 | 
						|
					}
 | 
						|
					break;
 | 
						|
 | 
						|
				case 'u':
 | 
						|
					fmt_uint = 1;
 | 
						|
				default:
 | 
						|
					fmt_flags |= 10;
 | 
						|
					if (flags & FLAG_PLUS)
 | 
						|
						fmt_flags |= HAWK_FMT_INTMAX_PLUSSIGN;
 | 
						|
					if (flags & FLAG_SPACE)
 | 
						|
						fmt_flags |= HAWK_FMT_INTMAX_EMPTYSIGN;
 | 
						|
					break;
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
			if (wp[WP_WIDTH] > 0)
 | 
						|
			{
 | 
						|
				if (wp[WP_WIDTH] > rtx->format.tmp.len)
 | 
						|
					GROW_WITH_INC (&rtx->format.tmp, wp[WP_WIDTH] - rtx->format.tmp.len);
 | 
						|
				fmt_width = wp[WP_WIDTH];
 | 
						|
			}
 | 
						|
			else fmt_width = rtx->format.tmp.len;
 | 
						|
 | 
						|
			do
 | 
						|
			{
 | 
						|
				if (fmt_uint)
 | 
						|
				{
 | 
						|
					/* Explicit type-casting for 'l' from hawk_int_t
 | 
						|
					 * to hawk_uint_t is needed before passing it to
 | 
						|
					 * hawk_fmt_uintmax_to_oocstr().
 | 
						|
 					 *
 | 
						|
					 * Consider a value of -1 for example.
 | 
						|
					 * -1 is a value with all bits set.
 | 
						|
					 * If hawk_int_t is 4 bytes and hawk_uintmax_t
 | 
						|
					 * is 8 bytes, the value is shown below for
 | 
						|
					 * each type respectively .
 | 
						|
					 *     -1 - 0xFFFFFFFF (hawk_int_t)
 | 
						|
					 *     -1 - 0xFFFFFFFFFFFFFFFF (hawk_uintmax_t)
 | 
						|
					 * Implicit typecasting of -1 from hawk_int_t to
 | 
						|
					 * to hawk_uintmax_t results in 0xFFFFFFFFFFFFFFFF,
 | 
						|
					 * though 0xFFFFFFF is expected in hexadecimal.
 | 
						|
					 */
 | 
						|
					n = hawk_fmt_uintmax_to_oocstr (
 | 
						|
						rtx->format.tmp.ptr,
 | 
						|
						fmt_width,
 | 
						|
						(hawk_uint_t)l,
 | 
						|
						fmt_flags,
 | 
						|
						wp[WP_PRECISION],
 | 
						|
						fmt_fill,
 | 
						|
						fmt_prefix
 | 
						|
					);
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					n = hawk_fmt_intmax_to_oocstr (
 | 
						|
						rtx->format.tmp.ptr,
 | 
						|
						fmt_width,
 | 
						|
						l,
 | 
						|
						fmt_flags,
 | 
						|
						wp[WP_PRECISION],
 | 
						|
						fmt_fill,
 | 
						|
						fmt_prefix
 | 
						|
					);
 | 
						|
				}
 | 
						|
				if (n <= -1)
 | 
						|
				{
 | 
						|
					/* -n is the number of characters required */
 | 
						|
					GROW_WITH_INC (&rtx->format.tmp, -n);
 | 
						|
					fmt_width = -n;
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			while (1);
 | 
						|
 | 
						|
			OUT_STR (rtx->format.tmp.ptr, n);
 | 
						|
		}
 | 
						|
		else if (fmt[i] == HAWK_T('e') || fmt[i] == HAWK_T('E') ||
 | 
						|
		         fmt[i] == HAWK_T('g') || fmt[i] == HAWK_T('G') ||
 | 
						|
		         fmt[i] == HAWK_T('f'))
 | 
						|
		{
 | 
						|
 | 
						|
			hawk_val_t* v;
 | 
						|
			hawk_flt_t r;
 | 
						|
			int n;
 | 
						|
 | 
						|
			if (!args)
 | 
						|
			{
 | 
						|
				if (stack_arg_idx >= nargs_on_stack)
 | 
						|
				{
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
				v = hawk_rtx_getarg(rtx, stack_arg_idx);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (val)  /* nargs_on_stack == (hawk_oow_t)-1 */
 | 
						|
				{
 | 
						|
					if (stack_arg_idx >= nargs_on_stack)
 | 
						|
					{
 | 
						|
						hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					v = val;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					v = eval_expression(rtx, args);
 | 
						|
					if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
			n = hawk_rtx_valtoflt(rtx, v, &r);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			if (n <= -1) return HAWK_NULL;
 | 
						|
 | 
						|
		#if defined(HAWK_USE_FLTMAX)
 | 
						|
			/*FMT_CHAR(HAWK_T('j'));*/
 | 
						|
			FMT_STR (HAWK_T("jj"), 2); /* see fmt.c for info on jj */
 | 
						|
			FMT_CHAR(fmt[i]);
 | 
						|
			/*if (hawk_ooecs_fcat(out, HAWK_OOECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL;*/
 | 
						|
			if (hawk_ooecs_fcat(out, HAWK_OOECS_PTR(fbu), &r) == (hawk_oow_t)-1) return HAWK_NULL;
 | 
						|
		#else
 | 
						|
			FMT_CHAR(HAWK_T('z'));
 | 
						|
			FMT_CHAR(fmt[i]);
 | 
						|
			if (hawk_ooecs_fcat(out, HAWK_OOECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL;
 | 
						|
		#endif
 | 
						|
		}
 | 
						|
		else if (fmt[i] == HAWK_T('c'))
 | 
						|
		{
 | 
						|
			hawk_ooch_t ch;
 | 
						|
			hawk_oow_t ch_len;
 | 
						|
			hawk_val_t* v;
 | 
						|
			hawk_val_type_t vtype;
 | 
						|
 | 
						|
			if (!args)
 | 
						|
			{
 | 
						|
				if (stack_arg_idx >= nargs_on_stack)
 | 
						|
				{
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
				v = hawk_rtx_getarg(rtx, stack_arg_idx);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (val)
 | 
						|
				{
 | 
						|
					if (stack_arg_idx >= nargs_on_stack)
 | 
						|
					{
 | 
						|
						hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					v = val;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					v = eval_expression(rtx, args);
 | 
						|
					if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
			vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | 
						|
			switch (vtype)
 | 
						|
			{
 | 
						|
				case HAWK_VAL_NIL:
 | 
						|
					ch = HAWK_T('\0');
 | 
						|
					ch_len = 0;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_CHAR:
 | 
						|
					ch = (hawk_ooch_t)HAWK_RTX_GETCHARFROMVAL(rtx, v);
 | 
						|
					ch_len = 1;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_BCHR:
 | 
						|
					ch = (hawk_ooch_t)HAWK_RTX_GETBCHRFROMVAL(rtx, v);
 | 
						|
					ch_len = 1;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_INT:
 | 
						|
					ch = (hawk_ooch_t)HAWK_RTX_GETINTFROMVAL(rtx, v);
 | 
						|
					ch_len = 1;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_FLT:
 | 
						|
					ch = (hawk_ooch_t)((hawk_val_flt_t*)v)->val;
 | 
						|
					ch_len = 1;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_STR:
 | 
						|
					/* printf("%c", "") => produces '\0' character */
 | 
						|
					ch = (((hawk_val_str_t*)v)->val.len  > 0)? ((hawk_val_str_t*)v)->val.ptr[0]: '\0';
 | 
						|
					ch_len = 1;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_MBS:
 | 
						|
					ch = (((hawk_val_mbs_t*)v)->val.len > 0)? ((hawk_val_mbs_t*)v)->val.ptr[0]: '\0';
 | 
						|
					ch_len = 1;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_BOB:
 | 
						|
					ch = (((hawk_val_bob_t*)v)->val.len > 0)? ((hawk_bch_t*)((hawk_val_bob_t*)v)->val.ptr)[0]: '\0';
 | 
						|
					ch_len = 1;
 | 
						|
					break;
 | 
						|
 | 
						|
				default:
 | 
						|
					hawk_rtx_refdownval(rtx, v);
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EVALTOCHR);
 | 
						|
					return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			if (wp[WP_PRECISION] <= 0 || wp[WP_PRECISION] > (hawk_int_t)ch_len)
 | 
						|
			{
 | 
						|
				wp[WP_PRECISION] = (hawk_int_t)ch_len;
 | 
						|
			}
 | 
						|
 | 
						|
			if (wp[WP_PRECISION] > wp[WP_WIDTH]) wp[WP_WIDTH] = wp[WP_PRECISION];
 | 
						|
 | 
						|
			if (!(flags & FLAG_MINUS))
 | 
						|
			{
 | 
						|
				/* right align */
 | 
						|
				while (wp[WP_WIDTH] > wp[WP_PRECISION])
 | 
						|
				{
 | 
						|
					if (hawk_ooecs_ccat(out, HAWK_T(' ')) == (hawk_oow_t)-1)
 | 
						|
					{
 | 
						|
						hawk_rtx_refdownval(rtx, v);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					wp[WP_WIDTH]--;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (wp[WP_PRECISION] > 0)
 | 
						|
			{
 | 
						|
				if (hawk_ooecs_ccat(out, ch) == (hawk_oow_t)-1)
 | 
						|
				{
 | 
						|
					hawk_rtx_refdownval(rtx, v);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (flags & FLAG_MINUS)
 | 
						|
			{
 | 
						|
				/* left align */
 | 
						|
				while (wp[WP_WIDTH] > wp[WP_PRECISION])
 | 
						|
				{
 | 
						|
					if (hawk_ooecs_ccat (out, HAWK_T(' ')) == (hawk_oow_t)-1)
 | 
						|
					{
 | 
						|
						hawk_rtx_refdownval(rtx, v);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					wp[WP_WIDTH]--;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
		}
 | 
						|
		else if (fmt[i] == 's' || fmt[i] == 'k' || fmt[i] == 'K' || fmt[i] == 'w' || fmt[i] == 'W')
 | 
						|
		{
 | 
						|
			hawk_val_t* v;
 | 
						|
 | 
						|
			if (!args)
 | 
						|
			{
 | 
						|
				if (stack_arg_idx >= nargs_on_stack)
 | 
						|
				{
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
				v = hawk_rtx_getarg(rtx, stack_arg_idx);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (val)
 | 
						|
				{
 | 
						|
					if (stack_arg_idx >= nargs_on_stack)
 | 
						|
					{
 | 
						|
						hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					v = val;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					v = eval_expression(rtx, args);
 | 
						|
					if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (val)
 | 
						|
			{
 | 
						|
				/* val_flt_to_str() in val.c calls hawk_rtx_format() with nargs_on_stack of (hawk_oow_t)-1 and the actual value.
 | 
						|
				 * the actual value is assigned to 'val' at the beginning of this function.
 | 
						|
				 *
 | 
						|
				 * the following code can drive here.
 | 
						|
				 *     BEGIN { CONVFMT="%s"; a=98.76 ""; }
 | 
						|
				 *
 | 
						|
				 * when the first attempt to convert 98.76 to a textual form invokes this function with %s and 98.76.
 | 
						|
				 * it comes to this part because the format specifier is 's'. since the floating-point type is not
 | 
						|
				 * specially handled, hawk_rtx_valtooocstrdup() is called below. it calls val_flt_to_str() again,
 | 
						|
				 * which eventually creates recursion and stack depletion.
 | 
						|
				 *
 | 
						|
				 * assuming only val_flt_to_str() calls it this way, i must convert the floating point number
 | 
						|
				 * to text in a rather crude way without calling hawk_rtx_valtooocstrdup().
 | 
						|
				 */
 | 
						|
				hawk_flt_t r;
 | 
						|
				int n;
 | 
						|
 | 
						|
				HAWK_ASSERT(HAWK_RTX_GETVALTYPE(rtx, val) == HAWK_VAL_FLT);
 | 
						|
 | 
						|
				hawk_rtx_refupval(rtx, v);
 | 
						|
				n = hawk_rtx_valtoflt(rtx, v, &r);
 | 
						|
				hawk_rtx_refdownval(rtx, v);
 | 
						|
				if (n <= -1) return HAWK_NULL;
 | 
						|
 | 
						|
				/* format the value as if '%g' is given */
 | 
						|
			#if defined(HAWK_USE_FLTMAX)
 | 
						|
				FMT_STR (HAWK_T("jjg"), 3); /* see fmt.c for info on jj */
 | 
						|
				if (hawk_ooecs_fcat(out, HAWK_OOECS_PTR(fbu), &r) == (hawk_oow_t)-1) return HAWK_NULL;
 | 
						|
			#else
 | 
						|
				FMT_STR (HAWK_T("zg"), 2);
 | 
						|
				if (hawk_ooecs_fcat(out, HAWK_OOECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL;
 | 
						|
			#endif
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				hawk_ooch_t* str_ptr, * str_free = HAWK_NULL, ooch_tmp;
 | 
						|
				hawk_bch_t bch_tmp;
 | 
						|
				hawk_oow_t str_len;
 | 
						|
				hawk_int_t k;
 | 
						|
				hawk_val_type_t vtype;
 | 
						|
				int bytetostr_flagged_radix = 16;
 | 
						|
 | 
						|
				hawk_rtx_refupval(rtx, v);
 | 
						|
 | 
						|
				vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | 
						|
				switch (vtype)
 | 
						|
				{
 | 
						|
					case HAWK_VAL_NIL:
 | 
						|
						str_ptr = HAWK_T("");
 | 
						|
						str_len = 0;
 | 
						|
						break;
 | 
						|
 | 
						|
					case HAWK_VAL_CHAR:
 | 
						|
						ooch_tmp = HAWK_RTX_GETCHARFROMVAL(rtx, v);
 | 
						|
						str_ptr = &ooch_tmp;
 | 
						|
						str_len = 1;
 | 
						|
						break;
 | 
						|
 | 
						|
					case HAWK_VAL_STR:
 | 
						|
						str_ptr = ((hawk_val_str_t*)v)->val.ptr;
 | 
						|
						str_len = ((hawk_val_str_t*)v)->val.len;
 | 
						|
						break;
 | 
						|
 | 
						|
					case HAWK_VAL_BCHR:
 | 
						|
					#if defined(HAWK_OOCH_IS_BCH)
 | 
						|
						ooch_tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v);
 | 
						|
						str_ptr = &ooch_tmp;
 | 
						|
						str_len = 1;
 | 
						|
					#else
 | 
						|
						if (fmt[i] == HAWK_T('s')) goto duplicate;
 | 
						|
						bch_tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v);
 | 
						|
						str_ptr = (hawk_ooch_t*)&bch_tmp;
 | 
						|
						str_len = 1;
 | 
						|
					#endif
 | 
						|
						break;
 | 
						|
 | 
						|
					case HAWK_VAL_MBS:
 | 
						|
					#if defined(HAWK_OOCH_IS_BCH)
 | 
						|
						str_ptr = ((hawk_val_mbs_t*)v)->val.ptr;
 | 
						|
						str_len = ((hawk_val_mbs_t*)v)->val.len;
 | 
						|
					#else
 | 
						|
						if (fmt[i] == HAWK_T('s')) goto duplicate;
 | 
						|
						str_ptr = (hawk_ooch_t*)((hawk_val_mbs_t*)v)->val.ptr;
 | 
						|
						str_len = ((hawk_val_mbs_t*)v)->val.len;
 | 
						|
					#endif
 | 
						|
						break;
 | 
						|
 | 
						|
					case HAWK_VAL_BOB:
 | 
						|
					#if defined(HAWK_OOCH_IS_BCH)
 | 
						|
						str_ptr = ((hawk_val_bob_t*)v)->val.ptr;
 | 
						|
						str_len = ((hawk_val_bob_t*)v)->val.len;
 | 
						|
					#else
 | 
						|
						if (fmt[i] == HAWK_T('s')) goto duplicate;
 | 
						|
						str_ptr = (hawk_ooch_t*)((hawk_val_bob_t*)v)->val.ptr;
 | 
						|
						str_len = ((hawk_val_bob_t*)v)->val.len;
 | 
						|
					#endif
 | 
						|
						break;
 | 
						|
 | 
						|
					default:
 | 
						|
					duplicate:
 | 
						|
						str_ptr = hawk_rtx_valtooocstrdup(rtx, v, &str_len);
 | 
						|
						if (!str_ptr)
 | 
						|
						{
 | 
						|
							hawk_rtx_refdownval(rtx, v);
 | 
						|
							return HAWK_NULL;
 | 
						|
						}
 | 
						|
 | 
						|
						str_free = str_ptr;
 | 
						|
						break;
 | 
						|
 | 
						|
				}
 | 
						|
 | 
						|
				if (wp_idx != WP_PRECISION || wp[WP_PRECISION] <= -1 || wp[WP_PRECISION] > (hawk_int_t)str_len)
 | 
						|
				{
 | 
						|
					/* precision not specified, or specified to a negative value or greater than the actual length */
 | 
						|
					wp[WP_PRECISION] = (hawk_int_t)str_len;
 | 
						|
				}
 | 
						|
				if (wp[WP_PRECISION] > wp[WP_WIDTH]) wp[WP_WIDTH] = wp[WP_PRECISION];
 | 
						|
 | 
						|
				if (!(flags & FLAG_MINUS))
 | 
						|
				{
 | 
						|
					/* right align */
 | 
						|
					while (wp[WP_WIDTH] > wp[WP_PRECISION])
 | 
						|
					{
 | 
						|
						if (hawk_ooecs_ccat(out, HAWK_T(' ')) == (hawk_oow_t)-1)
 | 
						|
						{
 | 
						|
							if (str_free) hawk_rtx_freemem(rtx, str_free);
 | 
						|
							hawk_rtx_refdownval(rtx, v);
 | 
						|
							return HAWK_NULL;
 | 
						|
						}
 | 
						|
						wp[WP_WIDTH]--;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				if (fmt[i] == 'k' || fmt[i] == 'w') bytetostr_flagged_radix |= HAWK_BYTE_TO_BCSTR_LOWERCASE;
 | 
						|
 | 
						|
				for (k = 0; k < wp[WP_PRECISION]; k++)
 | 
						|
				{
 | 
						|
					hawk_ooch_t curc;
 | 
						|
 | 
						|
				#if defined(HAWK_OOCH_IS_BCH)
 | 
						|
					curc = str_ptr[k];
 | 
						|
				#else
 | 
						|
					if ((vtype == HAWK_VAL_MBS || vtype == HAWK_VAL_BCHR) && fmt[i] != HAWK_T('s'))
 | 
						|
						curc = (hawk_uint8_t)((hawk_bch_t*)str_ptr)[k];
 | 
						|
					else curc = str_ptr[k];
 | 
						|
				#endif
 | 
						|
 | 
						|
					if ((fmt[i] != 's' && !HAWK_BYTE_PRINTABLE(curc)) || fmt[i] == 'w' || fmt[i] == 'W')
 | 
						|
					{
 | 
						|
						hawk_ooch_t xbuf[3];
 | 
						|
						if (curc <= 0xFF)
 | 
						|
						{
 | 
						|
							if (hawk_ooecs_ncat(out, HAWK_T("\\x"), 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_oocstr(curc, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0'));
 | 
						|
							if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
						}
 | 
						|
						else if (curc <= 0xFFFF)
 | 
						|
						{
 | 
						|
							hawk_uint16_t u16 = curc;
 | 
						|
							if (hawk_ooecs_ncat(out, HAWK_T("\\u"), 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_oocstr((u16 >> 8) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0'));
 | 
						|
							if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_oocstr(u16 & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0'));
 | 
						|
							if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
						}
 | 
						|
						else
 | 
						|
						{
 | 
						|
							hawk_uint32_t u32 = curc;
 | 
						|
							if (hawk_ooecs_ncat(out, HAWK_T("\\U"), 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_oocstr((u32 >> 24) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0'));
 | 
						|
							if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_oocstr((u32 >> 16) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0'));
 | 
						|
							if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_oocstr((u32 >> 8) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0'));
 | 
						|
							if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_oocstr(u32 & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0'));
 | 
						|
							if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
						}
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						if (hawk_ooecs_ccat(out, curc) == (hawk_oow_t)-1)
 | 
						|
						{
 | 
						|
						s_fail:
 | 
						|
							if (str_free) hawk_rtx_freemem(rtx, str_free);
 | 
						|
							hawk_rtx_refdownval(rtx, v);
 | 
						|
							return HAWK_NULL;
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				if (str_free) hawk_rtx_freemem(rtx, str_free);
 | 
						|
 | 
						|
				if (flags & FLAG_MINUS)
 | 
						|
				{
 | 
						|
					/* left align */
 | 
						|
					while (wp[WP_WIDTH] > wp[WP_PRECISION])
 | 
						|
					{
 | 
						|
						if (hawk_ooecs_ccat(out, HAWK_T(' ')) == (hawk_oow_t)-1)
 | 
						|
						{
 | 
						|
							hawk_rtx_refdownval(rtx, v);
 | 
						|
							return HAWK_NULL;
 | 
						|
						}
 | 
						|
						wp[WP_WIDTH]--;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				hawk_rtx_refdownval(rtx, v);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (fmt[i] != HAWK_T('%')) OUT_STR (HAWK_OOECS_PTR(fbu), HAWK_OOECS_LEN(fbu));
 | 
						|
			OUT_CHAR(fmt[i]);
 | 
						|
			goto skip_taking_arg;
 | 
						|
		}
 | 
						|
 | 
						|
		if (!args || val) stack_arg_idx++;
 | 
						|
		else args = args->next;
 | 
						|
	skip_taking_arg:
 | 
						|
		hawk_ooecs_clear (fbu);
 | 
						|
	}
 | 
						|
 | 
						|
	/* flush uncompleted formatting sequence */
 | 
						|
	OUT_STR (HAWK_OOECS_PTR(fbu), HAWK_OOECS_LEN(fbu));
 | 
						|
 | 
						|
	*len = HAWK_OOECS_LEN(out);
 | 
						|
	return HAWK_OOECS_PTR(out);
 | 
						|
}
 | 
						|
 | 
						|
/* ========================================================================= */
 | 
						|
 | 
						|
hawk_bch_t* hawk_rtx_formatmbs (
 | 
						|
	hawk_rtx_t* rtx, hawk_becs_t* out, hawk_becs_t* fbu,
 | 
						|
	const hawk_bch_t* fmt, hawk_oow_t fmt_len,
 | 
						|
	hawk_oow_t nargs_on_stack, hawk_nde_t* args, hawk_oow_t* len)
 | 
						|
{
 | 
						|
	hawk_oow_t i;
 | 
						|
	hawk_oow_t stack_arg_idx = 1;
 | 
						|
	hawk_val_t* val;
 | 
						|
 | 
						|
#define OUT_MCHAR(c) do { if (hawk_becs_ccat(out, (c)) == (hawk_oow_t)-1) return HAWK_NULL; } while(0)
 | 
						|
 | 
						|
#define OUT_MBS(ptr,len) do { if (hawk_becs_ncat(out, (ptr), (len)) == (hawk_oow_t)-1) return HAWK_NULL; } while(0)
 | 
						|
 | 
						|
#define FMT_MCHAR(c) do {  if (hawk_becs_ccat(fbu, (c)) == (hawk_oow_t)-1) return HAWK_NULL; } while(0)
 | 
						|
 | 
						|
#define FMT_MBS(ptr,len) do { if (hawk_becs_ncat(fbu, (ptr), (len)) == (hawk_oow_t)-1) return HAWK_NULL; } while(0)
 | 
						|
 | 
						|
#define GROW_MBSBUF(buf) do { \
 | 
						|
	if ((buf)->ptr) \
 | 
						|
	{ \
 | 
						|
		hawk_rtx_freemem(rtx, (buf)->ptr); \
 | 
						|
		(buf)->ptr = HAWK_NULL; \
 | 
						|
	} \
 | 
						|
	(buf)->len += (buf)->inc; \
 | 
						|
	(buf)->ptr = (hawk_bch_t*)hawk_rtx_allocmem(rtx, (buf)->len * HAWK_SIZEOF(hawk_bch_t)); \
 | 
						|
	if (HAWK_UNLIKELY(!(buf)->ptr)) \
 | 
						|
	{ \
 | 
						|
		(buf)->len = 0; \
 | 
						|
		return HAWK_NULL; \
 | 
						|
	} \
 | 
						|
} while(0)
 | 
						|
 | 
						|
#define GROW_MBSBUF_WITH_INC(buf,incv) do { \
 | 
						|
	if ((buf)->ptr) \
 | 
						|
	{ \
 | 
						|
		hawk_rtx_freemem(rtx, (buf)->ptr); \
 | 
						|
		(buf)->ptr = HAWK_NULL; \
 | 
						|
	} \
 | 
						|
	(buf)->len += ((incv) > (buf)->inc)? (incv): (buf)->inc; \
 | 
						|
	(buf)->ptr = (hawk_bch_t*)hawk_rtx_allocmem(rtx, (buf)->len * HAWK_SIZEOF(hawk_bch_t)); \
 | 
						|
	if (HAWK_UNLIKELY(!(buf)->ptr)) \
 | 
						|
	{ \
 | 
						|
		(buf)->len = 0; \
 | 
						|
		return HAWK_NULL; \
 | 
						|
	} \
 | 
						|
} while(0)
 | 
						|
 | 
						|
	/* run->format.tmp.ptr should have been assigned a pointer to a block of memory before this function has been called */
 | 
						|
	HAWK_ASSERT(rtx->formatmbs.tmp.ptr != HAWK_NULL);
 | 
						|
 | 
						|
	if (nargs_on_stack == (hawk_oow_t)-1)
 | 
						|
	{
 | 
						|
		/* dirty hack to support a single value argument instead of a tree node */
 | 
						|
		val = (hawk_val_t*)args;
 | 
						|
		nargs_on_stack = 2;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		val = HAWK_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (out == HAWK_NULL) out = &rtx->formatmbs.out;
 | 
						|
	if (fbu == HAWK_NULL) fbu = &rtx->formatmbs.fmt;
 | 
						|
 | 
						|
	hawk_becs_clear (out);
 | 
						|
	hawk_becs_clear (fbu);
 | 
						|
 | 
						|
	for (i = 0; i < fmt_len; i++)
 | 
						|
	{
 | 
						|
		hawk_int_t wp[2];
 | 
						|
		int wp_idx;
 | 
						|
#define WP_WIDTH     0
 | 
						|
#define WP_PRECISION 1
 | 
						|
 | 
						|
		int flags;
 | 
						|
#define FLAG_SPACE (1 << 0)
 | 
						|
#define FLAG_HASH  (1 << 1)
 | 
						|
#define FLAG_ZERO  (1 << 2)
 | 
						|
#define FLAG_PLUS  (1 << 3)
 | 
						|
#define FLAG_MINUS (1 << 4)
 | 
						|
 | 
						|
		if (HAWK_BECS_LEN(fbu) == 0)
 | 
						|
		{
 | 
						|
			/* format specifier is empty */
 | 
						|
			if (fmt[i] == HAWK_BT('%'))
 | 
						|
			{
 | 
						|
				/* add % to format specifier (fbu) */
 | 
						|
				FMT_MCHAR (fmt[i]);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				/* normal output */
 | 
						|
				OUT_MCHAR (fmt[i]);
 | 
						|
			}
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		/* handle flags */
 | 
						|
		flags = 0;
 | 
						|
		while (i < fmt_len)
 | 
						|
		{
 | 
						|
			switch (fmt[i])
 | 
						|
			{
 | 
						|
				case HAWK_BT(' '):
 | 
						|
					flags |= FLAG_SPACE;
 | 
						|
					break;
 | 
						|
				case HAWK_BT('#'):
 | 
						|
					flags |= FLAG_HASH;
 | 
						|
					break;
 | 
						|
				case HAWK_BT('0'):
 | 
						|
					flags |= FLAG_ZERO;
 | 
						|
					break;
 | 
						|
				case HAWK_BT('+'):
 | 
						|
					flags |= FLAG_PLUS;
 | 
						|
					break;
 | 
						|
				case HAWK_BT('-'):
 | 
						|
					flags |= FLAG_MINUS;
 | 
						|
					break;
 | 
						|
				default:
 | 
						|
					goto wp_mod_init;
 | 
						|
			}
 | 
						|
 | 
						|
			FMT_MCHAR (fmt[i]); i++;
 | 
						|
		}
 | 
						|
 | 
						|
wp_mod_init:
 | 
						|
		wp[WP_WIDTH] = 0; /* width */
 | 
						|
		wp[WP_PRECISION] = -1; /* precision */
 | 
						|
		wp_idx = WP_WIDTH; /* width first */
 | 
						|
 | 
						|
wp_mod_main:
 | 
						|
		if (i < fmt_len && fmt[i] == HAWK_BT('*'))
 | 
						|
		{
 | 
						|
			/* variable width/precision modifier.
 | 
						|
			 * take the width/precision from a parameter and
 | 
						|
			 * transform it to a fixed length format */
 | 
						|
			hawk_val_t* v;
 | 
						|
			int n;
 | 
						|
 | 
						|
			if (!args)
 | 
						|
			{
 | 
						|
				if (stack_arg_idx >= nargs_on_stack)
 | 
						|
				{
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
				v = hawk_rtx_getarg(rtx, stack_arg_idx);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (val)
 | 
						|
				{
 | 
						|
					if (stack_arg_idx >= nargs_on_stack)
 | 
						|
					{
 | 
						|
						hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					v = val;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					v = eval_expression(rtx, args);
 | 
						|
					if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
			n = hawk_rtx_valtoint(rtx, v, &wp[wp_idx]);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			if (HAWK_UNLIKELY(n <= -1)) return HAWK_NULL;
 | 
						|
 | 
						|
			do
 | 
						|
			{
 | 
						|
				n = hawk_fmt_intmax_to_bcstr (
 | 
						|
					rtx->formatmbs.tmp.ptr,
 | 
						|
					rtx->formatmbs.tmp.len,
 | 
						|
					wp[wp_idx],
 | 
						|
					10 | HAWK_FMT_INTMAX_NOTRUNC | HAWK_FMT_INTMAX_NONULL,
 | 
						|
					-1,
 | 
						|
					HAWK_BT('\0'),
 | 
						|
					HAWK_NULL
 | 
						|
				);
 | 
						|
				if (n <= -1)
 | 
						|
				{
 | 
						|
					/* -n is the number of characters required
 | 
						|
					 * including terminating null  */
 | 
						|
					GROW_MBSBUF_WITH_INC (&rtx->formatmbs.tmp, -n);
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			while (1);
 | 
						|
 | 
						|
			FMT_MBS(rtx->formatmbs.tmp.ptr, n);
 | 
						|
 | 
						|
			if (!args || val) stack_arg_idx++;
 | 
						|
			else args = args->next;
 | 
						|
			i++;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			/* fixed width/precision modifier */
 | 
						|
			if (i < fmt_len && hawk_is_bch_digit(fmt[i]))
 | 
						|
			{
 | 
						|
				wp[wp_idx] = 0;
 | 
						|
				do
 | 
						|
				{
 | 
						|
					wp[wp_idx] = wp[wp_idx] * 10 + fmt[i] - HAWK_BT('0');
 | 
						|
					FMT_MCHAR (fmt[i]); i++;
 | 
						|
				}
 | 
						|
				while (i < fmt_len && hawk_is_bch_digit(fmt[i]));
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (wp_idx == WP_WIDTH && i < fmt_len && fmt[i] == HAWK_BT('.'))
 | 
						|
		{
 | 
						|
			FMT_MCHAR (fmt[i]); i++;
 | 
						|
 | 
						|
			wp[WP_PRECISION] = 0;
 | 
						|
			wp_idx = WP_PRECISION; /* change index to precision */
 | 
						|
			goto wp_mod_main;
 | 
						|
		}
 | 
						|
 | 
						|
		if (i >= fmt_len) break;
 | 
						|
 | 
						|
		if (wp[WP_WIDTH] < 0)
 | 
						|
		{
 | 
						|
			wp[WP_WIDTH] = -wp[WP_WIDTH];
 | 
						|
			flags |= FLAG_MINUS;
 | 
						|
		}
 | 
						|
 | 
						|
		if (fmt[i] == HAWK_BT('d') || fmt[i] == HAWK_BT('i') ||
 | 
						|
		    fmt[i] == HAWK_BT('x') || fmt[i] == HAWK_BT('X') ||
 | 
						|
		    fmt[i] == HAWK_BT('b') || fmt[i] == HAWK_BT('B') ||
 | 
						|
		    fmt[i] == HAWK_BT('o'))
 | 
						|
		{
 | 
						|
			hawk_val_t* v;
 | 
						|
			hawk_int_t l;
 | 
						|
			int n;
 | 
						|
 | 
						|
			int fmt_flags;
 | 
						|
			int fmt_uint = 0;
 | 
						|
			int fmt_width;
 | 
						|
			hawk_bch_t fmt_fill = HAWK_BT('\0');
 | 
						|
			const hawk_bch_t* fmt_prefix = HAWK_NULL;
 | 
						|
 | 
						|
			if (!args)
 | 
						|
			{
 | 
						|
				if (stack_arg_idx >= nargs_on_stack)
 | 
						|
				{
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
				v = hawk_rtx_getarg(rtx, stack_arg_idx);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (val)
 | 
						|
				{
 | 
						|
					if (stack_arg_idx >= nargs_on_stack)
 | 
						|
					{
 | 
						|
						hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					v = val;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					v = eval_expression(rtx, args);
 | 
						|
					if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
			n = hawk_rtx_valtoint(rtx, v, &l);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			if (HAWK_UNLIKELY(n <= -1)) return HAWK_NULL;
 | 
						|
 | 
						|
			fmt_flags = HAWK_FMT_INTMAX_NOTRUNC | HAWK_FMT_INTMAX_NONULL;
 | 
						|
 | 
						|
			if (l == 0 && wp_idx == WP_PRECISION && wp[WP_PRECISION] == 0)
 | 
						|
			{
 | 
						|
				/* printf ("%.d", 0); printf ("%.0d", 0); printf ("%.*d", 0, 0); */
 | 
						|
				/* A zero value with a precision of zero produces no character. */
 | 
						|
				fmt_flags |= HAWK_FMT_INTMAX_NOZERO;
 | 
						|
			}
 | 
						|
 | 
						|
			if (wp[WP_WIDTH] > 0)
 | 
						|
			{
 | 
						|
				/* justification for width greater than 0 */
 | 
						|
				if (flags & FLAG_ZERO)
 | 
						|
				{
 | 
						|
					if (flags & FLAG_MINUS)
 | 
						|
					{
 | 
						|
						 /* FLAG_MINUS wins if both FLAG_ZERO
 | 
						|
						  * and FLAG_MINUS are specified. */
 | 
						|
						fmt_fill = HAWK_BT(' ');
 | 
						|
						if (flags & FLAG_MINUS)
 | 
						|
						{
 | 
						|
							/* left justification. need to fill the right side */
 | 
						|
							fmt_flags |= HAWK_FMT_INTMAX_FILLRIGHT;
 | 
						|
						}
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						if (wp_idx != WP_PRECISION) /* if precision is not set, wp_idx is at WP_WIDTH */
 | 
						|
						{
 | 
						|
							/* precision not specified.
 | 
						|
							 * FLAG_ZERO can take effect */
 | 
						|
							fmt_fill = HAWK_BT('0');
 | 
						|
							fmt_flags |= HAWK_FMT_INTMAX_FILLCENTER;
 | 
						|
						}
 | 
						|
						else
 | 
						|
						{
 | 
						|
							fmt_fill = HAWK_BT(' ');
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					fmt_fill = HAWK_BT(' ');
 | 
						|
					if (flags & FLAG_MINUS)
 | 
						|
					{
 | 
						|
						/* left justification. need to fill the right side */
 | 
						|
						fmt_flags |= HAWK_FMT_INTMAX_FILLRIGHT;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			switch (fmt[i])
 | 
						|
			{
 | 
						|
				case HAWK_BT('B'):
 | 
						|
				case HAWK_BT('b'):
 | 
						|
					fmt_flags |= 2;
 | 
						|
					fmt_uint = 1;
 | 
						|
					if (l && (flags & FLAG_HASH))
 | 
						|
					{
 | 
						|
						/* A nonzero value is prefixed with 0b */
 | 
						|
						fmt_prefix = HAWK_BT("0b");
 | 
						|
					}
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_BT('X'):
 | 
						|
					fmt_flags |= HAWK_FMT_INTMAX_UPPERCASE;
 | 
						|
				case HAWK_BT('x'):
 | 
						|
					fmt_flags |= 16;
 | 
						|
					fmt_uint = 1;
 | 
						|
					if (l && (flags & FLAG_HASH))
 | 
						|
					{
 | 
						|
						/* A nonzero value is prefixed with 0x */
 | 
						|
						fmt_prefix = HAWK_BT("0x");
 | 
						|
					}
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_BT('o'):
 | 
						|
					fmt_flags |= 8;
 | 
						|
					fmt_uint = 1;
 | 
						|
					if (flags & FLAG_HASH)
 | 
						|
					{
 | 
						|
						/* Force a leading zero digit including zero.
 | 
						|
						 * 0 with FLAG_HASH and precision 0 still emits '0'.
 | 
						|
						 * On the contrary, 'X' and 'x' emit no digits
 | 
						|
						 * for 0 with FLAG_HASH and precision 0. */
 | 
						|
						fmt_flags |= HAWK_FMT_INTMAX_ZEROLEAD;
 | 
						|
					}
 | 
						|
					break;
 | 
						|
 | 
						|
				default:
 | 
						|
					fmt_flags |= 10;
 | 
						|
					if (flags & FLAG_PLUS)
 | 
						|
						fmt_flags |= HAWK_FMT_INTMAX_PLUSSIGN;
 | 
						|
					if (flags & FLAG_SPACE)
 | 
						|
						fmt_flags |= HAWK_FMT_INTMAX_EMPTYSIGN;
 | 
						|
					break;
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
			if (wp[WP_WIDTH] > 0)
 | 
						|
			{
 | 
						|
				if (wp[WP_WIDTH] > rtx->formatmbs.tmp.len)
 | 
						|
					GROW_MBSBUF_WITH_INC (&rtx->formatmbs.tmp, wp[WP_WIDTH] - rtx->formatmbs.tmp.len);
 | 
						|
				fmt_width = wp[WP_WIDTH];
 | 
						|
			}
 | 
						|
			else fmt_width = rtx->formatmbs.tmp.len;
 | 
						|
 | 
						|
			do
 | 
						|
			{
 | 
						|
				if (fmt_uint)
 | 
						|
				{
 | 
						|
					/* Explicit type-casting for 'l' from hawk_int_t
 | 
						|
					 * to hawk_uint_t is needed before passing it to
 | 
						|
					 * hawk_fmt_uintmax_to_bcstr().
 | 
						|
 					 *
 | 
						|
					 * Consider a value of -1 for example.
 | 
						|
					 * -1 is a value with all bits set.
 | 
						|
					 * If hawk_int_t is 4 bytes and hawk_uintmax_t
 | 
						|
					 * is 8 bytes, the value is shown below for
 | 
						|
					 * each type respectively .
 | 
						|
					 *     -1 - 0xFFFFFFFF (hawk_int_t)
 | 
						|
					 *     -1 - 0xFFFFFFFFFFFFFFFF (hawk_uintmax_t)
 | 
						|
					 * Implicit typecasting of -1 from hawk_int_t to
 | 
						|
					 * to hawk_uintmax_t results in 0xFFFFFFFFFFFFFFFF,
 | 
						|
					 * though 0xFFFFFFF is expected in hexadecimal.
 | 
						|
					 */
 | 
						|
					n = hawk_fmt_uintmax_to_bcstr (
 | 
						|
						rtx->formatmbs.tmp.ptr,
 | 
						|
						fmt_width,
 | 
						|
						(hawk_uint_t)l,
 | 
						|
						fmt_flags,
 | 
						|
						wp[WP_PRECISION],
 | 
						|
						fmt_fill,
 | 
						|
						fmt_prefix
 | 
						|
					);
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					n = hawk_fmt_intmax_to_bcstr (
 | 
						|
						rtx->formatmbs.tmp.ptr,
 | 
						|
						fmt_width,
 | 
						|
						l,
 | 
						|
						fmt_flags,
 | 
						|
						wp[WP_PRECISION],
 | 
						|
						fmt_fill,
 | 
						|
						fmt_prefix
 | 
						|
					);
 | 
						|
				}
 | 
						|
				if (n <= -1)
 | 
						|
				{
 | 
						|
					/* -n is the number of characters required */
 | 
						|
					GROW_MBSBUF_WITH_INC (&rtx->formatmbs.tmp, -n);
 | 
						|
					fmt_width = -n;
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			while (1);
 | 
						|
 | 
						|
			OUT_MBS (rtx->formatmbs.tmp.ptr, n);
 | 
						|
		}
 | 
						|
		else if (fmt[i] == HAWK_BT('e') || fmt[i] == HAWK_BT('E') ||
 | 
						|
		         fmt[i] == HAWK_BT('g') || fmt[i] == HAWK_BT('G') ||
 | 
						|
		         fmt[i] == HAWK_BT('f'))
 | 
						|
		{
 | 
						|
			hawk_val_t* v;
 | 
						|
			hawk_flt_t r;
 | 
						|
			int n;
 | 
						|
 | 
						|
			if (!args)
 | 
						|
			{
 | 
						|
				if (stack_arg_idx >= nargs_on_stack)
 | 
						|
				{
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
				v = hawk_rtx_getarg(rtx, stack_arg_idx);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (val)
 | 
						|
				{
 | 
						|
					if (stack_arg_idx >= nargs_on_stack)
 | 
						|
					{
 | 
						|
						hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					v = val;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					v = eval_expression(rtx, args);
 | 
						|
					if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
			n = hawk_rtx_valtoflt(rtx, v, &r);
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
			if (n <= -1) return HAWK_NULL;
 | 
						|
 | 
						|
		#if defined(HAWK_USE_FLTMAX)
 | 
						|
			/*FMT_MCHAR (HAWK_BT('j'));*/
 | 
						|
			FMT_MBS (HAWK_BT("jj"), 2); /* see fmt.c for info on jj */
 | 
						|
			FMT_MCHAR (fmt[i]);
 | 
						|
			/*if (hawk_becs_fcat(out, HAWK_BECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL;*/
 | 
						|
			if (hawk_becs_fcat(out, HAWK_BECS_PTR(fbu), &r) == (hawk_oow_t)-1) return HAWK_NULL;
 | 
						|
		#else
 | 
						|
			FMT_MCHAR (HAWK_BT('z'));
 | 
						|
			FMT_MCHAR (fmt[i]);
 | 
						|
			if (hawk_becs_fcat(out, HAWK_BECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL;
 | 
						|
		#endif
 | 
						|
		}
 | 
						|
		else if (fmt[i] == HAWK_BT('c'))
 | 
						|
		{
 | 
						|
			hawk_bch_t ch;
 | 
						|
			hawk_oow_t ch_len;
 | 
						|
			hawk_val_t* v;
 | 
						|
			hawk_val_type_t vtype;
 | 
						|
 | 
						|
			if (!args)
 | 
						|
			{
 | 
						|
				if (stack_arg_idx >= nargs_on_stack)
 | 
						|
				{
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
				v = hawk_rtx_getarg(rtx, stack_arg_idx);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (val)
 | 
						|
				{
 | 
						|
					if (stack_arg_idx >= nargs_on_stack)
 | 
						|
					{
 | 
						|
						hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					v = val;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					v = eval_expression(rtx, args);
 | 
						|
					if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refupval(rtx, v);
 | 
						|
			vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | 
						|
			switch (vtype)
 | 
						|
			{
 | 
						|
				case HAWK_VAL_NIL:
 | 
						|
					ch = HAWK_BT('\0');
 | 
						|
					ch_len = 0;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_CHAR:
 | 
						|
					ch = (hawk_bch_t)HAWK_RTX_GETCHARFROMVAL(rtx, v); /* the value may get truncated */
 | 
						|
					ch_len = 1;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_BCHR:
 | 
						|
					ch = HAWK_RTX_GETBCHRFROMVAL(rtx, v);
 | 
						|
					ch_len = 1;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_INT:
 | 
						|
					ch = (hawk_bch_t)HAWK_RTX_GETINTFROMVAL(rtx, v);
 | 
						|
					ch_len = 1;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_FLT:
 | 
						|
					ch = (hawk_bch_t)((hawk_val_flt_t*)v)->val;
 | 
						|
					ch_len = 1;
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_STR:
 | 
						|
					ch_len = ((hawk_val_str_t*)v)->val.len;
 | 
						|
					if (ch_len > 0)
 | 
						|
					{
 | 
						|
						/* value truncation is expected */
 | 
						|
						ch = ((hawk_val_str_t*)v)->val.ptr[0];
 | 
						|
						ch_len = 1;
 | 
						|
					}
 | 
						|
					else ch = HAWK_BT('\0');
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_MBS:
 | 
						|
					ch_len = ((hawk_val_mbs_t*)v)->val.len;
 | 
						|
					if (ch_len > 0)
 | 
						|
					{
 | 
						|
						ch = ((hawk_val_mbs_t*)v)->val.ptr[0];
 | 
						|
						ch_len = 1;
 | 
						|
					}
 | 
						|
					else ch = HAWK_BT('\0');
 | 
						|
					break;
 | 
						|
 | 
						|
				case HAWK_VAL_BOB:
 | 
						|
					ch_len = ((hawk_val_bob_t*)v)->val.len;
 | 
						|
					if (ch_len > 0)
 | 
						|
					{
 | 
						|
						ch = ((hawk_bch_t*)((hawk_val_bob_t*)v)->val.ptr)[0];
 | 
						|
						ch_len = 1;
 | 
						|
					}
 | 
						|
					else ch = 0;
 | 
						|
					break;
 | 
						|
 | 
						|
				default:
 | 
						|
					hawk_rtx_refdownval(rtx, v);
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EVALTOCHR);
 | 
						|
					return HAWK_NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			if (wp[WP_PRECISION] <= 0 || wp[WP_PRECISION] > (hawk_int_t)ch_len)
 | 
						|
			{
 | 
						|
				wp[WP_PRECISION] = (hawk_int_t)ch_len;
 | 
						|
			}
 | 
						|
 | 
						|
			if (wp[WP_PRECISION] > wp[WP_WIDTH]) wp[WP_WIDTH] = wp[WP_PRECISION];
 | 
						|
 | 
						|
			if (!(flags & FLAG_MINUS))
 | 
						|
			{
 | 
						|
				/* right align */
 | 
						|
				while (wp[WP_WIDTH] > wp[WP_PRECISION])
 | 
						|
				{
 | 
						|
					if (hawk_becs_ccat(out, HAWK_BT(' ')) == (hawk_oow_t)-1)
 | 
						|
					{
 | 
						|
						hawk_rtx_refdownval(rtx, v);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					wp[WP_WIDTH]--;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (wp[WP_PRECISION] > 0)
 | 
						|
			{
 | 
						|
				if (hawk_becs_ccat(out, ch) == (hawk_oow_t)-1)
 | 
						|
				{
 | 
						|
					hawk_rtx_refdownval(rtx, v);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (flags & FLAG_MINUS)
 | 
						|
			{
 | 
						|
				/* left align */
 | 
						|
				while (wp[WP_WIDTH] > wp[WP_PRECISION])
 | 
						|
				{
 | 
						|
					if (hawk_becs_ccat(out, HAWK_BT(' ')) == (hawk_oow_t)-1)
 | 
						|
					{
 | 
						|
						hawk_rtx_refdownval(rtx, v);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					wp[WP_WIDTH]--;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			hawk_rtx_refdownval(rtx, v);
 | 
						|
		}
 | 
						|
		else if (fmt[i] == 's' || fmt[i] == 'k' || fmt[i] == 'K' || fmt[i] == 'w' || fmt[i] == 'W')
 | 
						|
		{
 | 
						|
			hawk_val_t* v;
 | 
						|
 | 
						|
			if (!args)
 | 
						|
			{
 | 
						|
				if (stack_arg_idx >= nargs_on_stack)
 | 
						|
				{
 | 
						|
					hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
					return HAWK_NULL;
 | 
						|
				}
 | 
						|
				v = hawk_rtx_getarg(rtx, stack_arg_idx);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (val)
 | 
						|
				{
 | 
						|
					if (stack_arg_idx >= nargs_on_stack)
 | 
						|
					{
 | 
						|
						hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EFMTARG);
 | 
						|
						return HAWK_NULL;
 | 
						|
					}
 | 
						|
					v = val;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					v = eval_expression(rtx, args);
 | 
						|
					if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (val)
 | 
						|
			{
 | 
						|
				/* val_flt_to_str() in val.c calls hawk_rtx_format() with nargs_on_stack of (hawk_oow_t)-1 and the actual value.
 | 
						|
				 * the actual value is assigned to 'val' at the beginning of this function.
 | 
						|
				 *
 | 
						|
				 * the following code can drive here.
 | 
						|
				 *     BEGIN { CONVFMT="%s"; a=98.76 ""; }
 | 
						|
				 *
 | 
						|
				 * when the first attempt to convert 98.76 to a textual form invokes this function with %s and 98.76.
 | 
						|
				 * it comes to this part because the format specifier is 's'. since the floating-point type is not
 | 
						|
				 * specially handled, hawk_rtx_valtooocstrdup() is called below. it calls val_flt_to_str() again,
 | 
						|
				 * which eventually creates recursion and stack depletion.
 | 
						|
				 *
 | 
						|
				 * assuming only val_flt_to_str() calls it this way, i must convert the floating point number
 | 
						|
				 * to text in a rather crude way without calling hawk_rtx_valtooocstrdup().
 | 
						|
				 */
 | 
						|
				hawk_flt_t r;
 | 
						|
				int n;
 | 
						|
 | 
						|
				HAWK_ASSERT(HAWK_RTX_GETVALTYPE(rtx, val) == HAWK_VAL_FLT);
 | 
						|
 | 
						|
				hawk_rtx_refupval(rtx, v);
 | 
						|
				n = hawk_rtx_valtoflt(rtx, v, &r);
 | 
						|
				hawk_rtx_refdownval(rtx, v);
 | 
						|
				if (n <= -1) return HAWK_NULL;
 | 
						|
 | 
						|
				/* format the value as if '%g' is given */
 | 
						|
			#if defined(HAWK_USE_FLTMAX)
 | 
						|
				FMT_MBS (HAWK_BT("jjg"), 3); /* see fmt.c for info on jj */
 | 
						|
				if (hawk_becs_fcat(out, HAWK_BECS_PTR(fbu), &r) == (hawk_oow_t)-1) return HAWK_NULL;
 | 
						|
			#else
 | 
						|
				FMT_MBS (HAWK_BT("zg"), 2);
 | 
						|
				if (hawk_becs_fcat(out, HAWK_BECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL;
 | 
						|
			#endif
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				hawk_bch_t* str_ptr, * str_free = HAWK_NULL, bchr_tmp;
 | 
						|
				hawk_ooch_t ooch_tmp;
 | 
						|
				hawk_oow_t str_len;
 | 
						|
				hawk_int_t k;
 | 
						|
				hawk_val_type_t vtype;
 | 
						|
				int bytetombs_flagged_radix = 16;
 | 
						|
 | 
						|
				hawk_rtx_refupval(rtx, v);
 | 
						|
 | 
						|
				vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | 
						|
				switch (vtype)
 | 
						|
				{
 | 
						|
					case HAWK_VAL_NIL:
 | 
						|
						str_ptr = HAWK_BT("");
 | 
						|
						str_len = 0;
 | 
						|
						break;
 | 
						|
 | 
						|
					case HAWK_VAL_BCHR:
 | 
						|
						bchr_tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v);
 | 
						|
						str_ptr = &bchr_tmp;
 | 
						|
						str_len = 1;
 | 
						|
						break;
 | 
						|
 | 
						|
					case HAWK_VAL_MBS:
 | 
						|
						str_ptr = ((hawk_val_mbs_t*)v)->val.ptr;
 | 
						|
						str_len = ((hawk_val_mbs_t*)v)->val.len;
 | 
						|
						break;
 | 
						|
 | 
						|
					case HAWK_VAL_BOB:
 | 
						|
						str_ptr = (hawk_bch_t*)((hawk_val_bob_t*)v)->val.ptr;
 | 
						|
						str_len = ((hawk_val_bob_t*)v)->val.len;
 | 
						|
						break;
 | 
						|
 | 
						|
					case HAWK_VAL_CHAR:
 | 
						|
					#if defined(HAWK_OOCH_IS_BCH)
 | 
						|
						bchr_tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v);
 | 
						|
						str_ptr = &bchr_tmp;
 | 
						|
						str_len = 1;
 | 
						|
					#else
 | 
						|
						if (fmt[i] == HAWK_BT('s')) goto duplicate;
 | 
						|
						ooch_tmp = HAWK_RTX_GETCHARFROMVAL(rtx, v);
 | 
						|
						str_ptr = (hawk_bch_t*)&ooch_tmp;
 | 
						|
						str_len = 1 * (HAWK_SIZEOF_OOCH_T / HAWK_SIZEOF_BCH_T);
 | 
						|
					#endif
 | 
						|
						break;
 | 
						|
 | 
						|
					case HAWK_VAL_STR:
 | 
						|
					#if defined(HAWK_OOCH_IS_BCH)
 | 
						|
						str_ptr = ((hawk_val_str_t*)v)->val.ptr;
 | 
						|
						str_len = ((hawk_val_str_t*)v)->val.len;
 | 
						|
					#else
 | 
						|
						if (fmt[i] == HAWK_BT('s')) goto duplicate;
 | 
						|
						/* arrange to print the wide character string byte by byte regardless of byte order */
 | 
						|
						str_ptr = (hawk_bch_t*)((hawk_val_str_t*)v)->val.ptr;
 | 
						|
						str_len = ((hawk_val_str_t*)v)->val.len * (HAWK_SIZEOF_OOCH_T / HAWK_SIZEOF_BCH_T);
 | 
						|
					#endif
 | 
						|
						break;
 | 
						|
 | 
						|
					default:
 | 
						|
					duplicate:
 | 
						|
						str_ptr = hawk_rtx_valtobcstrdup(rtx, v, &str_len);
 | 
						|
						if (!str_ptr)
 | 
						|
						{
 | 
						|
							hawk_rtx_refdownval(rtx, v);
 | 
						|
							return HAWK_NULL;
 | 
						|
						}
 | 
						|
 | 
						|
						str_free = str_ptr;
 | 
						|
						break;
 | 
						|
				}
 | 
						|
 | 
						|
				if (wp_idx != WP_PRECISION || wp[WP_PRECISION] <= -1 || wp[WP_PRECISION] > (hawk_int_t)str_len)
 | 
						|
				{
 | 
						|
					/* precision not specified, or specified to a negative value or greater than the actual length */
 | 
						|
					wp[WP_PRECISION] = (hawk_int_t)str_len;
 | 
						|
				}
 | 
						|
				if (wp[WP_PRECISION] > wp[WP_WIDTH]) wp[WP_WIDTH] = wp[WP_PRECISION];
 | 
						|
 | 
						|
				if (!(flags & FLAG_MINUS))
 | 
						|
				{
 | 
						|
					/* right align */
 | 
						|
					while (wp[WP_WIDTH] > wp[WP_PRECISION])
 | 
						|
					{
 | 
						|
						if (hawk_becs_ccat(out, HAWK_BT(' ')) == (hawk_oow_t)-1)
 | 
						|
						{
 | 
						|
							if (str_free) hawk_rtx_freemem(rtx, str_free);
 | 
						|
							hawk_rtx_refdownval(rtx, v);
 | 
						|
							return HAWK_NULL;
 | 
						|
						}
 | 
						|
						wp[WP_WIDTH]--;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				if (fmt[i] == 'k' || fmt[i] == 'w') bytetombs_flagged_radix |= HAWK_BYTE_TO_BCSTR_LOWERCASE;
 | 
						|
 | 
						|
				for (k = 0; k < wp[WP_PRECISION]; k++)
 | 
						|
				{
 | 
						|
					hawk_bch_t curc;
 | 
						|
 | 
						|
					curc = str_ptr[k];
 | 
						|
 | 
						|
					if ((fmt[i] != 's' && !HAWK_BYTE_PRINTABLE(curc)) || fmt[i] == 'w' || fmt[i] == 'W')
 | 
						|
					{
 | 
						|
						hawk_bch_t xbuf[3];
 | 
						|
					#if 0 /* the range check isn't needed for hawk_bch_t. it's always <= 0xFF */
 | 
						|
 | 
						|
						if (curc <= 0xFF)
 | 
						|
						{
 | 
						|
					#endif
 | 
						|
							if (hawk_becs_ncat(out, HAWK_BT("\\x"), 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_bcstr(curc, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0'));
 | 
						|
							if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
					#if 0
 | 
						|
						}
 | 
						|
						else if (curc <= 0xFFFF)
 | 
						|
						{
 | 
						|
							hawk_uint16_t u16 = curc;
 | 
						|
							if (hawk_becs_ncat(out, HAWK_BT("\\u"), 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_bcstr((u16 >> 8) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0'));
 | 
						|
							if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_bcstr(u16 & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0'));
 | 
						|
							if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
						}
 | 
						|
						else
 | 
						|
						{
 | 
						|
							hawk_uint32_t u32 = curc;
 | 
						|
							if (hawk_becs_ncat(out, HAWK_BT("\\U"), 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_bcstr((u32 >> 24) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0'));
 | 
						|
							if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_bcstr((u32 >> 16) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0'));
 | 
						|
							if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_bcstr((u32 >> 8) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0'));
 | 
						|
							if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
							hawk_byte_to_bcstr(u32 & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0'));
 | 
						|
							if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail;
 | 
						|
						}
 | 
						|
					#endif
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						if (hawk_becs_ccat(out, curc) == (hawk_oow_t)-1)
 | 
						|
						{
 | 
						|
						s_fail:
 | 
						|
							if (str_free) hawk_rtx_freemem(rtx, str_free);
 | 
						|
							hawk_rtx_refdownval(rtx, v);
 | 
						|
							return HAWK_NULL;
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				if (str_free) hawk_rtx_freemem(rtx, str_free);
 | 
						|
 | 
						|
				if (flags & FLAG_MINUS)
 | 
						|
				{
 | 
						|
					/* left align */
 | 
						|
					while (wp[WP_WIDTH] > wp[WP_PRECISION])
 | 
						|
					{
 | 
						|
						if (hawk_becs_ccat(out, HAWK_BT(' ')) == (hawk_oow_t)-1)
 | 
						|
						{
 | 
						|
							hawk_rtx_refdownval(rtx, v);
 | 
						|
							return HAWK_NULL;
 | 
						|
						}
 | 
						|
						wp[WP_WIDTH]--;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				hawk_rtx_refdownval(rtx, v);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (fmt[i] != HAWK_BT('%')) OUT_MBS (HAWK_BECS_PTR(fbu), HAWK_BECS_LEN(fbu));
 | 
						|
			OUT_MCHAR (fmt[i]);
 | 
						|
			goto skip_taking_arg;
 | 
						|
		}
 | 
						|
 | 
						|
		if (!args || val) stack_arg_idx++;
 | 
						|
		else args = args->next;
 | 
						|
	skip_taking_arg:
 | 
						|
		hawk_becs_clear (fbu);
 | 
						|
	}
 | 
						|
 | 
						|
	/* flush uncompleted formatting sequence */
 | 
						|
	OUT_MBS (HAWK_BECS_PTR(fbu), HAWK_BECS_LEN(fbu));
 | 
						|
 | 
						|
	*len = HAWK_BECS_LEN(out);
 | 
						|
	return HAWK_BECS_PTR(out);
 | 
						|
}
 | 
						|
 | 
						|
/* ------------------------------------------------------------------------- */
 | 
						|
 | 
						|
void hawk_rtx_setnrflt (hawk_rtx_t* rtx, const hawk_nrflt_t* nrflt)
 | 
						|
{
 | 
						|
	rtx->nrflt = *nrflt;
 | 
						|
}
 | 
						|
 | 
						|
void hawk_rtx_getnrflt (hawk_rtx_t* rtx, hawk_nrflt_t* nrflt)
 | 
						|
{
 | 
						|
	*nrflt = rtx->nrflt;
 | 
						|
}
 | 
						|
 | 
						|
/* ------------------------------------------------------------------------ */
 | 
						|
 | 
						|
hawk_oow_t hawk_rtx_fmttoucstr_ (hawk_rtx_t* rtx, hawk_uch_t* buf, hawk_oow_t bufsz, const hawk_uch_t* fmt, ...)
 | 
						|
{
 | 
						|
	va_list ap;
 | 
						|
	hawk_oow_t n;
 | 
						|
	va_start(ap, fmt);
 | 
						|
	n = hawk_gem_vfmttoucstr(hawk_rtx_getgem(rtx), buf, bufsz, fmt, ap);
 | 
						|
	va_end(ap);
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
hawk_oow_t hawk_rtx_fmttobcstr_ (hawk_rtx_t* rtx, hawk_bch_t* buf, hawk_oow_t bufsz, const hawk_bch_t* fmt, ...)
 | 
						|
{
 | 
						|
	va_list ap;
 | 
						|
	hawk_oow_t n;
 | 
						|
	va_start(ap, fmt);
 | 
						|
	n = hawk_gem_vfmttobcstr(hawk_rtx_getgem(rtx), buf, bufsz, fmt, ap);
 | 
						|
	va_end(ap);
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
/* ------------------------------------------------------------------------ */
 | 
						|
 | 
						|
int hawk_rtx_buildrex (hawk_rtx_t* rtx, const hawk_ooch_t* ptn, hawk_oow_t len, hawk_tre_t** code, hawk_tre_t** icode)
 | 
						|
{
 | 
						|
	return hawk_gem_buildrex(hawk_rtx_getgem(rtx), ptn, len, !(rtx->hawk->opt.trait & HAWK_REXBOUND), code, icode);
 | 
						|
}
 |