Compare commits
2 Commits
e8b613576f
...
0a0db012a3
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a0db012a3 | |||
| 21b22e28c4 |
394
lib/parse.c
394
lib/parse.c
@@ -994,6 +994,223 @@ oops:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int is_nde_bool_literal_atom (hawk_nde_t* nde)
|
||||
{
|
||||
switch (nde->type)
|
||||
{
|
||||
case HAWK_NDE_XFALSE:
|
||||
case HAWK_NDE_XTRUE:
|
||||
case HAWK_NDE_XNIL:
|
||||
case HAWK_NDE_INT:
|
||||
case HAWK_NDE_FLT:
|
||||
case HAWK_NDE_STR:
|
||||
case HAWK_NDE_MBS:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* return the effective literal node for boolean decision.
|
||||
* if nde is a grouped node, every grouped element must be literal.
|
||||
* the returned node is the last literal element in the group.
|
||||
*
|
||||
* examples:
|
||||
* (1, 0) -> INT(0)
|
||||
* ((1, 0)) -> INT(0)
|
||||
* ("x", @false) -> XFALSE
|
||||
* (abc(), 0) -> HAWK_NULL
|
||||
*/
|
||||
static hawk_nde_t* get_nde_bool_literal_tail (hawk_nde_t* nde, int depth)
|
||||
{
|
||||
if (depth >= 256) return HAWK_NULL; /* i don't wawnt to support to deep recursion. TODO: remove hard-coded value or remove recursion? */
|
||||
|
||||
if (nde->type == HAWK_NDE_GRP)
|
||||
{
|
||||
hawk_nde_t* cur, * last;
|
||||
|
||||
cur = ((hawk_nde_grp_t*)nde)->body;
|
||||
HAWK_ASSERT(cur != HAWK_NULL);
|
||||
|
||||
last = HAWK_NULL;
|
||||
do
|
||||
{
|
||||
last = get_nde_bool_literal_tail(cur, depth + 1);
|
||||
if (!last) return HAWK_NULL;
|
||||
cur = cur->next;
|
||||
}
|
||||
while (cur);
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
return is_nde_bool_literal_atom(nde)? nde: HAWK_NULL;
|
||||
}
|
||||
|
||||
static nde_hard_bool_t classify_nde_hard_bool (hawk_nde_t* nde)
|
||||
{
|
||||
nde = get_nde_bool_literal_tail(nde, 0);
|
||||
if (!nde) return NDE_HARD_BOOL_UNKNOWN;
|
||||
|
||||
switch (nde->type)
|
||||
{
|
||||
case HAWK_NDE_XFALSE:
|
||||
case HAWK_NDE_XNIL:
|
||||
return NDE_HARD_BOOL_FALSE;
|
||||
|
||||
case HAWK_NDE_XTRUE:
|
||||
return NDE_HARD_BOOL_TRUE;
|
||||
|
||||
case HAWK_NDE_INT:
|
||||
return (((hawk_nde_int_t*)nde)->val == 0)?
|
||||
NDE_HARD_BOOL_FALSE: NDE_HARD_BOOL_TRUE;
|
||||
|
||||
case HAWK_NDE_FLT:
|
||||
return (((hawk_nde_flt_t*)nde)->val == 0.0)?
|
||||
NDE_HARD_BOOL_FALSE: NDE_HARD_BOOL_TRUE;
|
||||
|
||||
case HAWK_NDE_STR:
|
||||
return (((hawk_nde_str_t*)nde)->len == 0)?
|
||||
NDE_HARD_BOOL_FALSE: NDE_HARD_BOOL_TRUE;
|
||||
|
||||
case HAWK_NDE_MBS:
|
||||
return (((hawk_nde_mbs_t*)nde)->len == 0)?
|
||||
NDE_HARD_BOOL_FALSE: NDE_HARD_BOOL_TRUE;
|
||||
|
||||
default:
|
||||
return NDE_HARD_BOOL_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static HAWK_INLINE int is_nde_hard_false (hawk_nde_t* nde)
|
||||
{
|
||||
return classify_nde_hard_bool(nde) == NDE_HARD_BOOL_FALSE;
|
||||
}
|
||||
|
||||
static HAWK_INLINE int is_nde_hard_true (hawk_nde_t* nde)
|
||||
{
|
||||
return classify_nde_hard_bool(nde) == NDE_HARD_BOOL_TRUE;
|
||||
}
|
||||
|
||||
static int is_nde_unconditional_terminator (hawk_nde_t* nde)
|
||||
{
|
||||
switch (nde->type)
|
||||
{
|
||||
case HAWK_NDE_EXIT: /* exit or @abort */
|
||||
case HAWK_NDE_RETURN: /* return */
|
||||
case HAWK_NDE_NEXT:
|
||||
case HAWK_NDE_NEXTFILE:
|
||||
return 1;
|
||||
|
||||
/* TODO: recursion depth check? */
|
||||
case HAWK_NDE_BLK:
|
||||
{
|
||||
hawk_nde_t* p;
|
||||
for (p = ((hawk_nde_blk_t*)nde)->body; p; p = p->next)
|
||||
{
|
||||
if (is_nde_unconditional_terminator(p)) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case HAWK_NDE_IF:
|
||||
{
|
||||
hawk_nde_if_t* p = (hawk_nde_if_t*)nde;
|
||||
return p->else_part &&
|
||||
is_nde_unconditional_terminator(p->else_part) &&
|
||||
is_nde_unconditional_terminator(p->then_part);
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int does_nde_have_side_effect (hawk_nde_t* nde)
|
||||
{
|
||||
HAWK_ASSERT(nde != HAWK_NULL);
|
||||
|
||||
switch (nde->type)
|
||||
{
|
||||
case HAWK_NDE_NULL:
|
||||
case HAWK_NDE_CHAR:
|
||||
case HAWK_NDE_BCHR:
|
||||
case HAWK_NDE_INT:
|
||||
case HAWK_NDE_FLT:
|
||||
case HAWK_NDE_STR:
|
||||
case HAWK_NDE_MBS:
|
||||
case HAWK_NDE_REX:
|
||||
case HAWK_NDE_XNIL:
|
||||
case HAWK_NDE_XTRUE:
|
||||
case HAWK_NDE_XFALSE:
|
||||
case HAWK_NDE_XARGC:
|
||||
case HAWK_NDE_XARGV:
|
||||
case HAWK_NDE_FUN:
|
||||
case HAWK_NDE_MODSYM:
|
||||
case HAWK_NDE_NAMED:
|
||||
case HAWK_NDE_GBL:
|
||||
case HAWK_NDE_LCL:
|
||||
case HAWK_NDE_ARG:
|
||||
return 0;
|
||||
|
||||
case HAWK_NDE_NAMEDIDX:
|
||||
case HAWK_NDE_GBLIDX:
|
||||
case HAWK_NDE_LCLIDX:
|
||||
case HAWK_NDE_ARGIDX:
|
||||
return does_nde_have_side_effect(((hawk_nde_var_t*)nde)->idx);
|
||||
|
||||
case HAWK_NDE_XARGVIDX:
|
||||
return does_nde_have_side_effect(((hawk_nde_xargvidx_t*)nde)->pos);
|
||||
|
||||
case HAWK_NDE_POS:
|
||||
return does_nde_have_side_effect(((hawk_nde_pos_t*)nde)->val);
|
||||
|
||||
case HAWK_NDE_GRP:
|
||||
{
|
||||
hawk_nde_t* p;
|
||||
for (p = ((hawk_nde_grp_t*)nde)->body; p; p = p->next)
|
||||
{
|
||||
if (does_nde_have_side_effect(p)) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case HAWK_NDE_EXP_BIN:
|
||||
return does_nde_have_side_effect(((hawk_nde_exp_t*)nde)->left) ||
|
||||
does_nde_have_side_effect(((hawk_nde_exp_t*)nde)->right);
|
||||
|
||||
case HAWK_NDE_EXP_UNR:
|
||||
return does_nde_have_side_effect(((hawk_nde_exp_t*)nde)->left);
|
||||
|
||||
case HAWK_NDE_BLK:
|
||||
{
|
||||
hawk_nde_t* p;
|
||||
for (p = ((hawk_nde_blk_t*)nde)->body; p; p = p->next)
|
||||
{
|
||||
if (does_nde_have_side_effect(p)) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case HAWK_NDE_CND:
|
||||
return does_nde_have_side_effect(((hawk_nde_cnd_t*)nde)->test) ||
|
||||
does_nde_have_side_effect(((hawk_nde_cnd_t*)nde)->left) ||
|
||||
does_nde_have_side_effect(((hawk_nde_cnd_t*)nde)->right);
|
||||
|
||||
case HAWK_NDE_IF:
|
||||
{
|
||||
hawk_nde_if_t* p = (hawk_nde_if_t*)nde;
|
||||
return does_nde_have_side_effect(p->test) ||
|
||||
does_nde_have_side_effect(p->then_part) ||
|
||||
(p->else_part && does_nde_have_side_effect(p->else_part));
|
||||
}
|
||||
|
||||
/* all other nodes */
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_progunit (hawk_t* hawk)
|
||||
{
|
||||
/*
|
||||
@@ -2024,6 +2241,7 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int flags)
|
||||
hawk_nde_blk_t* block;
|
||||
hawk_oow_t nlcls_outer, nlcls_max, tmp;
|
||||
nde_chain_t local_inits = { HAWK_NULL, HAWK_NULL };
|
||||
int dead_code;
|
||||
|
||||
nlcls_outer = HAWK_ARR_SIZE(hawk->parse.lcls);
|
||||
nlcls_max = hawk->parse.nlcls_max;
|
||||
@@ -2034,6 +2252,7 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int flags)
|
||||
/* block body */
|
||||
head = local_inits.head;
|
||||
curr = local_inits.tail;
|
||||
dead_code = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -2100,9 +2319,17 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int flags)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dead_code)
|
||||
{
|
||||
hawk_clrpt(hawk, nde);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (curr == HAWK_NULL) head = nde;
|
||||
else curr->next = nde;
|
||||
curr = nde;
|
||||
|
||||
if (is_nde_unconditional_terminator(nde)) dead_code = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3025,102 +3252,22 @@ oops:
|
||||
return HAWK_NULL;
|
||||
}
|
||||
|
||||
static int is_nde_bool_literal_atom (hawk_nde_t* nde)
|
||||
static hawk_nde_t* make_null_nde (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
{
|
||||
switch (nde->type)
|
||||
hawk_nde_t* null_nde;
|
||||
|
||||
null_nde = (hawk_nde_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*null_nde));
|
||||
if (HAWK_UNLIKELY(!null_nde))
|
||||
{
|
||||
case HAWK_NDE_XFALSE:
|
||||
case HAWK_NDE_XTRUE:
|
||||
case HAWK_NDE_XNIL:
|
||||
case HAWK_NDE_INT:
|
||||
case HAWK_NDE_FLT:
|
||||
case HAWK_NDE_STR:
|
||||
case HAWK_NDE_MBS:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* return the effective literal node for boolean decision.
|
||||
* if nde is a grouped node, every grouped element must be literal.
|
||||
* the returned node is the last literal element in the group.
|
||||
*
|
||||
* examples:
|
||||
* (1, 0) -> INT(0)
|
||||
* ((1, 0)) -> INT(0)
|
||||
* ("x", @false) -> XFALSE
|
||||
* (abc(), 0) -> HAWK_NULL
|
||||
*/
|
||||
static hawk_nde_t* get_nde_bool_literal_tail (hawk_nde_t* nde, int depth)
|
||||
{
|
||||
if (depth >= 256) return HAWK_NULL; /* i don't wawnt to support to deep recursion. TODO: remove hard-coded value or remove recursion? */
|
||||
|
||||
if (nde->type == HAWK_NDE_GRP)
|
||||
{
|
||||
hawk_nde_t* cur, * last;
|
||||
|
||||
cur = ((hawk_nde_grp_t*)nde)->body;
|
||||
HAWK_ASSERT(cur != HAWK_NULL);
|
||||
|
||||
last = HAWK_NULL;
|
||||
do
|
||||
{
|
||||
last = get_nde_bool_literal_tail(cur, depth + 1);
|
||||
if (!last) return HAWK_NULL;
|
||||
cur = cur->next;
|
||||
}
|
||||
while (cur);
|
||||
|
||||
return last;
|
||||
ADJERR_LOC(hawk, xloc);
|
||||
return HAWK_NULL;
|
||||
}
|
||||
|
||||
return is_nde_bool_literal_atom(nde)? nde: HAWK_NULL;
|
||||
}
|
||||
null_nde->type = HAWK_NDE_NULL;
|
||||
if (xloc) null_nde->loc = *xloc;
|
||||
null_nde->next = HAWK_NULL;
|
||||
|
||||
static nde_hard_bool_t classify_nde_hard_bool (hawk_nde_t* nde)
|
||||
{
|
||||
nde = get_nde_bool_literal_tail(nde, 0);
|
||||
if (!nde) return NDE_HARD_BOOL_UNKNOWN;
|
||||
|
||||
switch (nde->type)
|
||||
{
|
||||
case HAWK_NDE_XFALSE:
|
||||
case HAWK_NDE_XNIL:
|
||||
return NDE_HARD_BOOL_FALSE;
|
||||
|
||||
case HAWK_NDE_XTRUE:
|
||||
return NDE_HARD_BOOL_TRUE;
|
||||
|
||||
case HAWK_NDE_INT:
|
||||
return (((hawk_nde_int_t*)nde)->val == 0)?
|
||||
NDE_HARD_BOOL_FALSE: NDE_HARD_BOOL_TRUE;
|
||||
|
||||
case HAWK_NDE_FLT:
|
||||
return (((hawk_nde_flt_t*)nde)->val == 0.0)?
|
||||
NDE_HARD_BOOL_FALSE: NDE_HARD_BOOL_TRUE;
|
||||
|
||||
case HAWK_NDE_STR:
|
||||
return (((hawk_nde_str_t*)nde)->len == 0)?
|
||||
NDE_HARD_BOOL_FALSE: NDE_HARD_BOOL_TRUE;
|
||||
|
||||
case HAWK_NDE_MBS:
|
||||
return (((hawk_nde_mbs_t*)nde)->len == 0)?
|
||||
NDE_HARD_BOOL_FALSE: NDE_HARD_BOOL_TRUE;
|
||||
|
||||
default:
|
||||
return NDE_HARD_BOOL_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static HAWK_INLINE int is_nde_hard_false (hawk_nde_t* nde)
|
||||
{
|
||||
return classify_nde_hard_bool(nde) == NDE_HARD_BOOL_FALSE;
|
||||
}
|
||||
|
||||
static HAWK_INLINE int is_nde_hard_true (hawk_nde_t* nde)
|
||||
{
|
||||
return classify_nde_hard_bool(nde) == NDE_HARD_BOOL_TRUE;
|
||||
return null_nde;
|
||||
}
|
||||
|
||||
static hawk_nde_t* parse_if (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
@@ -3148,10 +3295,6 @@ static hawk_nde_t* parse_if (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
goto oops;
|
||||
}
|
||||
|
||||
/* TODO: optimization. if you know 'test' evaluates to true or false,
|
||||
* you can drop the 'if' statement and take either the 'then_part'
|
||||
* or 'else_part'. */
|
||||
|
||||
if (get_token(hawk) <= -1) goto oops;
|
||||
|
||||
tloc = hawk->tok.loc;
|
||||
@@ -3189,12 +3332,8 @@ static hawk_nde_t* parse_if (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
{
|
||||
hawk_nde_t* null_nde;
|
||||
|
||||
null_nde = (hawk_nde_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*null_nde));
|
||||
if (HAWK_UNLIKELY(!null_nde))
|
||||
{
|
||||
ADJERR_LOC(hawk, xloc);
|
||||
goto oops;
|
||||
}
|
||||
null_nde = make_null_nde(hawk, xloc);
|
||||
if (HAWK_UNLIKELY(!null_nde)) goto oops;
|
||||
|
||||
/* [BE CAREFUL]
|
||||
* Don't forget reset test and then_part to HAWK_NULL if the control
|
||||
@@ -3202,8 +3341,6 @@ static hawk_nde_t* parse_if (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
hawk_clrpt(hawk, test);
|
||||
hawk_clrpt(hawk, then_part);
|
||||
|
||||
null_nde->type = HAWK_NDE_NULL;
|
||||
null_nde->loc = *xloc;
|
||||
return null_nde;
|
||||
}
|
||||
}
|
||||
@@ -3480,18 +3617,12 @@ static hawk_nde_t* parse_while (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
/* fold while(0) and while(@false) into a null statement. */
|
||||
hawk_nde_t* null_nde;
|
||||
|
||||
null_nde = (hawk_nde_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*null_nde));
|
||||
if (HAWK_UNLIKELY(!null_nde))
|
||||
{
|
||||
ADJERR_LOC(hawk, xloc);
|
||||
goto oops;
|
||||
}
|
||||
null_nde = make_null_nde(hawk, xloc);
|
||||
if (HAWK_UNLIKELY(!null_nde)) goto oops;
|
||||
|
||||
hawk_clrpt(hawk, body); body = HAWK_NULL;
|
||||
hawk_clrpt(hawk, test); test = HAWK_NULL;
|
||||
|
||||
null_nde->type = HAWK_NDE_NULL;
|
||||
null_nde->loc = *xloc;
|
||||
return null_nde;
|
||||
}
|
||||
|
||||
@@ -4342,20 +4473,12 @@ static hawk_nde_t* parse_statement (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
if (MATCH(hawk,TOK_SEMICOLON))
|
||||
{
|
||||
/* null statement */
|
||||
nde = (hawk_nde_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*nde));
|
||||
if (HAWK_UNLIKELY(!nde))
|
||||
{
|
||||
ADJERR_LOC(hawk, xloc);
|
||||
return HAWK_NULL;
|
||||
}
|
||||
|
||||
nde->type = HAWK_NDE_NULL;
|
||||
nde->loc = *xloc;
|
||||
nde->next = HAWK_NULL;
|
||||
nde = make_null_nde(hawk, xloc);
|
||||
if (HAWK_UNLIKELY(!nde)) return HAWK_NULL;
|
||||
|
||||
if (get_token(hawk) <= -1)
|
||||
{
|
||||
hawk_freemem(hawk, nde);
|
||||
hawk_clrpt(hawk, nde);
|
||||
return HAWK_NULL;
|
||||
}
|
||||
}
|
||||
@@ -4392,6 +4515,15 @@ static hawk_nde_t* parse_statement (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
hawk->parse.id.stmt = old_id;
|
||||
}
|
||||
|
||||
if (nde && !does_nde_have_side_effect(nde))
|
||||
{
|
||||
hawk_nde_t* tmp;
|
||||
tmp = make_null_nde(hawk, &nde->loc);
|
||||
hawk_clrpt(hawk, nde);
|
||||
if (HAWK_UNLIKELY(!tmp)) return HAWK_NULL;
|
||||
nde = tmp;
|
||||
}
|
||||
|
||||
return nde;
|
||||
}
|
||||
|
||||
@@ -4430,7 +4562,7 @@ static hawk_nde_t* parse_expr_basic (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
hawk_nde_t* nde, * n1, * n2;
|
||||
|
||||
nde = parse_logical_or(hawk, xloc);
|
||||
if (nde == HAWK_NULL) return HAWK_NULL;
|
||||
if (!nde) return HAWK_NULL;
|
||||
|
||||
if (MATCH(hawk,TOK_QUEST))
|
||||
{
|
||||
@@ -4445,7 +4577,7 @@ static hawk_nde_t* parse_expr_basic (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
|
||||
eloc = hawk->tok.loc;
|
||||
n1 = parse_expr_withdc(hawk, &eloc);
|
||||
if (n1 == HAWK_NULL)
|
||||
if (!n1)
|
||||
{
|
||||
hawk_clrpt(hawk, nde);
|
||||
return HAWK_NULL;
|
||||
@@ -4467,7 +4599,7 @@ static hawk_nde_t* parse_expr_basic (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
|
||||
eloc = hawk->tok.loc;
|
||||
n2 = parse_expr_withdc(hawk, &eloc);
|
||||
if (n2 == HAWK_NULL)
|
||||
if (!n2)
|
||||
{
|
||||
hawk_clrpt(hawk, nde);
|
||||
hawk_clrpt(hawk, n1);
|
||||
@@ -4475,7 +4607,7 @@ static hawk_nde_t* parse_expr_basic (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
}
|
||||
|
||||
cnd = (hawk_nde_cnd_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*cnd));
|
||||
if (cnd == HAWK_NULL)
|
||||
if (HAWK_UNLIKELY(!cnd))
|
||||
{
|
||||
hawk_clrpt(hawk, nde);
|
||||
hawk_clrpt(hawk, n1);
|
||||
@@ -7403,18 +7535,14 @@ static hawk_nde_t* parse_idx_chain (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
|
||||
/* additional index - a[10][20] or a.b.c ...
|
||||
* use the NULL node as a splitter */
|
||||
splitter = (hawk_nde_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*splitter));
|
||||
if (HAWK_UNLIKELY(!splitter))
|
||||
{
|
||||
ADJERR_LOC(hawk, xloc);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
splitter->type = HAWK_NDE_NULL;
|
||||
splitter = make_null_nde(hawk, xloc);
|
||||
if (HAWK_UNLIKELY(!splitter)) goto oops;
|
||||
|
||||
HAWK_ASSERT(idx.tail != HAWK_NULL);
|
||||
idx.tail->next = splitter;
|
||||
idx.tail = splitter;
|
||||
/* splitter is already chained. no need seperate clearing upon failure */
|
||||
|
||||
if (parse_single_idx(hawk, &idx) <= -1) goto oops;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user