changed the behavior of for(x in y) loop - it now takes a snapshot of keys before running body

This commit is contained in:
hyung-hwan 2020-03-22 18:01:05 +00:00
parent 66d461e664
commit 6502a2e388
11 changed files with 279 additions and 80 deletions

View File

@ -45,7 +45,7 @@
#endif #endif
/// \file /// \file
/// AWK Interpreter /// Hawk Interpreter
///////////////////////////////// /////////////////////////////////
HAWK_BEGIN_NAMESPACE(HAWK) HAWK_BEGIN_NAMESPACE(HAWK)

View File

@ -30,7 +30,7 @@
#include <Hawk.hpp> #include <Hawk.hpp>
/// \file /// \file
/// Standard AWK Interpreter /// Standard Hawk Interpreter
///////////////////////////////// /////////////////////////////////
HAWK_BEGIN_NAMESPACE(HAWK) HAWK_BEGIN_NAMESPACE(HAWK)

View File

@ -491,6 +491,13 @@ struct hawk_rtx_t
hawk_oow_t expr; /* expression */ hawk_oow_t expr; /* expression */
} depth; } depth;
struct
{
hawk_val_t** ptr;
hawk_oow_t size;
hawk_oow_t capa;
} forin; /* keys for for (x in y) ... */
hawk_oow_t errmsg_len; /* used by errbfmt() and errufmt(). don't rely on this. some other funtions don't set this properly */ hawk_oow_t errmsg_len; /* used by errbfmt() and errufmt(). don't rely on this. some other funtions don't set this properly */
hawk_ooch_t errmsg_backup[HAWK_ERRMSG_CAPA]; hawk_ooch_t errmsg_backup[HAWK_ERRMSG_CAPA];
#if defined(HAWK_OOCH_IS_BCH) #if defined(HAWK_OOCH_IS_BCH)

View File

@ -230,6 +230,21 @@ enum hawk_rbt_style_kind_t
typedef enum hawk_rbt_style_kind_t hawk_rbt_style_kind_t; typedef enum hawk_rbt_style_kind_t hawk_rbt_style_kind_t;
typedef struct hawk_rbt_itr_t hawk_rbt_itr_t;
struct hawk_rbt_itr_t
{
hawk_rbt_pair_t* pair;
hawk_rbt_pair_t* _prev;
unsigned int _dir: 1; /* 0 or 1 */
unsigned int _state: 8;
#if defined(HAWK_ENABLE_RBT_ITR_PROTECTION)
unsigned int _prot_updated: 1;
hawk_oow_t _prot_seqno;
hawk_rbt_itr_t* _prot_prev;
hawk_rbt_itr_t* _prot_next;
#endif
};
/** /**
* The hawk_rbt_t type defines a red-black tree. * The hawk_rbt_t type defines a red-black tree.
*/ */
@ -241,19 +256,11 @@ struct hawk_rbt_t
hawk_rbt_pair_t xnil; /**< internal nil node */ hawk_rbt_pair_t xnil; /**< internal nil node */
hawk_oow_t size; /**< number of pairs */ hawk_oow_t size; /**< number of pairs */
hawk_rbt_pair_t* root; /**< root pair */ hawk_rbt_pair_t* root; /**< root pair */
#if defined(HAWK_ENABLE_RBT_ITR_PROTECTION)
hawk_rbt_itr_t _prot_itr; /**< protected iterators */
#endif
}; };
struct hawk_rbt_itr_t
{
hawk_rbt_pair_t* pair;
hawk_rbt_pair_t* _prev;
int _dir; /* 0 or 1 */
int _state;
};
typedef struct hawk_rbt_itr_t hawk_rbt_itr_t;
/** /**
* The HAWK_RBT_COPIER_SIMPLE macros defines a copier that remembers the * The HAWK_RBT_COPIER_SIMPLE macros defines a copier that remembers the
* pointer and length of data in a pair. * pointer and length of data in a pair.
@ -564,6 +571,18 @@ HAWK_EXPORT hawk_rbt_pair_t* hawk_rbt_getnextpair (
hawk_rbt_itr_t* itr hawk_rbt_itr_t* itr
); );
#if defined(HAWK_ENABLE_RBT_ITR_PROTECTION)
HAWK_EXPORT void hawk_rbt_protectitr (
hawk_rbt_t* rbt,
hawk_rbt_itr_t* itr
);
HAWK_EXPORT void hawk_rbt_unprotectitr (
hawk_rbt_t* rbt,
hawk_rbt_itr_t* itr
);
#endif
/** /**
* The hawk_rbt_walk() function traverses a red-black tree in preorder * The hawk_rbt_walk() function traverses a red-black tree in preorder
* from the leftmost child. * from the leftmost child.

View File

@ -373,7 +373,7 @@ enum hawk_nde_type_t
HAWK_NDE_WHILE, HAWK_NDE_WHILE,
HAWK_NDE_DOWHILE, HAWK_NDE_DOWHILE,
HAWK_NDE_FOR, HAWK_NDE_FOR,
HAWK_NDE_FOREACH, HAWK_NDE_FORIN,
HAWK_NDE_BREAK, HAWK_NDE_BREAK,
HAWK_NDE_CONTINUE, HAWK_NDE_CONTINUE,
HAWK_NDE_RETURN, HAWK_NDE_RETURN,

View File

@ -2613,7 +2613,7 @@ static hawk_nde_t* parse_for (hawk_t* awk, const hawk_loc_t* xloc)
hawk_nde_t* init = HAWK_NULL, * test = HAWK_NULL; hawk_nde_t* init = HAWK_NULL, * test = HAWK_NULL;
hawk_nde_t* incr = HAWK_NULL, * body = HAWK_NULL; hawk_nde_t* incr = HAWK_NULL, * body = HAWK_NULL;
hawk_nde_for_t* nde_for; hawk_nde_for_t* nde_for;
hawk_nde_foreach_t* nde_foreach; hawk_nde_forin_t* nde_forin;
hawk_loc_t ploc; hawk_loc_t ploc;
if (!MATCH(awk,TOK_LPAREN)) if (!MATCH(awk,TOK_LPAREN))
@ -2628,17 +2628,17 @@ static hawk_nde_t* parse_for (hawk_t* awk, const hawk_loc_t* xloc)
/* this line is very ugly. it checks the entire next /* this line is very ugly. it checks the entire next
* expression or the first element in the expression * expression or the first element in the expression
* is wrapped by a parenthesis */ * is wrapped by a parenthesis */
int no_foreach = MATCH(awk,TOK_LPAREN); int no_forin = MATCH(awk,TOK_LPAREN);
ploc = awk->tok.loc; ploc = awk->tok.loc;
init = parse_expr_withdc (awk, &ploc); init = parse_expr_withdc (awk, &ploc);
if (init == HAWK_NULL) goto oops; if (init == HAWK_NULL) goto oops;
if (!no_foreach && init->type == HAWK_NDE_EXP_BIN && if (!no_forin && init->type == HAWK_NDE_EXP_BIN &&
((hawk_nde_exp_t*)init)->opcode == HAWK_BINOP_IN && ((hawk_nde_exp_t*)init)->opcode == HAWK_BINOP_IN &&
is_plain_var(((hawk_nde_exp_t*)init)->left)) is_plain_var(((hawk_nde_exp_t*)init)->left))
{ {
/* switch to foreach - for (x in y) */ /* switch to forin - for (x in y) */
if (!MATCH(awk,TOK_RPAREN)) if (!MATCH(awk,TOK_RPAREN))
{ {
@ -2652,20 +2652,20 @@ static hawk_nde_t* parse_for (hawk_t* awk, const hawk_loc_t* xloc)
body = parse_statement (awk, &ploc); body = parse_statement (awk, &ploc);
if (body == HAWK_NULL) goto oops; if (body == HAWK_NULL) goto oops;
nde_foreach = (hawk_nde_foreach_t*) hawk_callocmem ( nde_forin = (hawk_nde_forin_t*) hawk_callocmem (
awk, HAWK_SIZEOF(*nde_foreach)); awk, HAWK_SIZEOF(*nde_forin));
if (nde_foreach == HAWK_NULL) if (nde_forin == HAWK_NULL)
{ {
ADJERR_LOC (awk, xloc); ADJERR_LOC (awk, xloc);
goto oops; goto oops;
} }
nde_foreach->type = HAWK_NDE_FOREACH; nde_forin->type = HAWK_NDE_FORIN;
nde_foreach->loc = *xloc; nde_forin->loc = *xloc;
nde_foreach->test = init; nde_forin->test = init;
nde_foreach->body = body; nde_forin->body = body;
return (hawk_nde_t*)nde_foreach; return (hawk_nde_t*)nde_forin;
} }
if (!MATCH(awk,TOK_SEMICOLON)) if (!MATCH(awk,TOK_SEMICOLON))

View File

@ -235,6 +235,11 @@ int hawk_rbt_init (hawk_rbt_t* rbt, hawk_gem_t* gem, int kscale, int vscale)
/* root is set to nil initially */ /* root is set to nil initially */
rbt->root = &rbt->xnil; rbt->root = &rbt->xnil;
#if defined(HAWK_ENABLE_RBT_ITR_PROTECTION)
rbt->_prot_itr._prot_next = &rbt->_prot_itr;
rbt->_prot_itr._prot_prev = &rbt->_prot_itr;
#endif
return 0; return 0;
} }
@ -408,8 +413,7 @@ static void adjust (hawk_rbt_t* rbt, hawk_rbt_pair_t* pair)
} }
} }
static hawk_rbt_pair_t* change_pair_val ( static hawk_rbt_pair_t* change_pair_val (hawk_rbt_t* rbt, hawk_rbt_pair_t* pair, void* vptr, hawk_oow_t vlen)
hawk_rbt_t* rbt, hawk_rbt_pair_t* pair, void* vptr, hawk_oow_t vlen)
{ {
if (VPTR(pair) == vptr && VLEN(pair) == vlen) if (VPTR(pair) == vptr && VLEN(pair) == vlen)
{ {
@ -769,7 +773,7 @@ static void adjust_for_delete (hawk_rbt_t* rbt, hawk_rbt_pair_t* pair, hawk_rbt_
static void delete_pair (hawk_rbt_t* rbt, hawk_rbt_pair_t* pair) static void delete_pair (hawk_rbt_t* rbt, hawk_rbt_pair_t* pair)
{ {
hawk_rbt_pair_t* x, * y, * par; hawk_rbt_pair_t* x, * y, * parent;
HAWK_ASSERT (pair && !IS_NIL(rbt,pair)); HAWK_ASSERT (pair && !IS_NIL(rbt,pair));
@ -786,15 +790,15 @@ static void delete_pair (hawk_rbt_t* rbt, hawk_rbt_pair_t* pair)
x = IS_NIL(rbt,y->left)? y->right: y->left; x = IS_NIL(rbt,y->left)? y->right: y->left;
par = y->parent; parent = y->parent;
if (!IS_NIL(rbt,x)) x->parent = par; if (!IS_NIL(rbt,x)) x->parent = parent;
if (par) if (parent)
{ {
if (y == par->left) if (y == parent->left)
par->left = x; parent->left = x;
else else
par->right = x; parent->right = x;
} }
else else
{ {
@ -804,16 +808,15 @@ static void delete_pair (hawk_rbt_t* rbt, hawk_rbt_pair_t* pair)
if (y == pair) if (y == pair)
{ {
if (y->color == HAWK_RBT_BLACK && !IS_NIL(rbt,x)) if (y->color == HAWK_RBT_BLACK && !IS_NIL(rbt,x))
adjust_for_delete (rbt, x, par); adjust_for_delete (rbt, x, parent);
hawk_rbt_freepair (rbt, y); hawk_rbt_freepair (rbt, y);
} }
else else
{ {
if (y->color == HAWK_RBT_BLACK && !IS_NIL(rbt,x)) if (y->color == HAWK_RBT_BLACK && !IS_NIL(rbt,x))
adjust_for_delete (rbt, x, par); adjust_for_delete (rbt, x, parent);
#if 1
if (pair->parent) if (pair->parent)
{ {
if (pair->parent->left == pair) pair->parent->left = y; if (pair->parent->left == pair) pair->parent->left = y;
@ -831,34 +834,48 @@ static void delete_pair (hawk_rbt_t* rbt, hawk_rbt_pair_t* pair)
if (pair->left->parent == pair) pair->left->parent = y; if (pair->left->parent == pair) pair->left->parent = y;
if (pair->right->parent == pair) pair->right->parent = y; if (pair->right->parent == pair) pair->right->parent = y;
#else
*y = *pair;
if (y->parent)
{
if (y->parent->left == pair) y->parent->left = y;
if (y->parent->right == pair) y->parent->right = y;
}
else
{
rbt->root = y;
}
if (y->left->parent == pair) y->left->parent = y;
if (y->right->parent == pair) y->right->parent = y;
#endif
hawk_rbt_freepair (rbt, pair); hawk_rbt_freepair (rbt, pair);
} }
rbt->size--; rbt->size--;
#if defined(HAWK_ENABLE_RBT_ITR_PROTECTION)
/* an iterator set by hawk_rbt_getfirstpair() or hawk_rbt_getnextpair(), if deleted, gets invalidated.
* this protection updates registered iterators to the next valid pair if they gets deleted.
* the caller may reuse the iterator if _prot_updated is set to a non-zero value */
if (rbt->_prot_itr._prot_next != &rbt->_prot_itr)
{
/* there are protected iterators */
hawk_rbt_itr_t* itr = rbt->_prot_itr._prot_next;
do
{
if (itr->pair == pair)
{
hawk_oow_t seqno = itr->_prot_seqno;
/* TODO: this is slow. devise a way to get the next pair safely without traversal */
hawk_rbt_getfirstpair (rbt, itr);
while (itr->pair && itr->_prot_seqno < seqno)
{
hawk_rbt_getnextpair (rbt, itr);
}
itr->_prot_updated = 1;
}
itr = itr->_prot_next;
}
while (itr != &rbt->_prot_itr);
}
#endif
} }
int hawk_rbt_delete (hawk_rbt_t* rbt, const void* kptr, hawk_oow_t klen) int hawk_rbt_delete (hawk_rbt_t* rbt, const void* kptr, hawk_oow_t klen)
{ {
hawk_rbt_pair_t* pair; hawk_rbt_pair_t* pair;
pair = hawk_rbt_search (rbt, kptr, klen); pair = hawk_rbt_search(rbt, kptr, klen);
if (pair == HAWK_NULL) return -1; if (!pair) return -1;
delete_pair (rbt, pair); delete_pair (rbt, pair);
return 0; return 0;
@ -900,7 +917,6 @@ void hawk_init_rbt_itr (hawk_rbt_itr_t* itr, int dir)
itr->_state = 0; itr->_state = 0;
} }
static hawk_rbt_pair_t* get_next_pair (hawk_rbt_t* rbt, hawk_rbt_itr_t* itr) static hawk_rbt_pair_t* get_next_pair (hawk_rbt_t* rbt, hawk_rbt_itr_t* itr)
{ {
hawk_rbt_pair_t* x_cur = itr->pair; hawk_rbt_pair_t* x_cur = itr->pair;
@ -929,7 +945,10 @@ static hawk_rbt_pair_t* get_next_pair (hawk_rbt_t* rbt, hawk_rbt_itr_t* itr)
itr->pair = x_cur; itr->pair = x_cur;
itr->_prev = prev; itr->_prev = prev;
itr->_state = 1; itr->_state = 1;
return x_cur; #if defined(HAWK_ENABLE_RBT_ITR_PROTECTION)
itr->_prot_seqno++;
#endif
return x_cur;
resume_1: resume_1:
if (!IS_NIL(rbt,x_cur->child[r])) if (!IS_NIL(rbt,x_cur->child[r]))
@ -954,6 +973,9 @@ static hawk_rbt_pair_t* get_next_pair (hawk_rbt_t* rbt, hawk_rbt_itr_t* itr)
itr->pair = x_cur; itr->pair = x_cur;
itr->_prev = prev; itr->_prev = prev;
itr->_state = 2; itr->_state = 2;
#if defined(HAWK_ENABLE_RBT_ITR_PROTECTION)
itr->_prot_seqno++;
#endif
return x_cur; return x_cur;
resume_2: resume_2:
@ -980,6 +1002,9 @@ static hawk_rbt_pair_t* get_next_pair (hawk_rbt_t* rbt, hawk_rbt_itr_t* itr)
} }
} }
itr->pair = HAWK_NULL;
itr->_prev = HAWK_NULL;
itr->_state = 0;
return HAWK_NULL; return HAWK_NULL;
} }
@ -988,6 +1013,12 @@ hawk_rbt_pair_t* hawk_rbt_getfirstpair (hawk_rbt_t* rbt, hawk_rbt_itr_t* itr)
itr->pair = rbt->root; itr->pair = rbt->root;
itr->_prev = rbt->root->parent; itr->_prev = rbt->root->parent;
itr->_state = 0; itr->_state = 0;
#if defined(HAWK_ENABLE_RBT_ITR_PROTECTION)
itr->_prot_seqno = 0;
/* _prot_prev and _prot_next must be left uninitialized because of the way
* this function is called in delete_pair() for protection handling
*/
#endif
return get_next_pair(rbt, itr); return get_next_pair(rbt, itr);
} }
@ -996,12 +1027,28 @@ hawk_rbt_pair_t* hawk_rbt_getnextpair (hawk_rbt_t* rbt, hawk_rbt_itr_t* itr)
return get_next_pair(rbt, itr); return get_next_pair(rbt, itr);
} }
#if defined(HAWK_ENABLE_RBT_ITR_PROTECTION)
void hawk_rbt_protectitr (hawk_rbt_t* rbt, hawk_rbt_itr_t* itr)
{
itr->_prot_next = &rbt->_prot_itr;
itr->_prot_prev = rbt->_prot_itr._prot_prev;
itr->_prot_prev->_prot_next = itr;
rbt->_prot_itr._prot_prev = itr;
}
void hawk_rbt_unprotectitr (hawk_rbt_t* rbt, hawk_rbt_itr_t* itr)
{
itr->_prot_prev->_prot_next = itr->_prot_next;
itr->_prot_next->_prot_prev = itr->_prot_prev;
}
#endif
void hawk_rbt_walk (hawk_rbt_t* rbt, walker_t walker, void* ctx) void hawk_rbt_walk (hawk_rbt_t* rbt, walker_t walker, void* ctx)
{ {
hawk_rbt_itr_t itr; hawk_rbt_itr_t itr;
hawk_rbt_pair_t* pair; hawk_rbt_pair_t* pair;
itr._dir = 0; hawk_init_map_itr (&itr, 0);
pair = hawk_rbt_getfirstpair(rbt, &itr); pair = hawk_rbt_getfirstpair(rbt, &itr);
while (pair) while (pair)
{ {
@ -1015,7 +1062,7 @@ void hawk_rbt_rwalk (hawk_rbt_t* rbt, walker_t walker, void* ctx)
hawk_rbt_itr_t itr; hawk_rbt_itr_t itr;
hawk_rbt_pair_t* pair; hawk_rbt_pair_t* pair;
itr._dir = 1; hawk_init_map_itr (&itr, 1);
pair = hawk_rbt_getfirstpair(rbt, &itr); pair = hawk_rbt_getfirstpair(rbt, &itr);
while (pair) while (pair)
{ {

View File

@ -104,7 +104,7 @@ 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_if (hawk_rtx_t* rtx, hawk_nde_if_t* nde);
static int run_while (hawk_rtx_t* rtx, hawk_nde_while_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_for (hawk_rtx_t* rtx, hawk_nde_for_t* nde);
static int run_foreach (hawk_rtx_t* rtx, hawk_nde_foreach_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_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_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_return (hawk_rtx_t* rtx, hawk_nde_return_t* nde);
@ -1136,6 +1136,17 @@ oops_0:
static void fini_rtx (hawk_rtx_t* rtx, int fini_globals) 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) if (rtx->pattern_range_state)
hawk_rtx_freemem (rtx, rtx->pattern_range_state); hawk_rtx_freemem (rtx, rtx->pattern_range_state);
@ -1273,7 +1284,7 @@ static void fini_rtx (hawk_rtx_t* rtx, int fini_globals)
{ {
while (rtx->mbs_cache_count[i] > 0) while (rtx->mbs_cache_count[i] > 0)
{ {
hawk_val_str_t* t = rtx->mbs_cache[i][--rtx->mbs_cache_count[i]]; hawk_val_mbs_t* t = rtx->mbs_cache[i][--rtx->mbs_cache_count[i]];
hawk_rtx_freeval (rtx, (hawk_val_t*)t, 0); hawk_rtx_freeval (rtx, (hawk_val_t*)t, 0);
} }
} }
@ -2154,7 +2165,7 @@ static HAWK_INLINE int run_block0 (hawk_rtx_t* rtx, hawk_nde_blk_t* nde)
while (nlcls > 0) while (nlcls > 0)
{ {
--nlcls; --nlcls;
hawk_rtx_refdownval (rtx, RTX_STACK_LCL(rtx,nlcls)); hawk_rtx_refdownval (rtx, RTX_STACK_LCL(rtx, nlcls));
__raw_pop (rtx); __raw_pop (rtx);
} }
@ -2217,8 +2228,8 @@ static int run_statement (hawk_rtx_t* rtx, hawk_nde_t* nde)
xret = run_for(rtx, (hawk_nde_for_t*)nde); xret = run_for(rtx, (hawk_nde_for_t*)nde);
break; break;
case HAWK_NDE_FOREACH: case HAWK_NDE_FORIN:
xret = run_foreach(rtx, (hawk_nde_foreach_t*)nde); xret = run_forin(rtx, (hawk_nde_forin_t*)nde);
break; break;
case HAWK_NDE_BREAK: case HAWK_NDE_BREAK:
@ -2476,15 +2487,17 @@ static int run_for (hawk_rtx_t* rtx, hawk_nde_for_t* nde)
return 0; return 0;
} }
static int run_foreach (hawk_rtx_t* rtx, hawk_nde_foreach_t* nde) static int run_forin (hawk_rtx_t* rtx, hawk_nde_forin_t* nde)
{ {
hawk_nde_exp_t* test; hawk_nde_exp_t* test;
hawk_val_t* rv; hawk_val_t* rv;
hawk_map_t* map; hawk_map_t* map = HAWK_NULL;
hawk_map_pair_t* pair; hawk_map_pair_t* pair;
hawk_map_itr_t itr; hawk_map_itr_t itr;
hawk_val_type_t rvtype; hawk_val_type_t rvtype;
hawk_oow_t old_forin_size, i;
int ret; int ret;
test = (hawk_nde_exp_t*)nde->test; test = (hawk_nde_exp_t*)nde->test;
HAWK_ASSERT (test->type == HAWK_NDE_EXP_BIN && test->opcode == HAWK_BINOP_IN); HAWK_ASSERT (test->type == HAWK_NDE_EXP_BIN && test->opcode == HAWK_BINOP_IN);
@ -2514,12 +2527,94 @@ static int run_foreach (hawk_rtx_t* rtx, hawk_nde_foreach_t* nde)
map = ((hawk_val_map_t*)rv)->map; map = ((hawk_val_map_t*)rv)->map;
#if 1
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 done;
}
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); hawk_init_map_itr (&itr, 0);
pair = hawk_map_getfirstpair(map, &itr); pair = hawk_map_getfirstpair(map, &itr);
while (pair) while (pair)
{ {
hawk_val_t* str; 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 done;
}
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 done;
}
if (rtx->exit_level == EXIT_BREAK)
{
rtx->exit_level = EXIT_NONE;
goto done;
}
else if (rtx->exit_level == EXIT_CONTINUE)
{
rtx->exit_level = EXIT_NONE;
}
else if (rtx->exit_level != EXIT_NONE)
{
goto done;
}
}
done:
while (rtx->forin.size > old_forin_size)
hawk_rtx_refdownval (rtx, rtx->forin.ptr[--rtx->forin.size]);
hawk_rtx_refdownval (rtx, rv);
return ret;
#else
hawk_init_map_itr (&itr, 0);
#if defined(HAWK_MAP_IS_RBT)
hawk_rbt_protectitr (map, &itr);
#endif
pair = hawk_map_getfirstpair(map, &itr);
while (pair)
{
hawk_val_t* str;
#if defined(HAWK_MAP_IS_RBT)
itr._prot_updated = 0;
#endif
str = (hawk_val_t*)hawk_rtx_makestrvalwithoochars(rtx, HAWK_HTB_KPTR(pair), HAWK_HTB_KLEN(pair)); str = (hawk_val_t*)hawk_rtx_makestrvalwithoochars(rtx, HAWK_HTB_KPTR(pair), HAWK_HTB_KLEN(pair));
if (HAWK_UNLIKELY(!str)) if (HAWK_UNLIKELY(!str))
{ {
@ -2529,7 +2624,7 @@ static int run_foreach (hawk_rtx_t* rtx, hawk_nde_foreach_t* nde)
} }
hawk_rtx_refupval (rtx, str); hawk_rtx_refupval (rtx, str);
if (!do_assignment(rtx, test->left, str) || run_statement(rtx, nde->body) <= -1) if (HAWK_UNLIKELY(!do_assignment(rtx, test->left, str)) || HAWK_UNLIKELY(run_statement(rtx, nde->body) <= -1))
{ {
hawk_rtx_refdownval (rtx, str); hawk_rtx_refdownval (rtx, str);
ret = -1; ret = -1;
@ -2551,12 +2646,20 @@ static int run_foreach (hawk_rtx_t* rtx, hawk_nde_foreach_t* nde)
goto done; goto done;
} }
pair = hawk_map_getnextpair(map, &itr); #if defined(HAWK_MAP_IS_RBT)
pair = itr._prot_updated? itr.pair: hawk_map_getnextpair(map, &itr);
#else
# error UNSUPPORTED
#endif
} }
done: done:
#if defined(HAWK_MAP_IS_RBT)
if (map) hawk_rbt_unprotectitr (map, &itr);
#endif
hawk_rtx_refdownval (rtx, rv); hawk_rtx_refdownval (rtx, rv);
return ret; return ret;
#endif
} }
static int run_break (hawk_rtx_t* run, hawk_nde_break_t* nde) static int run_break (hawk_rtx_t* run, hawk_nde_break_t* nde)

View File

@ -71,7 +71,7 @@ typedef struct hawk_nde_getline_t hawk_nde_getline_t;
typedef struct hawk_nde_if_t hawk_nde_if_t; typedef struct hawk_nde_if_t hawk_nde_if_t;
typedef struct hawk_nde_while_t hawk_nde_while_t; typedef struct hawk_nde_while_t hawk_nde_while_t;
typedef struct hawk_nde_for_t hawk_nde_for_t; typedef struct hawk_nde_for_t hawk_nde_for_t;
typedef struct hawk_nde_foreach_t hawk_nde_foreach_t; typedef struct hawk_nde_forin_t hawk_nde_forin_t;
typedef struct hawk_nde_break_t hawk_nde_break_t; typedef struct hawk_nde_break_t hawk_nde_break_t;
typedef struct hawk_nde_continue_t hawk_nde_continue_t; typedef struct hawk_nde_continue_t hawk_nde_continue_t;
typedef struct hawk_nde_return_t hawk_nde_return_t; typedef struct hawk_nde_return_t hawk_nde_return_t;
@ -263,8 +263,8 @@ struct hawk_nde_for_t
hawk_nde_t* body; hawk_nde_t* body;
}; };
/* HAWK_NDE_FOREACH */ /* HAWK_NDE_FORIN */
struct hawk_nde_foreach_t struct hawk_nde_forin_t
{ {
HAWK_NDE_HDR; HAWK_NDE_HDR;
hawk_nde_t* test; hawk_nde_t* test;

View File

@ -955,9 +955,9 @@ static int print_stmt (hawk_t* awk, hawk_nde_t* p, int depth)
break; break;
} }
case HAWK_NDE_FOREACH: case HAWK_NDE_FORIN:
{ {
hawk_nde_foreach_t* px = (hawk_nde_foreach_t*)p; hawk_nde_forin_t* px = (hawk_nde_forin_t*)p;
PRINT_TABS (awk, depth); PRINT_TABS (awk, depth);
hawk_getkwname (awk, HAWK_KWID_FOR, &kw); hawk_getkwname (awk, HAWK_KWID_FOR, &kw);
@ -1209,10 +1209,10 @@ void hawk_clrpt (hawk_t* awk, hawk_nde_t* tree)
break; break;
} }
case HAWK_NDE_FOREACH: case HAWK_NDE_FORIN:
{ {
hawk_clrpt (awk, ((hawk_nde_foreach_t*)p)->test); hawk_clrpt (awk, ((hawk_nde_forin_t*)p)->test);
hawk_clrpt (awk, ((hawk_nde_foreach_t*)p)->body); hawk_clrpt (awk, ((hawk_nde_forin_t*)p)->body);
hawk_freemem (awk, p); hawk_freemem (awk, p);
break; break;
} }

View File

@ -127,7 +127,7 @@ static void gc_trace_refs (hawk_gch_t* list)
/* as of now, there is only one type available - HAWK_VAL_MAP */ /* as of now, there is only one type available - HAWK_VAL_MAP */
HAWK_ASSERT (v->v_type == HAWK_VAL_MAP); HAWK_ASSERT (v->v_type == HAWK_VAL_MAP);
itr._dir = 0; hawk_init_map_itr (&itr, 0);
pair = hawk_map_getfirstpair(((hawk_val_map_t*)v)->map, &itr); pair = hawk_map_getfirstpair(((hawk_val_map_t*)v)->map, &itr);
while (pair) while (pair)
{ {
@ -184,7 +184,7 @@ static void gc_move_reachables (hawk_gch_t* list, hawk_gch_t* reachable_list)
/* as of now, there is only one type available - HAWK_VAL_MAP */ /* as of now, there is only one type available - HAWK_VAL_MAP */
/* the key part is a string. don't care. but if a generic value is allowed as a key, this should change... */ /* the key part is a string. don't care. but if a generic value is allowed as a key, this should change... */
HAWK_ASSERT (v->v_type == HAWK_VAL_MAP); HAWK_ASSERT (v->v_type == HAWK_VAL_MAP);
itr._dir = 0; hawk_init_map_itr (&itr, 0);
pair = hawk_map_getfirstpair(((hawk_val_map_t*)v)->map, &itr); pair = hawk_map_getfirstpair(((hawk_val_map_t*)v)->map, &itr);
while (pair) while (pair)
{ {
@ -214,8 +214,29 @@ static void gc_free_unreachables (hawk_rtx_t* rtx, hawk_gch_t* list)
while (gch != list) while (gch != list)
{ {
tmp = gch->gc_next; tmp = gch->gc_next;
printf ("^^^^^^^^^^^^^^^^^^^^^^^^ freeing %p(%p) gc_refs %d v_refs %d\n", gch, gch->gc_refs, hawk_gch_to_val(gch)->v_refs);
hawk_rtx_freeval (rtx, hawk_gch_to_val(gch), 0); printf ("^^^^^^^^^^^^^^^^^^^^^^^^ freeing %p gc_refs %d v_refs %d\n", gch, (int)gch->gc_refs, (int)hawk_gch_to_val(gch)->v_refs);
//hawk_rtx_freeval (rtx, hawk_gch_to_val(gch), 0);
{
// TODO: revise this. MAP ONLY as of now.
hawk_val_map_t* v = (hawk_val_map_t*)hawk_gch_to_val(gch);
hawk_map_pair_t* pair;
hawk_map_itr_t itr;
hawk_oow_t refs = 0;
hawk_init_map_itr (&itr, 0);
pair = hawk_map_getfirstpair(v->map, &itr);
while (pair)
{
if (HAWK_MAP_VPTR(pair) == v) refs++;
else hawk_rtx_refdownval (rtx, HAWK_MAP_VPTR(pair));
pair = hawk_map_getnextpair(v->map, &itr);
}
while (refs-- > 0) hawk_rtx_refdownval (rtx, v);
}
gch = tmp; gch = tmp;
} }
} }
@ -234,6 +255,7 @@ printf ("collecting garbage...\n");
/* only unreachables are left in rtx->gc.all */ /* only unreachables are left in rtx->gc.all */
gc_dump_refs (rtx, &rtx->gc.all); gc_dump_refs (rtx, &rtx->gc.all);
gc_free_unreachables (rtx, &rtx->gc.all); gc_free_unreachables (rtx, &rtx->gc.all);
gc_dump_refs (rtx, &rtx->gc.all);
HAWK_ASSERT (rtx->gc.all.gc_next == &rtx->gc.all); HAWK_ASSERT (rtx->gc.all.gc_next == &rtx->gc.all);
gc_move_gchs (&rtx->gc.all, &reachable); gc_move_gchs (&rtx->gc.all, &reachable);
@ -534,6 +556,7 @@ hawk_val_t* hawk_rtx_makenstrvalwithuchars (hawk_rtx_t* rtx, const hawk_uch_t* p
v = hawk_rtx_makestrvalwithuchars(rtx, ptr, len); v = hawk_rtx_makestrvalwithuchars(rtx, ptr, len);
if (HAWK_UNLIKELY(!v)) return HAWK_NULL; if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
if (x >= 0) if (x >= 0)
{ {
/* set the numeric string flag if a string /* set the numeric string flag if a string