Compare commits

9 Commits

10 changed files with 3193 additions and 118 deletions
+87
View File
@@ -69,6 +69,20 @@ typedef struct hawk_tree_t hawk_tree_t;
#define HAWK_ENABLE_ATOMIC_SIG
#endif
/* this part is kept for preservation of experiment only.
#if defined(HAVE_UCONTEXT_H)
#include <ucontext.h>
#define HAWK_ENABLE_UCONTEXT
#endif
*/
/* Use iterative (heap-stack) expression evaluation instead of C recursion.
* eval_expression, eval_expression0, and hawk_rtx_evalcall automatically
* route through the xstack variants when this is defined. Comment out to
* revert to the purely recursive implementation. */
/*#define HAWK_ENABLE_XSTACK_EVAL*/
/* ------------------------------------------------------------------------ */
/* private headers. some files are affected by feature macros above */
@@ -448,6 +462,49 @@ struct hawk_exec_stack_t
typedef struct hawk_exec_stack_t hawk_exec_stack_t;
/* expression frame states for eval_expression0_xstack */
enum hawk_ef_state_t
{
HAWK_EF_EVAL = 0, /* dispatch on nde->type */
HAWK_EF_BIN_LEFT, /* binary: awaiting left result */
HAWK_EF_BIN_RIGHT, /* binary: left done (val=left refupped), awaiting right */
HAWK_EF_UNARY, /* unary: awaiting operand result */
HAWK_EF_CND, /* conditional: awaiting test result */
HAWK_EF_ASS_RHS, /* assignment: awaiting RHS result */
HAWK_EF_ASS_LHS, /* compound assign: RHS in val (refupped), awaiting LHS */
HAWK_EF_LAND_LEFT, /* logical AND: awaiting left result */
HAWK_EF_LAND_RIGHT, /* logical AND: left done and true (val=left), awaiting right */
HAWK_EF_LOR_LEFT, /* logical OR: awaiting left result */
HAWK_EF_LOR_RIGHT, /* logical OR: left done and false (val=left), awaiting right */
#if defined(HAWK_ENABLE_XSTACK_EVAL)
HAWK_EF_FNCALL_FUN_AWAIT /* user fn body executing on exec_stack; aux=exec_body_base */
#endif
};
typedef enum hawk_ef_state_t hawk_ef_state_t;
struct hawk_eframe_t
{
hawk_ef_state_t state;
hawk_nde_t* nde; /* composite node being processed */
hawk_val_t* val; /* intermediate value (refcount incremented) */
hawk_oow_t aux; /* FNCALL_FUN_AWAIT: exec_stack size when body frames were pushed */
};
typedef struct hawk_eframe_t hawk_eframe_t;
#if defined(HAWK_ENABLE_XSTACK_EVAL)
/* call frame: saves context for a user-defined function call made from within
* expression evaluation. stored in the call_stack. */
struct hawk_call_frame_t
{
hawk_nde_fncall_t* call; /* call-site node */
hawk_fun_t* fun; /* resolved function */
hawk_oow_t saved_stack_top; /* rtx->stack_top before the call */
hawk_oow_t saved_stack_base;/* rtx->stack_base before the call */
hawk_oow_t nargs; /* actual argument count pushed */
};
typedef struct hawk_call_frame_t hawk_call_frame_t;
#endif
struct hawk_rtx_t
{
HAWK_RTX_HDR;
@@ -467,6 +524,36 @@ struct hawk_rtx_t
hawk_oow_t exec_stack_size;
hawk_oow_t exec_stack_limit;
/* heap-based stack for iterative expression evaluation (xstack variant) */
hawk_eframe_t* eframe_stack;
hawk_oow_t eframe_stack_size;
hawk_oow_t eframe_stack_limit;
#if defined(HAWK_ENABLE_XSTACK_EVAL)
/* heap-based call frame stack: user-defined function calls from eframe evaluation */
hawk_call_frame_t* call_stack;
hawk_oow_t call_stack_size;
hawk_oow_t call_stack_limit;
/* result register: eframe eval result delivered to exec AFTER_EVAL frames */
hawk_val_t* driver_eval_result;
#endif
#if defined(HAWK_ENABLE_UCONTEXT)
/* pool of reusable C stacks for coroutine-based function calls */
struct
{
char* pool[16];
hawk_oow_t pool_size;
/* arguments for the next coroutine invocation */
hawk_nde_blk_t* pending_body;
int* pending_result;
/* depth at which the current C stack segment started */
hawk_oow_t stack_base;
/* nonzero when executing on a heap-allocated coroutine stack */
int in_coroutine;
} co;
#endif
int exit_level;
int init_called;
+6 -2
View File
@@ -1922,12 +1922,14 @@ static HAWK_INLINE void hawk_geterruinf (hawk_t* hawk, hawk_erruinf_t* errinf) {
* it automatically formatted.
*/
#if defined(HAWK_HAVE_INLINE)
static HAWK_INLINE void hawk_seterrnum (hawk_t* hawk, const hawk_loc_t* errloc, hawk_errnum_t errnum) { hawk_gem_seterrnum (hawk_getgem(hawk), errloc, errnum); }
static HAWK_INLINE void hawk_seterrinf (hawk_t* hawk, const hawk_errinf_t* errinf) { hawk_gem_seterrinf (hawk_getgem(hawk), errinf); }
static HAWK_INLINE void hawk_clrerror (hawk_t* hawk) { hawk_gem_seterrnum(hawk_getgem(hawk), HAWK_NULL, HAWK_ENOERR); }
static HAWK_INLINE void hawk_seterrnum (hawk_t* hawk, const hawk_loc_t* errloc, hawk_errnum_t errnum) { hawk_gem_seterrnum(hawk_getgem(hawk), errloc, errnum); }
static HAWK_INLINE void hawk_seterrinf (hawk_t* hawk, const hawk_errinf_t* errinf) { hawk_gem_seterrinf(hawk_getgem(hawk), errinf); }
static HAWK_INLINE void hawk_seterror (hawk_t* hawk, const hawk_loc_t* errloc, hawk_errnum_t errnum, const hawk_oocs_t* errarg) { hawk_gem_seterror(hawk_getgem(hawk), errloc, errnum, errarg); }
static HAWK_INLINE const hawk_ooch_t* hawk_backuperrmsg (hawk_t* hawk) { return hawk_gem_backuperrmsg(hawk_getgem(hawk)); }
static HAWK_INLINE void hawk_geterror (hawk_t* hawk, hawk_errnum_t* errnum, const hawk_ooch_t** errmsg, hawk_loc_t* errloc) { return hawk_gem_geterror(hawk_getgem(hawk), errnum, errmsg, errloc); }
#else
#define hawk_clrerror(hawk) hawk_gem_seterrnum(hawk_getgem(hawk), HAWK_NULL, HAWK_ENOERR)
#define hawk_seterrnum(hawk, errloc, errnum) hawk_gem_seterrnum(hawk_getgem(hawk), errloc, errnum)
#define hawk_seterrinf(hawk, errinf) hawk_gem_seterrinf(hawk_getgem(hawk), errinf)
#define hawk_seterror(hawk, errloc, errnum, errarg) hawk_gem_seterror(hawk_getgem(hawk), errloc, errnum, errarg)
@@ -3119,11 +3121,13 @@ static HAWK_INLINE void hawk_rtx_geterror (hawk_rtx_t* rtx, hawk_errnum_t* errnu
* The hawk_rtx_seterrinf() function sets error information.
*/
#if defined(HAWK_HAVE_INLINE)
static HAWK_INLINE void hawk_rtx_clrerror (hawk_rtx_t* rtx) { hawk_gem_seterrnum(hawk_rtx_getgem(rtx), HAWK_NULL, HAWK_ENOERR); }
static HAWK_INLINE void hawk_rtx_seterrnum (hawk_rtx_t* rtx, const hawk_loc_t* errloc, hawk_errnum_t errnum) { hawk_gem_seterrnum (hawk_rtx_getgem(rtx), errloc, errnum); }
static HAWK_INLINE void hawk_rtx_seterrinf (hawk_rtx_t* rtx, const hawk_errinf_t* errinf) { hawk_gem_seterrinf (hawk_rtx_getgem(rtx), errinf); }
static HAWK_INLINE void hawk_rtx_seterror (hawk_rtx_t* rtx, const hawk_loc_t* errloc, hawk_errnum_t errnum, const hawk_oocs_t* errarg) { hawk_gem_seterror(hawk_rtx_getgem(rtx), errloc, errnum, errarg); }
static HAWK_INLINE const hawk_ooch_t* hawk_rtx_backuperrmsg (hawk_rtx_t* rtx) { return hawk_gem_backuperrmsg(hawk_rtx_getgem(rtx)); }
#else
#define hawk_rtx_clrerror(rtx) hawk_gem_seterrnum(hawk_rtx_getgem(rtx), HAWK_NULL, HAWK_ENOERR)
#define hawk_rtx_seterrnum(rtx, errloc, errnum) hawk_gem_seterrnum(hawk_rtx_getgem(rtx), errloc, errnum)
#define hawk_rtx_seterrinf(rtx, errinf) hawk_gem_seterrinf(hawk_rtx_getgem(rtx), errinf)
#define hawk_rtx_seterror(rtx, errloc, errnum, errarg) hawk_gem_seterror(hawk_rtx_getgem(rtx), errloc, errnum, errarg)
+9 -4
View File
@@ -22,6 +22,15 @@
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <hawk-cfg.h>
#if defined(HAVE_ACCEPT4)
/* the runtime library has accept4. but accept4 is usually visiable
* if _GNU_SOURCE is defined */
# if !defined(_GNU_SOURCE)
# define _GNU_SOURCE
# endif
#endif
#include "mod-sys.h"
#include "hawk-prv.h"
#include <hawk-pio.h>
@@ -42,10 +51,6 @@
#elif defined(__DOS__)
# include <dos.h>
#else
# if !defined(_GNU_SOURCE)
# define _GNU_SOURCE
# endif
# include "syscall.h"
# include <sys/utsname.h>
# if defined(HAVE_SYS_EPOLL_H)
+13
View File
@@ -30,6 +30,7 @@ enum hawk_assop_type_t
/* if you change this, you have to change assop_str in tree.c.
* synchronize it wit:
* - binop_func in eval_assignment of run.c
* - binop_func in eval_expression0_xstack in run.c
* - assop in assing_to_opcode of parse.c
* - TOK_XXX_ASSN in tok_t in parse.c
* - assop_str in tree.c
@@ -149,6 +150,18 @@ hawk_val_t* hawk_rtx_evalcall (
void* eharg
);
#if 0
hawk_val_t* hawk_rtx_evalcall_xstack (
hawk_rtx_t* rtx,
hawk_nde_fncall_t* call,
hawk_fun_t* fun,
hawk_oow_t(*argpusher)(hawk_rtx_t*,const hawk_loc_t* loc,void*),
void* apdata,
void(*errhandler)(void*),
void* eharg
);
#endif
int hawk_rtx_setsighandler (
hawk_rtx_t* rtx,
int sig,
+2451 -83
View File
File diff suppressed because it is too large Load Diff
+29 -27
View File
@@ -231,7 +231,7 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
PUT_SRCSTR(hawk, HAWK_T(" "));
PRINT_EXPR(hawk, px->right);
HAWK_ASSERT (px->right->next == HAWK_NULL);
HAWK_ASSERT(px->right->next == HAWK_NULL);
break;
}
@@ -241,7 +241,7 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
PUT_SRCSTR(hawk, HAWK_T("("));
PRINT_EXPR(hawk, px->left);
HAWK_ASSERT (px->left->next == HAWK_NULL);
HAWK_ASSERT(px->left->next == HAWK_NULL);
PUT_SRCSTR(hawk, HAWK_T(" "));
PUT_SRCSTR(hawk, binop_str[px->opcode][(hawk->opt.trait & HAWK_BLANKCONCAT)? 0: 1]);
@@ -252,7 +252,7 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
PRINT_EXPR(hawk, px->right);
if (px->right->type == HAWK_NDE_ASS)
PUT_SRCSTR(hawk, HAWK_T(")"));
HAWK_ASSERT (px->right->next == HAWK_NULL);
HAWK_ASSERT(px->right->next == HAWK_NULL);
PUT_SRCSTR(hawk, HAWK_T(")"));
break;
}
@@ -260,7 +260,7 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
case HAWK_NDE_EXP_UNR:
{
hawk_nde_exp_t* px = (hawk_nde_exp_t*)nde;
HAWK_ASSERT (px->right == HAWK_NULL);
HAWK_ASSERT(px->right == HAWK_NULL);
PUT_SRCSTR(hawk, HAWK_T("("));
PUT_SRCSTR(hawk, unrop_str[px->opcode]);
@@ -274,7 +274,7 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
case HAWK_NDE_EXP_INCPRE:
{
hawk_nde_exp_t* px = (hawk_nde_exp_t*)nde;
HAWK_ASSERT (px->right == HAWK_NULL);
HAWK_ASSERT(px->right == HAWK_NULL);
PUT_SRCSTR(hawk, incop_str[px->opcode]);
PUT_SRCSTR(hawk, HAWK_T("("));
@@ -286,7 +286,7 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
case HAWK_NDE_EXP_INCPST:
{
hawk_nde_exp_t* px = (hawk_nde_exp_t*)nde;
HAWK_ASSERT (px->right == HAWK_NULL);
HAWK_ASSERT(px->right == HAWK_NULL);
PUT_SRCSTR(hawk, HAWK_T("("));
PRINT_EXPR(hawk, px->left);
@@ -659,14 +659,14 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
hawk_ooch_t tmp[HAWK_SIZEOF(hawk_int_t)*8+2];
hawk_oow_t n;
hawk_nde_var_t* px = (hawk_nde_var_t*)nde;
HAWK_ASSERT (px->id.idxa != (hawk_oow_t)-1);
HAWK_ASSERT(px->id.idxa != (hawk_oow_t)-1);
n = hawk_int_to_oocstr(px->id.idxa, 10, HAWK_NULL, tmp, HAWK_COUNTOF(tmp));
PUT_SRCSTR(hawk, HAWK_T("__p"));
PUT_SRCSTRN(hawk, tmp, n);
HAWK_ASSERT (px->idx == HAWK_NULL);
HAWK_ASSERT(px->idx == HAWK_NULL);
break;
}
@@ -674,8 +674,8 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
{
hawk_oow_t n;
hawk_nde_var_t* px = (hawk_nde_var_t*)nde;
HAWK_ASSERT (px->id.idxa != (hawk_oow_t)-1);
HAWK_ASSERT (px->idx != HAWK_NULL);
HAWK_ASSERT(px->id.idxa != (hawk_oow_t)-1);
HAWK_ASSERT(px->idx != HAWK_NULL);
PUT_SRCSTR(hawk, HAWK_T("__p"));
n = hawk_int_to_oocstr(px->id.idxa, 10, HAWK_NULL, hawk->tmp.fmt, HAWK_COUNTOF(hawk->tmp.fmt));
@@ -687,10 +687,10 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
case HAWK_NDE_NAMED:
{
hawk_nde_var_t* px = (hawk_nde_var_t*)nde;
/*HAWK_ASSERT (px->id.idxa == (hawk_oow_t)-1);
/*HAWK_ASSERT(px->id.idxa == (hawk_oow_t)-1);
* commented out the above assertion because
* id.idxa field holds an index to the rtx->named_slots. */
HAWK_ASSERT (px->idx == HAWK_NULL);
HAWK_ASSERT(px->idx == HAWK_NULL);
PUT_SRCSTRN(hawk, px->id.name.ptr, px->id.name.len);
break;
@@ -699,8 +699,10 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
case HAWK_NDE_NAMEDIDX:
{
hawk_nde_var_t* px = (hawk_nde_var_t*)nde;
HAWK_ASSERT (px->id.idxa == (hawk_oow_t)-1);
HAWK_ASSERT (px->idx != HAWK_NULL);
/*HAWK_ASSERT(px->id.idxa == (hawk_oow_t)-1);
* commented out the above assertion because
* id.idxa field holds an index to the rtx->named_slots. */
HAWK_ASSERT(px->idx != HAWK_NULL);
PUT_SRCSTRN(hawk, px->id.name.ptr, px->id.name.len);
PRINT_EXPR_LIST_FOR_IDX(hawk, px->idx);
@@ -740,7 +742,7 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
{
PUT_SRCSTRN(hawk, px->id.name.ptr, px->id.name.len);
}
HAWK_ASSERT (px->idx == HAWK_NULL);
HAWK_ASSERT(px->idx == HAWK_NULL);
break;
}
@@ -777,7 +779,7 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
{
PUT_SRCSTRN(hawk, px->id.name.ptr, px->id.name.len);
}
HAWK_ASSERT (px->idx != HAWK_NULL);
HAWK_ASSERT(px->idx != HAWK_NULL);
PRINT_EXPR_LIST_FOR_IDX(hawk, px->idx);
break;
}
@@ -798,7 +800,7 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
{
PUT_SRCSTRN(hawk, px->id.name.ptr, px->id.name.len);
}
HAWK_ASSERT (px->idx == HAWK_NULL);
HAWK_ASSERT(px->idx == HAWK_NULL);
break;
}
@@ -817,7 +819,7 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde, int depth)
{
PUT_SRCSTRN(hawk, px->id.name.ptr, px->id.name.len);
}
HAWK_ASSERT (px->idx != HAWK_NULL);
HAWK_ASSERT(px->idx != HAWK_NULL);
PRINT_EXPR_LIST_FOR_IDX(hawk, px->idx);
break;
}
@@ -1027,7 +1029,7 @@ static int print_stmt (hawk_t* hawk, hawk_nde_t* p, int depth, int flags)
PRINT_EXPR(hawk, px->test);
PUT_SRCSTR(hawk, HAWK_T(") "));
HAWK_ASSERT (px->then_part != HAWK_NULL);
HAWK_ASSERT(px->then_part != HAWK_NULL);
xflags = STMT_FLAG_NO_LEAD_INDENT;
if (!px->else_part) xflags |= STMT_FLAG_NO_ENDING_NL;
xdepth = depth + (px->then_part->type != HAWK_NDE_BLK);
@@ -1202,7 +1204,7 @@ static int print_stmt (hawk_t* hawk, hawk_nde_t* p, int depth, int flags)
hawk_getkwname(hawk, HAWK_KWID_RETURN, &kw);
PUT_SRCSTRN(hawk, kw.ptr, kw.len);
PUT_SRCSTR(hawk, HAWK_T(" "));
HAWK_ASSERT (((hawk_nde_return_t*)p)->val->next == HAWK_NULL);
HAWK_ASSERT(((hawk_nde_return_t*)p)->val->next == HAWK_NULL);
PRINT_EXPR(hawk, ((hawk_nde_return_t*)p)->val);
PUT_SRCSTR(hawk, HAWK_T(";"));
@@ -1225,7 +1227,7 @@ static int print_stmt (hawk_t* hawk, hawk_nde_t* p, int depth, int flags)
hawk_getkwname(hawk, (px->abort? HAWK_KWID_XABORT: HAWK_KWID_EXIT), &kw);
PUT_SRCSTRN(hawk, kw.ptr, kw.len);
PUT_SRCSTR(hawk, HAWK_T(" "));
HAWK_ASSERT (px->val->next == HAWK_NULL);
HAWK_ASSERT(px->val->next == HAWK_NULL);
PRINT_EXPR(hawk, px->val);
PUT_SRCSTR(hawk, HAWK_T(";"));
}
@@ -1494,8 +1496,8 @@ void hawk_clrpt (hawk_t* hawk, hawk_nde_t* tree)
case HAWK_NDE_EXP_BIN:
{
hawk_nde_exp_t* px = (hawk_nde_exp_t*)p;
HAWK_ASSERT (px->left->next == HAWK_NULL);
HAWK_ASSERT (px->right->next == HAWK_NULL);
HAWK_ASSERT(px->left->next == HAWK_NULL);
HAWK_ASSERT(px->right->next == HAWK_NULL);
hawk_clrpt(hawk, px->left);
hawk_clrpt(hawk, px->right);
@@ -1508,7 +1510,7 @@ void hawk_clrpt (hawk_t* hawk, hawk_nde_t* tree)
case HAWK_NDE_EXP_INCPST:
{
hawk_nde_exp_t* px = (hawk_nde_exp_t*)p;
HAWK_ASSERT (px->right == HAWK_NULL);
HAWK_ASSERT(px->right == HAWK_NULL);
hawk_clrpt(hawk, px->left);
hawk_freemem(hawk, p);
break;
@@ -1605,7 +1607,7 @@ void hawk_clrpt (hawk_t* hawk, hawk_nde_t* tree)
case HAWK_NDE_ARG:
{
hawk_nde_var_t* px = (hawk_nde_var_t*)p;
HAWK_ASSERT (px->idx == HAWK_NULL);
HAWK_ASSERT(px->idx == HAWK_NULL);
if (px->id.name.ptr) hawk_freemem(hawk, px->id.name.ptr);
hawk_freemem(hawk, p);
break;
@@ -1617,7 +1619,7 @@ void hawk_clrpt (hawk_t* hawk, hawk_nde_t* tree)
case HAWK_NDE_ARGIDX:
{
hawk_nde_var_t* px = (hawk_nde_var_t*)p;
HAWK_ASSERT (px->idx != HAWK_NULL);
HAWK_ASSERT(px->idx != HAWK_NULL);
hawk_clrpt(hawk, px->idx);
if (px->id.name.ptr) hawk_freemem(hawk, px->id.name.ptr);
hawk_freemem(hawk, p);
@@ -1678,7 +1680,7 @@ void hawk_clrpt (hawk_t* hawk, hawk_nde_t* tree)
default:
{
HAWK_ASSERT (!"should never happen - invalid node type");
HAWK_ASSERT(!"should never happen - invalid node type");
hawk_freemem(hawk, p);
break;
}
+21
View File
@@ -215,6 +215,18 @@ void hawk_rtx_freevalchunk (
);
#if defined(HAWK_HAVE_INLINE)
/* the nocheck versions are defined in case you already know the value
* is a pointer and not a static value */
static HAWK_INLINE_ALWAYS void hawk_rtx_refupval_nocheck_inline (hawk_rtx_t* rtx, hawk_val_t* val)
{
#if defined(HAWK_USE_ATOMIC_REFCNT) && defined(HAWK_ATOMIC_FETCH_ADD)
HAWK_ATOMIC_FETCH_ADD(&val->v_refs, 1, HAWK_ATOMIC_RELAXED);
#else
val->v_refs++;
#endif
}
/* regular refup with pointer check */
static HAWK_INLINE_ALWAYS void hawk_rtx_refupval_inline (hawk_rtx_t* rtx, hawk_val_t* val)
{
if (HAWK_VTR_IS_POINTER(val) && !HAWK_IS_STATICVAL(val))
@@ -226,13 +238,22 @@ static HAWK_INLINE_ALWAYS void hawk_rtx_refupval_inline (hawk_rtx_t* rtx, hawk_v
#endif
}
}
#elif defined(HAWK_USE_ATOMIC_REFCNT) && defined(HAWK_ATOMIC_FETCH_ADD)
#define hawk_rtx_refupval_nocheck_inline(rtx, val) do { \
HAWK_ATOMIC_FETCH_ADD(&(val)->v_refs, 1, HAWK_ATOMIC_RELAXED); \
} while(0)
#define hawk_rtx_refupval_inline(rtx, val) do { \
if (HAWK_VTR_IS_POINTER(val) && !HAWK_IS_STATICVAL(val)) { \
HAWK_ATOMIC_FETCH_ADD(&(val)->v_refs, 1, HAWK_ATOMIC_RELAXED); \
} \
} while(0)
#else
#define hawk_rtx_refupval_nocheck_inline(rtx, val) do { (val)->v_refs++; } while(0)
#define hawk_rtx_refupval_inline(rtx, val) do { \
if (HAWK_VTR_IS_POINTER(val) && !HAWK_IS_STATICVAL(val)) (val)->v_refs++; \
} while(0)
+1 -1
View File
@@ -20,7 +20,7 @@ endif
check_SCRIPTS += h-003.hawk h-004.hawk h-009.hawk h-010.hawk \
h-011.hawk h-012.hawk h-013.hawk h-014.hawk h-015.hawk \
h-016.hawk h-017.hawk h-018.hawk h-019.hawk h-020.hawk \
h-021.hawk h-022.hawk h-023.hawk h-024.hawk
h-021.hawk h-022.hawk h-023.hawk h-024.hawk h-025.hawk
check_SCRIPTS += regress-filename.sh regress-extra-info.sh regress-environ.sh
+2 -1
View File
@@ -659,7 +659,8 @@ check_SCRIPTS = $(am__append_1) h-003.hawk h-004.hawk h-009.hawk \
h-010.hawk h-011.hawk h-012.hawk h-013.hawk h-014.hawk \
h-015.hawk h-016.hawk h-017.hawk h-018.hawk h-019.hawk \
h-020.hawk h-021.hawk h-022.hawk h-023.hawk h-024.hawk \
regress-filename.sh regress-extra-info.sh regress-environ.sh
h-025.hawk regress-filename.sh regress-extra-info.sh \
regress-environ.sh
check_ERRORS = e-001.err
EXTRA_DIST = $(check_SCRIPTS) $(check_ERRORS) tap.inc err.sh \
journal-toc.hawk journal-toc.in journal-toc.out journal-toc-html.out \
+574
View File
@@ -0,0 +1,574 @@
## xstack expression evaluator tests
## Covers every eframe state in eval_expression0_xstack:
## HAWK_EF_BIN_LEFT/RIGHT - binary operators
## HAWK_EF_LAND_LEFT/RIGHT - logical && with short-circuit
## HAWK_EF_LOR_LEFT/RIGHT - logical || with short-circuit
## HAWK_EF_UNARY - unary operators
## HAWK_EF_CND - ternary conditional
## HAWK_EF_ASS_RHS - simple assignment
## HAWK_EF_ASS_LHS - compound assignment (read-modify-write)
@pragma entry main
@pragma implicit off
@include "tap.inc";
## -----------------------------------------------------------------------
## binary arithmetic operators
## -----------------------------------------------------------------------
function test_binary_arith( x)
{
tap_ensure(2 + 3, 5, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(10 - 4, 6, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(3 * 7, 21, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(15 / 4, 3.75, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(17 % 5, 2, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(2 ^ 10, 1024, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(17 \ 5, 3, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(-17 \ 5, -3, @SCRIPTNAME, @SCRIPTLINE);
## string concatenation (binary)
tap_ensure("hello" " " "world", "hello world", @SCRIPTNAME, @SCRIPTLINE);
tap_ensure("a" "b" "c", "abc", @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## binary comparison operators
## -----------------------------------------------------------------------
function test_binary_cmp()
{
tap_ensure((3 < 5), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((5 < 3), 0, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((3 <= 3), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((4 <= 3), 0, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((5 > 3), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((3 > 5), 0, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((3 >= 3), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((2 >= 3), 0, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((3 == 3), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((3 == 4), 0, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((3 != 4), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((3 != 3), 0, @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## bitwise binary operators
## -----------------------------------------------------------------------
function test_binary_bitwise()
{
tap_ensure((0xF0 & 0xFF), 240, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((0x0F & 0xFF), 15, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((0xF0 | 0x0F), 255, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((0xFF ^^ 0x0F), 240, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((1 << 4), 16, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((256 >> 3), 32, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((0 << 10), 0, @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## deeply chained binary expressions (stress eframe stack growth)
## The eframe stack starts at 0 and grows 64 at a time; these chains
## push many BIN_LEFT frames before resolving any BIN_RIGHT frames.
## -----------------------------------------------------------------------
function test_binary_chain( x)
{
## left-associative chain (parser produces left-leaning tree)
x = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10;
tap_ensure(x, 55, @SCRIPTNAME, @SCRIPTLINE);
x = 1 * 2 * 3 * 4 * 5;
tap_ensure(x, 120, @SCRIPTNAME, @SCRIPTLINE);
## deeply parenthesised right-associative nesting
x = (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + 10)))))))));
tap_ensure(x, 55, @SCRIPTNAME, @SCRIPTLINE);
## mix of operators
x = 2 * 3 + 4 * 5 - 6 / 2;
tap_ensure(x, 23, @SCRIPTNAME, @SCRIPTLINE);
## 20-term sum (forces eframe realloc path)
x = 1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20;
tap_ensure(x, 210, @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## logical AND -- HAWK_EF_LAND_LEFT / HAWK_EF_LAND_RIGHT
## -----------------------------------------------------------------------
function test_logical_and( r, se)
{
## short-circuit: right never evaluated when left is false
se = 0;
r = 0 && (se = 1);
tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(se, 0, @SCRIPTNAME, @SCRIPTLINE); ## right NOT evaluated
## both sides evaluated when left is true
se = 0;
r = 1 && (se = 99);
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(se, 99, @SCRIPTNAME, @SCRIPTLINE); ## right WAS evaluated
## false right side
r = 1 && 0;
tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE);
## chained AND
r = 1 && 1 && 1;
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
r = 1 && 1 && 0;
tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE);
## AND with complex subexpressions
r = (2 + 3 == 5) && (10 / 2 == 5);
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
r = (2 + 3 == 5) && (10 / 2 == 4);
tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## logical OR -- HAWK_EF_LOR_LEFT / HAWK_EF_LOR_RIGHT
## -----------------------------------------------------------------------
function test_logical_or( r, se)
{
## short-circuit: right never evaluated when left is true
se = 0;
r = 1 || (se = 1);
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(se, 0, @SCRIPTNAME, @SCRIPTLINE); ## right NOT evaluated
## both sides evaluated when left is false
se = 0;
r = 0 || (se = 77);
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(se, 77, @SCRIPTNAME, @SCRIPTLINE); ## right WAS evaluated
## false || false
r = 0 || 0;
tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE);
## chained OR
r = 0 || 0 || 1;
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
r = 0 || 0 || 0;
tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE);
## OR with complex subexpressions
r = (1 == 2) || (3 * 3 == 9);
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
r = (1 == 2) || (2 + 2 == 5);
tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## mixed AND/OR with nested short-circuit
## -----------------------------------------------------------------------
function test_logical_mixed( r, se)
{
r = (1 && 1) || (0 && 1);
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
r = (0 || 0) && (1 || 0);
tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE);
r = (0 || 1) && (1 && 1) && (0 || 1);
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
## right side of AND is never reached because left is short-circuit false
se = 0;
r = (0 && 1) || (se = 5);
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(se, 5, @SCRIPTNAME, @SCRIPTLINE); ## OR's right WAS evaluated
## right side of OR never reached
se = 0;
r = (1 || (se = 3)) && 1;
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(se, 0, @SCRIPTNAME, @SCRIPTLINE); ## OR's right NOT evaluated
}
## -----------------------------------------------------------------------
## unary operators -- HAWK_EF_UNARY
## -----------------------------------------------------------------------
function test_unary( x)
{
x = 5;
tap_ensure(-x, -5, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(+x, 5, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(!x, 0, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(!0, 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(~0, -1, @SCRIPTNAME, @SCRIPTLINE); ## bitwise NOT
## nested unary operators (each adds a UNARY frame)
tap_ensure(-(-x), 5, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(!!x, 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(!!!x, 0, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(~(~0), 0, @SCRIPTNAME, @SCRIPTLINE);
## unary applied to binary subexpression
tap_ensure(-(2 + 3), -5, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(!(3 < 2), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(-(2 * 3), -6, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(~(0xF0 & 0xFF), -241, @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## conditional (ternary) -- HAWK_EF_CND
## -----------------------------------------------------------------------
function test_conditional( a, b, x)
{
a = 10; b = 20;
## basic true/false branch selection
tap_ensure((a < b ? "lt" : "ge"), "lt", @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((a > b ? "gt" : "le"), "le", @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((a == 10 ? a : b), 10, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((a == 99 ? a : b), 20, @SCRIPTNAME, @SCRIPTLINE);
## nested ternary (each level adds a CND frame)
x = (a < b) ? (b < 30 ? "lt30" : "ge30") : "no";
tap_ensure(x, "lt30", @SCRIPTNAME, @SCRIPTLINE);
x = (a > b) ? "no" : (b > 15 ? "gt15" : "le15");
tap_ensure(x, "gt15", @SCRIPTNAME, @SCRIPTLINE);
## ternary with binary expressions in all three positions
x = (a + b == 30) ? (a * b) : (a - b);
tap_ensure(x, 200, @SCRIPTNAME, @SCRIPTLINE);
x = (a + b == 99) ? (a * b) : (a - b);
tap_ensure(x, -10, @SCRIPTNAME, @SCRIPTLINE);
## ternary result used in larger expression
tap_ensure((a < b ? a : b) + (a > b ? a : b), 30, @SCRIPTNAME, @SCRIPTLINE);
## ternary inside AND/OR
tap_ensure((1 && (a < b ? 1 : 0)), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((0 || (a > b ? 1 : 0)), 0, @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## simple assignment -- HAWK_EF_ASS_RHS (opcode == NONE path)
## -----------------------------------------------------------------------
function test_simple_assign( x, y, z)
{
x = 42;
tap_ensure(x, 42, @SCRIPTNAME, @SCRIPTLINE);
## assignment with complex RHS (exercises BIN/UNARY/CND inside ASS_RHS)
x = 3 * 4 + 5;
tap_ensure(x, 17, @SCRIPTNAME, @SCRIPTLINE);
x = (2 < 3 ? 10 : 20) + 5;
tap_ensure(x, 15, @SCRIPTNAME, @SCRIPTLINE);
x = !(1 == 2);
tap_ensure(x, 1, @SCRIPTNAME, @SCRIPTLINE);
## chained assignment (right-to-left: z=7, y=7, x=7)
x = y = z = 7;
tap_ensure(x, 7, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(y, 7, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(z, 7, @SCRIPTNAME, @SCRIPTLINE);
## assignment used as expression in larger context
tap_ensure((x = 5) + 3, 8, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(x, 5, @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## compound assignment -- HAWK_EF_ASS_LHS (opcode != NONE path)
## -----------------------------------------------------------------------
function test_compound_assign( x)
{
x = 10;
x += 5; tap_ensure(x, 15, @SCRIPTNAME, @SCRIPTLINE);
x -= 3; tap_ensure(x, 12, @SCRIPTNAME, @SCRIPTLINE);
x *= 4; tap_ensure(x, 48, @SCRIPTNAME, @SCRIPTLINE);
x /= 6; tap_ensure(x, 8, @SCRIPTNAME, @SCRIPTLINE);
x %= 3; tap_ensure(x, 2, @SCRIPTNAME, @SCRIPTLINE);
x ^= 8; tap_ensure(x, 256, @SCRIPTNAME, @SCRIPTLINE);
x \= 10; tap_ensure(x, 25, @SCRIPTNAME, @SCRIPTLINE);
## compound with complex RHS (BIN evaluator inside ASS_RHS)
x = 5;
x += 2 * 3; tap_ensure(x, 11, @SCRIPTNAME, @SCRIPTLINE);
x = 100;
x -= (3 + 7); tap_ensure(x, 90, @SCRIPTNAME, @SCRIPTLINE);
x = 4;
x *= (1 + 1); tap_ensure(x, 8, @SCRIPTNAME, @SCRIPTLINE);
## bitwise compound assignments
x = 0xFF;
x &= 0x0F; tap_ensure(x, 15, @SCRIPTNAME, @SCRIPTLINE);
x = 0xF0;
x |= 0x0F; tap_ensure(x, 255, @SCRIPTNAME, @SCRIPTLINE);
x = 0xFF;
x ^^= 0x0F; tap_ensure(x, 240, @SCRIPTNAME, @SCRIPTLINE);
x = 1;
x <<= 4; tap_ensure(x, 16, @SCRIPTNAME, @SCRIPTLINE);
x >>= 2; tap_ensure(x, 4, @SCRIPTNAME, @SCRIPTLINE);
## string concatenation compound assignment
x = "hello";
x = x " " "world";
tap_ensure(x, "hello world", @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## function calls with complex argument expressions
## (exercises push_arg_from_nde_xstack for each argument)
## -----------------------------------------------------------------------
function add3(a, b, c) { return a + b + c; }
function mul_add(a, b, c) { return a * b + c; }
function identity(x) { return x; }
function choose(flag, a, b){ return flag ? a : b; }
function noop() { return 0; }
function test_fncall_args( r, tmp)
{
## args are binary expressions
r = add3(1 + 2, 3 * 4, 5 - 1);
tap_ensure(r, 19, @SCRIPTNAME, @SCRIPTLINE); ## 3 + 12 + 4
## arg is a conditional
r = choose(1 > 0, "yes", "no");
tap_ensure(r, "yes", @SCRIPTNAME, @SCRIPTLINE);
r = choose(0 > 1, "yes", "no");
tap_ensure(r, "no", @SCRIPTNAME, @SCRIPTLINE);
## arg is a unary expression
r = identity(-(3 + 4));
tap_ensure(r, -7, @SCRIPTNAME, @SCRIPTLINE);
## arg is itself a function call with complex args
r = identity(add3(1, 2, 3));
tap_ensure(r, 6, @SCRIPTNAME, @SCRIPTLINE);
## arg mixing AND with function call
r = choose(1 && 1, add3(1, 2, 3), 0);
tap_ensure(r, 6, @SCRIPTNAME, @SCRIPTLINE);
r = choose(1 && 0, add3(1, 2, 3), 99);
tap_ensure(r, 99, @SCRIPTNAME, @SCRIPTLINE);
## arg that is an assignment expression (side-effect)
tmp = 0;
r = add3((tmp = 10), tmp + 1, tmp + 2);
tap_ensure(r, 33, @SCRIPTNAME, @SCRIPTLINE); ## 10 + 11 + 12
tap_ensure(tmp, 10, @SCRIPTNAME, @SCRIPTLINE);
## deeply nested call in arg
r = mul_add(add3(1, 1, 1), identity(4), noop() + 2);
tap_ensure(r, 14, @SCRIPTNAME, @SCRIPTLINE); ## 3*4 + 2
}
## -----------------------------------------------------------------------
## recursive user-defined functions
## (each call goes through evalcall/evalcall_xstack)
## -----------------------------------------------------------------------
function fib(n) { return n <= 1 ? n : fib(n - 1) + fib(n - 2); }
function fact(n) { return n <= 1 ? 1 : n * fact(n - 1); }
function sum_to(n) { return n <= 0 ? 0 : n + sum_to(n - 1); }
function ack(m, n)
{
if (m == 0) return n + 1;
if (n == 0) return ack(m - 1, 1);
return ack(m - 1, ack(m, n - 1));
}
function test_recursive()
{
@local r;
tap_ensure(fib(0), 0, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(fib(1), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(fib(10), 55, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(fib(15), 610, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(fact(0), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(fact(1), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(fact(10), 3628800, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(sum_to(0), 0, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(sum_to(100), 5050, @SCRIPTNAME, @SCRIPTLINE);
## Ackermann: moderate values to avoid stack overflow
tap_ensure(ack(0, 0), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(ack(1, 1), 3, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(ack(2, 2), 7, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(ack(3, 3), 61, @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## deeply nested mixed expressions
## (combines BIN, UNARY, CND, ASS — many eframe levels at once)
## -----------------------------------------------------------------------
function test_deep_mixed()
{
@local t, a, b, c, x;
a = 3; b = 4; c = 5;
## Pythagorean triple check
x = (a*a + b*b == c*c) ? "right" : "wrong";
tap_ensure(x, "right", @SCRIPTNAME, @SCRIPTLINE);
## deeply nested: binary inside conditional inside assignment
x = (a < b) ? (b < c ? a + b + c : a * b) : (a - b) * c;
tap_ensure(x, 12, @SCRIPTNAME, @SCRIPTLINE); ## a+b+c = 12
## right-associated depth 10
x = (1+(2+(3+(4+(5+(6+(7+(8+(9+10)))))))));
tap_ensure(x, 55, @SCRIPTNAME, @SCRIPTLINE);
## logical chains mixed with arithmetic
x = (a > 0 && b > 0 && c > 0) ? a * b * c : 0;
tap_ensure(x, 60, @SCRIPTNAME, @SCRIPTLINE);
## unary inside conditional inside AND
x = (!(a > b)) && (-(a - b) > 0);
tap_ensure(x, 1, @SCRIPTNAME, @SCRIPTLINE); ## !(3>4)=1, -(3-4)=1 > 0
## assignment inside binary
x = (t = a + b) * (t - a);
tap_ensure(x, 28, @SCRIPTNAME, @SCRIPTLINE); ## t=7, 7*4=28
tap_ensure(t, 7, @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## in operator (delegated to eval_binop_in, not iterative)
## Verify the default-case delegation path in eval_expression0_xstack.
## -----------------------------------------------------------------------
function test_in_operator()
{
@local m, r;
m["x"] = 1; m["y"] = 2;
tap_ensure(("x" in m), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(("z" in m), 0, @SCRIPTNAME, @SCRIPTLINE);
## 'in' inside AND/OR (both iterative and delegated evaluators)
tap_ensure((("x" in m) && ("y" in m)), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((("x" in m) && ("z" in m)), 0, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure((("z" in m) || ("x" in m)), 1, @SCRIPTNAME, @SCRIPTLINE);
## 'in' inside conditional
r = ("x" in m) ? m["x"] : -1;
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
r = ("z" in m) ? m["z"] : -1;
tap_ensure(r, -1, @SCRIPTNAME, @SCRIPTLINE);
## 'in' inside unary
tap_ensure(!("z" in m), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(!("x" in m), 0, @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## pre/post increment and decrement
## (delegated to original eval_expression0 via default: branch)
## -----------------------------------------------------------------------
function test_incr_decr( x, r)
{
x = 5;
r = ++x; tap_ensure(r, 6, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(x, 6, @SCRIPTNAME, @SCRIPTLINE);
r = x++; tap_ensure(r, 6, @SCRIPTNAME, @SCRIPTLINE); ## returns old value
tap_ensure(x, 7, @SCRIPTNAME, @SCRIPTLINE);
r = --x; tap_ensure(r, 6, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(x, 6, @SCRIPTNAME, @SCRIPTLINE);
r = x--; tap_ensure(r, 6, @SCRIPTNAME, @SCRIPTLINE); ## returns old value
tap_ensure(x, 5, @SCRIPTNAME, @SCRIPTLINE);
## incr/decr result used in binary expression
x = 10;
r = (++x) + (++x);
tap_ensure(r, 23, @SCRIPTNAME, @SCRIPTLINE); ## 11 + 12
tap_ensure(x, 12, @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## positional variable ($n) — delegated path
## -----------------------------------------------------------------------
function test_positional()
{
@local r;
$1 = "hello";
$2 = "world";
r = $1 " " $2;
tap_ensure(r, "hello world", @SCRIPTNAME, @SCRIPTLINE);
## positional in conditional (force numeric comparison with +0)
$1 = 10;
r = ($1 + 0 > 5 ? $1 * 2 : $1 / 2);
tap_ensure(r, 20, @SCRIPTNAME, @SCRIPTLINE);
## positional in compound assignment
$1 = 3;
$1 += 7;
tap_ensure($1, 10, @SCRIPTNAME, @SCRIPTLINE);
}
## -----------------------------------------------------------------------
## match/no-match operators (delegated to eval_binop_ma / eval_binop_nm)
## -----------------------------------------------------------------------
function test_match_ops()
{
@local r;
r = ("hello" ~ /ell/);
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
r = ("hello" ~ /xyz/);
tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE);
r = ("hello" !~ /xyz/);
tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE);
r = ("hello" !~ /ell/);
tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE);
## match result in AND/OR
tap_ensure(("abc" ~ /a/) && ("xyz" ~ /x/), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(("abc" ~ /z/) || ("xyz" ~ /x/), 1, @SCRIPTNAME, @SCRIPTLINE);
## match result in conditional
r = ("hawk" ~ /awk/) ? "yes" : "no";
tap_ensure(r, "yes", @SCRIPTNAME, @SCRIPTLINE);
}
function main()
{
test_binary_arith();
test_binary_cmp();
test_binary_bitwise();
test_binary_chain();
test_logical_and();
test_logical_or();
test_logical_mixed();
test_unary();
test_conditional();
test_simple_assign();
test_compound_assign();
test_fncall_args();
test_recursive();
test_deep_mixed();
test_in_operator();
test_incr_decr();
test_positional();
test_match_ops();
tap_end();
}