Compare commits
6 Commits
b9dd73ee9f
...
479b74d1a3
| Author | SHA1 | Date | |
|---|---|---|---|
| 479b74d1a3 | |||
| f444cc92fe | |||
| b5464605d8 | |||
| 9e5804a15b | |||
| ecc1c4bfb3 | |||
| 1428e7dc2f |
@@ -358,7 +358,8 @@ BEGIN {
|
||||
|
||||
### Arithmetic and Comparison
|
||||
|
||||
- Arithmetic: `+`, `-`, `*`, `/`, `%`, `**` (exponentiation), `++`, `--`, `<<`, `>>`.
|
||||
- Arithmetic: `+`, `-`, `*`, `/`, `\`(integer division), `%`(modulo), `**` or '^'(exponentiation), `++`, `--`, `<<`, `>>`.
|
||||
- Compound assignment: `=`, `+=`, `-=`, `*=`, `/=`, `\=`, `%=`, `^=` or `**=`, `%%=`.
|
||||
- Comparisons: `==`, `!=`, `<`, `<=`, `>`, `>=`.
|
||||
- Type-precise compare: `===` and `!==`.
|
||||
|
||||
@@ -367,7 +368,11 @@ Example:
|
||||
```awk
|
||||
BEGIN {
|
||||
x = 10 + 5 * 2
|
||||
x += 3
|
||||
s = "ha"
|
||||
s %%= "wk"
|
||||
if (x >= 20) print x
|
||||
print s
|
||||
if ("10" === 10) print "no"
|
||||
}
|
||||
```
|
||||
@@ -404,6 +409,7 @@ BEGIN {
|
||||
|
||||
- Bitwise AND/OR/XOR: `&`, `|`, ^^
|
||||
- Unary bitwise negation: ~
|
||||
- Compound bitwise assignment: `&=`, `|=`, `^^=`, `<<=`, `>>=`
|
||||
- `|` also denotes pipes, so use parentheses when you mean bitwise OR.
|
||||
- `>>` is also used for append redirection; use parentheses when you mean right shift.
|
||||
|
||||
|
||||
+492
-162
@@ -218,6 +218,15 @@ struct nde_chain_t
|
||||
hawk_nde_t* tail;
|
||||
};
|
||||
|
||||
enum nde_hard_bool_t
|
||||
{
|
||||
NDE_HARD_BOOL_UNKNOWN = -1,
|
||||
NDE_HARD_BOOL_FALSE = 0,
|
||||
NDE_HARD_BOOL_TRUE = 1
|
||||
};
|
||||
typedef enum nde_hard_bool_t nde_hard_bool_t;
|
||||
|
||||
|
||||
static int parse_progunit (hawk_t* hawk);
|
||||
static void adjust_static_globals (hawk_t* hawk);
|
||||
static hawk_oow_t find_global (hawk_t* hawk, const hawk_oocs_t* name);
|
||||
@@ -1100,6 +1109,56 @@ static int compile_funbc_expr_bin_land (hawk_t* hawk, hawk_fbc_t* bc, hawk_nde_e
|
||||
return COMPILE_FUNBC_EXPR_OK;
|
||||
}
|
||||
|
||||
static int is_lowerable_funbc_fnc_argspec (const hawk_ooch_t* arg_spec)
|
||||
{
|
||||
if (!arg_spec) return 1;
|
||||
|
||||
do
|
||||
{
|
||||
if (*arg_spec == HAWK_T('r') || *arg_spec == HAWK_T('R') || *arg_spec == HAWK_T('x')) return 0;
|
||||
}
|
||||
while (*arg_spec++);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int compile_funbc_expr_fncall (hawk_t* hawk, hawk_fbc_t* bc, hawk_nde_fncall_t* call)
|
||||
{
|
||||
hawk_nde_t* p;
|
||||
int n;
|
||||
|
||||
switch (call->type)
|
||||
{
|
||||
case HAWK_NDE_FNCALL_FNC:
|
||||
if (call->u.fnc.flags & HAWK_NDE_FNCALL_FNC_DEFERRED_MODFNC) return COMPILE_FUNBC_EXPR_UNSUPPORTED;
|
||||
if (!is_lowerable_funbc_fnc_argspec(call->u.fnc.spec.arg.spec)) return COMPILE_FUNBC_EXPR_UNSUPPORTED;
|
||||
break;
|
||||
|
||||
case HAWK_NDE_FNCALL_EXPR:
|
||||
HAWK_ASSERT(call->u.expr.callable != HAWK_NULL);
|
||||
n = compile_funbc_expr(hawk, bc, call->u.expr.callable);
|
||||
if (n <= -1) return -1;
|
||||
if (n == COMPILE_FUNBC_EXPR_UNSUPPORTED) return COMPILE_FUNBC_EXPR_UNSUPPORTED;
|
||||
break;
|
||||
|
||||
case HAWK_NDE_FNCALL_FUN:
|
||||
break;
|
||||
|
||||
default:
|
||||
return COMPILE_FUNBC_EXPR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
for (p = call->args; p; p = p->next)
|
||||
{
|
||||
n = compile_funbc_expr(hawk, bc, p);
|
||||
if (n <= -1) return -1;
|
||||
if (n == COMPILE_FUNBC_EXPR_UNSUPPORTED) return COMPILE_FUNBC_EXPR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (emit_funbc_ins_nde(hawk, bc, HAWK_FBC_OP_CALL, (hawk_nde_t*)call, &call->loc) <= -1) return -1;
|
||||
return COMPILE_FUNBC_EXPR_OK;
|
||||
}
|
||||
|
||||
static int compile_funbc_expr (hawk_t* hawk, hawk_fbc_t* bc, hawk_nde_t* nde)
|
||||
{
|
||||
hawk_oow_t rollback;
|
||||
@@ -1178,6 +1237,18 @@ static int compile_funbc_expr (hawk_t* hawk, hawk_fbc_t* bc, hawk_nde_t* nde)
|
||||
return COMPILE_FUNBC_EXPR_OK;
|
||||
}
|
||||
|
||||
case HAWK_NDE_FNCALL_FNC:
|
||||
case HAWK_NDE_FNCALL_FUN:
|
||||
case HAWK_NDE_FNCALL_EXPR:
|
||||
{
|
||||
int n;
|
||||
|
||||
n = compile_funbc_expr_fncall(hawk, bc, (hawk_nde_fncall_t*)nde);
|
||||
if (n <= -1) goto oops_rollback;
|
||||
if (n == COMPILE_FUNBC_EXPR_UNSUPPORTED) goto unsupported;
|
||||
return COMPILE_FUNBC_EXPR_OK;
|
||||
}
|
||||
|
||||
case HAWK_NDE_ASS:
|
||||
{
|
||||
hawk_nde_ass_t* ass = (hawk_nde_ass_t*)nde;
|
||||
@@ -4245,6 +4316,104 @@ oops:
|
||||
return HAWK_NULL;
|
||||
}
|
||||
|
||||
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 hawk_nde_t* parse_if (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
{
|
||||
hawk_nde_t* test = HAWK_NULL;
|
||||
@@ -4298,6 +4467,45 @@ static hawk_nde_t* parse_if (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
}
|
||||
}
|
||||
|
||||
if (is_nde_hard_false(test))
|
||||
{
|
||||
/* fold if (0) or if (@false) or its variants */
|
||||
if (else_part)
|
||||
{
|
||||
hawk_clrpt(hawk, test);
|
||||
hawk_clrpt(hawk, then_part);
|
||||
return else_part;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* [BE CAREFUL]
|
||||
* Don't forget reset test and then_part to HAWK_NULL if the control
|
||||
* skips the immediate return below and reaches further down */
|
||||
hawk_clrpt(hawk, test);
|
||||
hawk_clrpt(hawk, then_part);
|
||||
|
||||
null_nde->type = HAWK_NDE_NULL;
|
||||
null_nde->loc = *xloc;
|
||||
return null_nde;
|
||||
}
|
||||
}
|
||||
else if (is_nde_hard_true(test))
|
||||
{
|
||||
/* fold the else part for if (1) or if (@true) or its variants */
|
||||
hawk_clrpt(hawk, test);
|
||||
if (else_part) hawk_clrpt(hawk, else_part);
|
||||
return then_part;
|
||||
}
|
||||
|
||||
nde = (hawk_nde_if_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*nde));
|
||||
if (HAWK_UNLIKELY(!nde))
|
||||
{
|
||||
@@ -4558,6 +4766,26 @@ static hawk_nde_t* parse_while (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
body = parse_statement(hawk, &ploc);
|
||||
if (HAWK_UNLIKELY(!body)) goto oops;
|
||||
|
||||
if (is_nde_hard_false(test))
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
nde = (hawk_nde_while_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*nde));
|
||||
if (HAWK_UNLIKELY(!nde))
|
||||
{
|
||||
@@ -5677,195 +5905,235 @@ union folded_t
|
||||
};
|
||||
typedef union folded_t folded_t;
|
||||
|
||||
static int fold_constants_for_binop (
|
||||
hawk_t* hawk, hawk_nde_t* left, hawk_nde_t* right,
|
||||
int opcode, folded_t* folded)
|
||||
static HAWK_INLINE int is_nde_numeric_literal (hawk_nde_t* nde)
|
||||
{
|
||||
int fold = -1;
|
||||
return nde->type == HAWK_NDE_INT || nde->type == HAWK_NDE_FLT;
|
||||
}
|
||||
|
||||
/* TODO: can i shorten various comparisons below?
|
||||
* i hate to repeat similar code just for type difference */
|
||||
|
||||
if (left->type == HAWK_NDE_INT && right->type == HAWK_NDE_INT)
|
||||
static HAWK_INLINE hawk_int_t get_nde_literal_as_int (hawk_nde_t* nde)
|
||||
{
|
||||
fold = HAWK_NDE_INT;
|
||||
return (nde->type == HAWK_NDE_INT)? ((hawk_nde_int_t*)nde)->val: (hawk_int_t)((hawk_nde_flt_t*)nde)->val;
|
||||
}
|
||||
|
||||
static HAWK_INLINE hawk_flt_t get_nde_literal_as_flt (hawk_nde_t* nde)
|
||||
{
|
||||
return (nde->type == HAWK_NDE_INT)? (hawk_flt_t)((hawk_nde_int_t*)nde)->val: ((hawk_nde_flt_t*)nde)->val;
|
||||
}
|
||||
|
||||
static HAWK_INLINE int is_safe_shift_count (hawk_int_t n)
|
||||
{
|
||||
return n >= 0 && n < HAWK_BITSOF(hawk_int_t);
|
||||
}
|
||||
|
||||
static int fold_constants_for_binop (hawk_t* hawk, hawk_nde_t* left, hawk_nde_t* right, int opcode, folded_t* folded)
|
||||
{
|
||||
hawk_int_t li, ri;
|
||||
hawk_flt_t lf, rf;
|
||||
int both_int;
|
||||
|
||||
if (!is_nde_numeric_literal(left) || !is_nde_numeric_literal(right)) return -1;
|
||||
|
||||
li = get_nde_literal_as_int(left);
|
||||
ri = get_nde_literal_as_int(right);
|
||||
lf = get_nde_literal_as_flt(left);
|
||||
rf = get_nde_literal_as_flt(right);
|
||||
both_int = (left->type == HAWK_NDE_INT && right->type == HAWK_NDE_INT);
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case HAWK_BINOP_PLUS:
|
||||
folded->l = INT_BINOP_INT(left,+,right);
|
||||
break;
|
||||
if (both_int)
|
||||
{
|
||||
folded->l = li + ri;
|
||||
return HAWK_NDE_INT;
|
||||
}
|
||||
folded->r = lf + rf;
|
||||
return HAWK_NDE_FLT;
|
||||
|
||||
case HAWK_BINOP_MINUS:
|
||||
folded->l = INT_BINOP_INT(left,-,right);
|
||||
break;
|
||||
if (both_int)
|
||||
{
|
||||
folded->l = li - ri;
|
||||
return HAWK_NDE_INT;
|
||||
}
|
||||
folded->r = lf - rf;
|
||||
return HAWK_NDE_FLT;
|
||||
|
||||
case HAWK_BINOP_MUL:
|
||||
folded->l = INT_BINOP_INT(left,*,right);
|
||||
break;
|
||||
if (both_int)
|
||||
{
|
||||
folded->l = li * ri;
|
||||
return HAWK_NDE_INT;
|
||||
}
|
||||
folded->r = lf * rf;
|
||||
return HAWK_NDE_FLT;
|
||||
|
||||
case HAWK_BINOP_DIV:
|
||||
if (((hawk_nde_int_t*)right)->val == 0)
|
||||
if (both_int)
|
||||
{
|
||||
if (ri == 0)
|
||||
{
|
||||
hawk_seterrnum(hawk, HAWK_NULL, HAWK_EDIVBY0);
|
||||
fold = -2; /* error */
|
||||
return -2;
|
||||
}
|
||||
else if (INT_BINOP_INT(left,%,right))
|
||||
|
||||
if ((li % ri) == 0)
|
||||
{
|
||||
folded->r = (hawk_flt_t)((hawk_nde_int_t*)left)->val /
|
||||
(hawk_flt_t)((hawk_nde_int_t*)right)->val;
|
||||
fold = HAWK_NDE_FLT;
|
||||
folded->l = li / ri;
|
||||
return HAWK_NDE_INT;
|
||||
}
|
||||
else
|
||||
{
|
||||
folded->l = INT_BINOP_INT(left,/,right);
|
||||
|
||||
folded->r = (hawk_flt_t)li / (hawk_flt_t)ri;
|
||||
return HAWK_NDE_FLT;
|
||||
}
|
||||
break;
|
||||
|
||||
folded->r = lf / rf;
|
||||
return HAWK_NDE_FLT;
|
||||
|
||||
case HAWK_BINOP_IDIV:
|
||||
if (((hawk_nde_int_t*)right)->val == 0)
|
||||
if (both_int && ri == 0)
|
||||
{
|
||||
hawk_seterrnum(hawk, HAWK_NULL, HAWK_EDIVBY0);
|
||||
fold = -2; /* error */
|
||||
return -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
folded->l = INT_BINOP_INT(left,/,right);
|
||||
}
|
||||
break;
|
||||
|
||||
folded->l = (both_int)? (li / ri): (hawk_int_t)(lf / rf);
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
case HAWK_BINOP_MOD:
|
||||
folded->l = INT_BINOP_INT(left,%,right);
|
||||
break;
|
||||
if (both_int)
|
||||
{
|
||||
if (ri == 0)
|
||||
{
|
||||
hawk_seterrnum(hawk, HAWK_NULL, HAWK_EDIVBY0);
|
||||
return -2;
|
||||
}
|
||||
|
||||
folded->l = li % ri;
|
||||
return HAWK_NDE_INT;
|
||||
}
|
||||
|
||||
folded->r = hawk->prm.math.mod(hawk, lf, rf);
|
||||
return HAWK_NDE_FLT;
|
||||
|
||||
case HAWK_BINOP_EXP:
|
||||
if (both_int)
|
||||
{
|
||||
if (ri >= 0)
|
||||
{
|
||||
hawk_int_t v = 1;
|
||||
hawk_int_t n = ri;
|
||||
while (n-- > 0) v *= li;
|
||||
folded->l = v;
|
||||
return HAWK_NDE_INT;
|
||||
}
|
||||
|
||||
if (li == 0)
|
||||
{
|
||||
hawk_seterrnum(hawk, HAWK_NULL, HAWK_EDIVBY0);
|
||||
return -2;
|
||||
}
|
||||
|
||||
{
|
||||
hawk_flt_t v = 1.0;
|
||||
hawk_int_t n = -ri;
|
||||
while (n-- > 0) v /= li;
|
||||
folded->r = v;
|
||||
return HAWK_NDE_FLT;
|
||||
}
|
||||
}
|
||||
|
||||
if (right->type == HAWK_NDE_INT)
|
||||
{
|
||||
if (ri >= 0)
|
||||
{
|
||||
hawk_flt_t v = 1.0;
|
||||
hawk_int_t n = ri;
|
||||
while (n-- > 0) v *= lf;
|
||||
folded->r = v;
|
||||
return HAWK_NDE_FLT;
|
||||
}
|
||||
|
||||
if (lf == 0.0)
|
||||
{
|
||||
hawk_seterrnum(hawk, HAWK_NULL, HAWK_EDIVBY0);
|
||||
return -2;
|
||||
}
|
||||
|
||||
{
|
||||
hawk_flt_t v = 1.0;
|
||||
hawk_int_t n = -ri;
|
||||
while (n-- > 0) v /= lf;
|
||||
folded->r = v;
|
||||
return HAWK_NDE_FLT;
|
||||
}
|
||||
}
|
||||
|
||||
folded->r = hawk->prm.math.pow(hawk, lf, rf);
|
||||
return HAWK_NDE_FLT;
|
||||
|
||||
case HAWK_BINOP_LS:
|
||||
if (!is_safe_shift_count(ri)) return -1;
|
||||
folded->l = li << ri;
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
case HAWK_BINOP_RS:
|
||||
if (!is_safe_shift_count(ri)) return -1;
|
||||
folded->l = li >> ri;
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
case HAWK_BINOP_BAND:
|
||||
folded->l = li & ri;
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
case HAWK_BINOP_BXOR:
|
||||
folded->l = li ^ ri;
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
case HAWK_BINOP_BOR:
|
||||
folded->l = li | ri;
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
case HAWK_BINOP_TEQ:
|
||||
if (left->type != right->type) folded->l = 0;
|
||||
else if (both_int) folded->l = (li == ri);
|
||||
else folded->l = (lf == rf);
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
case HAWK_BINOP_TNE:
|
||||
if (left->type != right->type) folded->l = 1;
|
||||
else if (both_int) folded->l = (li != ri);
|
||||
else folded->l = (lf != rf);
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
case HAWK_BINOP_EQ:
|
||||
folded->l = (both_int)? (li == ri): (lf == rf);
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
case HAWK_BINOP_NE:
|
||||
folded->l = (both_int)? (li != ri): (lf != rf);
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
case HAWK_BINOP_GT:
|
||||
folded->l = (both_int)? (li > ri): (lf > rf);
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
case HAWK_BINOP_GE:
|
||||
folded->l = (both_int)? (li >= ri): (lf >= rf);
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
case HAWK_BINOP_LT:
|
||||
folded->l = (both_int)? (li < ri): (lf < rf);
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
case HAWK_BINOP_LE:
|
||||
folded->l = (both_int)? (li <= ri): (lf <= rf);
|
||||
return HAWK_NDE_INT;
|
||||
|
||||
default:
|
||||
fold = -1; /* no folding */
|
||||
break;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (left->type == HAWK_NDE_FLT && right->type == HAWK_NDE_FLT)
|
||||
{
|
||||
fold = HAWK_NDE_FLT;
|
||||
switch (opcode)
|
||||
{
|
||||
case HAWK_BINOP_PLUS:
|
||||
folded->r = FLT_BINOP_FLT(left,+,right);
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_MINUS:
|
||||
folded->r = FLT_BINOP_FLT(left,-,right);
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_MUL:
|
||||
folded->r = FLT_BINOP_FLT(left,*,right);
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_DIV:
|
||||
folded->r = FLT_BINOP_FLT(left,/,right);
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_IDIV:
|
||||
folded->l = (hawk_int_t)FLT_BINOP_FLT(left,/,right);
|
||||
fold = HAWK_NDE_INT;
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_MOD:
|
||||
folded->r = hawk->prm.math.mod(
|
||||
hawk,
|
||||
((hawk_nde_flt_t*)left)->val,
|
||||
((hawk_nde_flt_t*)right)->val
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
fold = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (left->type == HAWK_NDE_INT && right->type == HAWK_NDE_FLT)
|
||||
{
|
||||
fold = HAWK_NDE_FLT;
|
||||
switch (opcode)
|
||||
{
|
||||
case HAWK_BINOP_PLUS:
|
||||
folded->r = INT_BINOP_FLT(left,+,right);
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_MINUS:
|
||||
folded->r = INT_BINOP_FLT(left,-,right);
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_MUL:
|
||||
folded->r = INT_BINOP_FLT(left,*,right);
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_DIV:
|
||||
folded->r = INT_BINOP_FLT(left,/,right);
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_IDIV:
|
||||
folded->l = (hawk_int_t)
|
||||
((hawk_flt_t)((hawk_nde_int_t*)left)->val /
|
||||
((hawk_nde_flt_t*)right)->val);
|
||||
fold = HAWK_NDE_INT;
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_MOD:
|
||||
folded->r = hawk->prm.math.mod(
|
||||
hawk,
|
||||
(hawk_flt_t)((hawk_nde_int_t*)left)->val,
|
||||
((hawk_nde_flt_t*)right)->val
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
fold = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (left->type == HAWK_NDE_FLT && right->type == HAWK_NDE_INT)
|
||||
{
|
||||
fold = HAWK_NDE_FLT;
|
||||
switch (opcode)
|
||||
{
|
||||
case HAWK_BINOP_PLUS:
|
||||
folded->r = FLT_BINOP_INT(left,+,right);
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_MINUS:
|
||||
folded->r = FLT_BINOP_INT(left,-,right);
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_MUL:
|
||||
folded->r = FLT_BINOP_INT(left,*,right);
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_DIV:
|
||||
folded->r = FLT_BINOP_INT(left,/,right);
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_IDIV:
|
||||
folded->l = (hawk_int_t)
|
||||
(((hawk_nde_int_t*)left)->val /
|
||||
(hawk_flt_t)((hawk_nde_int_t*)right)->val);
|
||||
fold = HAWK_NDE_INT;
|
||||
break;
|
||||
|
||||
case HAWK_BINOP_MOD:
|
||||
folded->r = hawk->prm.math.mod(
|
||||
hawk,
|
||||
((hawk_nde_flt_t*)left)->val,
|
||||
(hawk_flt_t)((hawk_nde_int_t*)right)->val
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
fold = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return fold;
|
||||
}
|
||||
|
||||
static hawk_nde_t* new_exp_bin_node (
|
||||
hawk_t* hawk, const hawk_loc_t* loc,
|
||||
@@ -5919,6 +6187,21 @@ static hawk_nde_t* new_flt_node (hawk_t* hawk, hawk_flt_t rv, const hawk_loc_t*
|
||||
return (hawk_nde_t*)tmp;
|
||||
}
|
||||
|
||||
static hawk_nde_t* new_xbool_node (hawk_t* hawk, int bv, const hawk_loc_t* loc)
|
||||
{
|
||||
hawk_nde_xnil_t* tmp;
|
||||
|
||||
tmp = (hawk_nde_xnil_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*tmp));
|
||||
if (HAWK_LIKELY(tmp))
|
||||
{
|
||||
tmp->type = bv? HAWK_NDE_XTRUE: HAWK_NDE_XFALSE;
|
||||
tmp->loc = *loc;
|
||||
}
|
||||
else ADJERR_LOC(hawk, loc);
|
||||
|
||||
return (hawk_nde_t*)tmp;
|
||||
}
|
||||
|
||||
static HAWK_INLINE void update_int_node (hawk_t* hawk, hawk_nde_int_t* node, hawk_int_t lv)
|
||||
{
|
||||
node->val = lv;
|
||||
@@ -6342,6 +6625,19 @@ static hawk_nde_t* parse_unary (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
hawk->parse.depth.expr--;
|
||||
if (left == HAWK_NULL) return HAWK_NULL;
|
||||
|
||||
if (opcode == HAWK_UNROP_LNOT)
|
||||
{
|
||||
/* handle the logical negation operator(!) first */
|
||||
nde_hard_bool_t hb;
|
||||
|
||||
hb = classify_nde_hard_bool(left);
|
||||
if (hb != NDE_HARD_BOOL_UNKNOWN)
|
||||
{
|
||||
hawk_clrpt(hawk, left);
|
||||
return new_xbool_node(hawk, hb == NDE_HARD_BOOL_FALSE, xloc);
|
||||
}
|
||||
}
|
||||
|
||||
fold = -1;
|
||||
if (left->type == HAWK_NDE_INT)
|
||||
{
|
||||
@@ -6356,9 +6652,11 @@ static hawk_nde_t* parse_unary (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
folded.l = -((hawk_nde_int_t*)left)->val;
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case HAWK_UNROP_LNOT:
|
||||
folded.l = !((hawk_nde_int_t*)left)->val;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case HAWK_UNROP_BNOT:
|
||||
folded.l = ~((hawk_nde_int_t*)left)->val;
|
||||
@@ -6382,9 +6680,12 @@ static hawk_nde_t* parse_unary (hawk_t* hawk, const hawk_loc_t* xloc)
|
||||
folded.r = -((hawk_nde_flt_t*)left)->val;
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case HAWK_UNROP_LNOT:
|
||||
folded.r = !((hawk_nde_flt_t*)left)->val;
|
||||
folded.l = !((hawk_nde_flt_t*)left)->val;
|
||||
fold = HAWK_NDE_INT;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case HAWK_UNROP_BNOT:
|
||||
folded.l = ~((hawk_int_t)((hawk_nde_flt_t*)left)->val);
|
||||
@@ -10111,11 +10412,40 @@ static int dump_funbc_ins (hawk_t* hawk, hawk_oow_t pc, const hawk_fbc_ins_t* in
|
||||
|
||||
case HAWK_FBC_OP_JMP:
|
||||
case HAWK_FBC_OP_JZ:
|
||||
case HAWK_FBC_OP_CALL:
|
||||
if (hawk_putsrcoocstr(hawk, HAWK_T(" ")) <= -1 ||
|
||||
put_oow_as_dec(hawk, ins->u.idx) <= -1) return -1;
|
||||
break;
|
||||
|
||||
case HAWK_FBC_OP_CALL:
|
||||
{
|
||||
hawk_nde_fncall_t* call = (hawk_nde_fncall_t*)ins->u.nde;
|
||||
const hawk_ooch_t* kind = HAWK_T("?");
|
||||
|
||||
if (!call)
|
||||
{
|
||||
if (hawk_putsrcoocstr(hawk, HAWK_T(" <null-call>")) <= -1) return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (call->type)
|
||||
{
|
||||
case HAWK_NDE_FNCALL_FNC: kind = HAWK_T("fnc"); break;
|
||||
case HAWK_NDE_FNCALL_FUN: kind = HAWK_T("fun"); break;
|
||||
case HAWK_NDE_FNCALL_EXPR: kind = HAWK_T("expr"); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (hawk_putsrcoocstr(hawk, HAWK_T(" ")) <= -1 ||
|
||||
hawk_putsrcoocstr(hawk, kind) <= -1 ||
|
||||
hawk_putsrcoocstr(hawk, HAWK_T(" nargs=")) <= -1 ||
|
||||
put_oow_as_dec(hawk, call->nargs) <= -1 ||
|
||||
hawk_putsrcoocstr(hawk, HAWK_T(" @")) <= -1 ||
|
||||
put_oow_as_dec(hawk, call->loc.line) <= -1 ||
|
||||
hawk_putsrcoocstr(hawk, HAWK_T(":")) <= -1 ||
|
||||
put_oow_as_dec(hawk, call->loc.colm) <= -1) return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
case HAWK_FBC_OP_INIT_BLK:
|
||||
{
|
||||
hawk_oow_t start, end;
|
||||
|
||||
+3
-3
@@ -54,15 +54,15 @@ int hawk_rtx_readiobytes (
|
||||
|
||||
int hawk_rtx_writeioval (
|
||||
hawk_rtx_t* rtx, hawk_out_type_t out_type,
|
||||
const hawk_ooch_t* name, hawk_val_t* v);
|
||||
const hawk_ooch_t* name, const hawk_val_t* v);
|
||||
|
||||
int hawk_rtx_writeiostr (
|
||||
hawk_rtx_t* rtx, hawk_out_type_t out_type,
|
||||
const hawk_ooch_t* name, hawk_ooch_t* str, hawk_oow_t len);
|
||||
const hawk_ooch_t* name, const hawk_ooch_t* str, hawk_oow_t len);
|
||||
|
||||
int hawk_rtx_writeiobytes (
|
||||
hawk_rtx_t* rtx, hawk_out_type_t out_type,
|
||||
const hawk_ooch_t* name, hawk_bch_t* str, hawk_oow_t len);
|
||||
const hawk_ooch_t* name, const hawk_bch_t* str, hawk_oow_t len);
|
||||
|
||||
int hawk_rtx_flushio (
|
||||
hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_ooch_t* name);
|
||||
|
||||
@@ -1138,7 +1138,7 @@ int hawk_rtx_readiobytes (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_oo
|
||||
}
|
||||
|
||||
|
||||
int hawk_rtx_writeioval (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_ooch_t* name, hawk_val_t* v)
|
||||
int hawk_rtx_writeioval (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_ooch_t* name, const hawk_val_t* v)
|
||||
{
|
||||
hawk_val_type_t vtype;
|
||||
vtype = HAWK_RTX_GETVALTYPE(rtx, v);
|
||||
@@ -1275,7 +1275,7 @@ static int prepare_for_write_io_data (hawk_rtx_t* rtx, hawk_out_type_t out_type,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hawk_rtx_writeiostr (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_ooch_t* name, hawk_ooch_t* str, hawk_oow_t len)
|
||||
int hawk_rtx_writeiostr (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_ooch_t* name, const hawk_ooch_t* str, hawk_oow_t len)
|
||||
{
|
||||
int x;
|
||||
write_io_data_t wid;
|
||||
@@ -1286,7 +1286,7 @@ int hawk_rtx_writeiostr (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_o
|
||||
{
|
||||
hawk_ooi_t n;
|
||||
|
||||
n = wid.handler(rtx, HAWK_RIO_CMD_WRITE, wid.p, str, len);
|
||||
n = wid.handler(rtx, HAWK_RIO_CMD_WRITE, wid.p, (void*)str, len);
|
||||
if (n <= -1) return -1;
|
||||
|
||||
if (n == 0)
|
||||
@@ -1302,7 +1302,7 @@ int hawk_rtx_writeiostr (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_o
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hawk_rtx_writeiobytes (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_ooch_t* name, hawk_bch_t* str, hawk_oow_t len)
|
||||
int hawk_rtx_writeiobytes (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_ooch_t* name, const hawk_bch_t* str, hawk_oow_t len)
|
||||
{
|
||||
int x;
|
||||
write_io_data_t wid;
|
||||
@@ -1313,7 +1313,7 @@ int hawk_rtx_writeiobytes (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk
|
||||
{
|
||||
hawk_ooi_t n;
|
||||
|
||||
n = wid.handler(rtx, HAWK_RIO_CMD_WRITE_BYTES, wid.p, str, len);
|
||||
n = wid.handler(rtx, HAWK_RIO_CMD_WRITE_BYTES, wid.p, (void*)str, len);
|
||||
if (n <= -1) return -1;
|
||||
|
||||
if (n == 0)
|
||||
|
||||
@@ -84,6 +84,7 @@ static int init_globals (hawk_rtx_t* rtx);
|
||||
static void refdown_globals (hawk_rtx_t* rtx, int pop);
|
||||
|
||||
static void fbc_eval_stack_fini (hawk_rtx_t* rtx, hawk_fbc_eval_stack_t* stack);
|
||||
static hawk_val_t* fbc_eval_stack_pop (hawk_fbc_eval_stack_t* stack);
|
||||
|
||||
static int run_pblocks (hawk_rtx_t* rtx);
|
||||
static int run_pblock_chain (hawk_rtx_t* rtx, hawk_chain_t* cha);
|
||||
@@ -1463,12 +1464,12 @@ hawk_mod_t* hawk_rtx_querymodulewithoocs (hawk_rtx_t* rtx, const hawk_oocs_t* na
|
||||
/* the logic here must match hawk_querymodulewithoocs() in parse.c */
|
||||
dc = hawk_find_oochars_in_oochars(name->ptr, name->len, HAWK_T("::"), 2, 0);
|
||||
HAWK_ASSERT(dc != HAWK_NULL);
|
||||
if (HAWK_UNLIKELY(!dc)) goto internal_error_unrolling;
|
||||
if (HAWK_UNLIKELY(!dc)) goto internal_error_unrolling; /* this must not happend but .. */
|
||||
len = dc - name->ptr;
|
||||
|
||||
pair = hawk_rbt_search(rtx->modtab, name->ptr, len);
|
||||
HAWK_ASSERT(pair != HAWK_NULL);
|
||||
if (HAWK_UNLIKELY(!pair))
|
||||
if (HAWK_UNLIKELY(!pair)) /* this must not happen but .. */
|
||||
{
|
||||
internal_error_unrolling:
|
||||
hawk_rtx_seterrbfmt(rtx, HAWK_NULL, HAWK_EINTERN,
|
||||
@@ -1480,9 +1481,9 @@ hawk_mod_t* hawk_rtx_querymodulewithoocs (hawk_rtx_t* rtx, const hawk_oocs_t* na
|
||||
/* skip the fini callback because the init callback returned failure. not calling m->fini().
|
||||
* invoke the unload() callback if needed and unload the module itself. */
|
||||
hawk_modtab_unload_module(rtx->modtab, pair, rtx->hawk);
|
||||
hawk_rbt_delete(rtx->modtab, name->ptr, len);
|
||||
}
|
||||
|
||||
hawk_rbt_delete(rtx->modtab, name->ptr, len);
|
||||
m = HAWK_NULL; /* indicate failure */
|
||||
}
|
||||
}
|
||||
@@ -1493,7 +1494,7 @@ hawk_mod_t* hawk_rtx_querymodulewithoocs (hawk_rtx_t* rtx, const hawk_oocs_t* na
|
||||
hawk_mod_t* hawk_rtx_querymodulewithname (hawk_rtx_t* rtx, const hawk_ooch_t* name, hawk_mod_sym_t* sym, int flags)
|
||||
{
|
||||
hawk_oocs_t oocs;
|
||||
oocs.ptr = name;
|
||||
oocs.ptr = (hawk_ooch_t*)name;
|
||||
oocs.len = hawk_count_oocstr(name);
|
||||
return hawk_rtx_querymodulewithoocs(rtx, &oocs, sym, flags);
|
||||
}
|
||||
@@ -1717,7 +1718,6 @@ static int run_blocks_for_bpae_loop (hawk_rtx_t* rtx, hawk_nde_t* blk_head, int
|
||||
|
||||
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;
|
||||
@@ -2668,15 +2668,10 @@ static int call_signal_handlers (hawk_rtx_t* rtx)
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
static int run_statement (hawk_rtx_t* rtx, hawk_nde_t* nde)
|
||||
static HAWK_INLINE int run_pending_signal_handlers (hawk_rtx_t* rtx)
|
||||
{
|
||||
int xret;
|
||||
hawk_val_t* tmp;
|
||||
if (rtx->sig_handling) return 0;
|
||||
|
||||
ON_STATEMENT(rtx, nde);
|
||||
|
||||
if (!rtx->sig_handling)
|
||||
{
|
||||
/* run singal handlers if there are raised signals */
|
||||
#if defined(HAWK_ATOMIC_LOAD)
|
||||
if (HAWK_ATOMIC_LOAD(&rtx->sig_pending_any, HAWK_ATOMIC_RELAXED) != 0 &&
|
||||
@@ -2689,8 +2684,18 @@ static int run_statement (hawk_rtx_t* rtx, hawk_nde_t* nde)
|
||||
* modern compilers should support the atomic primitives. */
|
||||
if (rtx->sig_pending_any && call_signal_handlers(rtx) <= -1) return -1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_statement (hawk_rtx_t* rtx, hawk_nde_t* nde)
|
||||
{
|
||||
int xret;
|
||||
hawk_val_t* tmp;
|
||||
|
||||
ON_STATEMENT(rtx, nde);
|
||||
if (run_pending_signal_handlers(rtx) <= -1) return -1;
|
||||
|
||||
/* run the actual statement */
|
||||
switch (nde->type)
|
||||
{
|
||||
@@ -3862,9 +3867,7 @@ static int run_reset (hawk_rtx_t* rtx, hawk_nde_reset_t* nde)
|
||||
}
|
||||
}
|
||||
|
||||
static int io_val_to_str (
|
||||
hawk_rtx_t* rtx, hawk_val_t* v, const hawk_loc_t* loc,
|
||||
hawk_oocs_t* dst, int seterr)
|
||||
static int io_val_to_str (hawk_rtx_t* rtx, hawk_val_t* v, const hawk_loc_t* loc, hawk_oocs_t* dst, int seterr)
|
||||
{
|
||||
dst->ptr = hawk_rtx_getvaloocstr(rtx, v, &dst->len);
|
||||
if (HAWK_UNLIKELY(!dst->ptr)) return -1;
|
||||
@@ -3910,9 +3913,7 @@ static hawk_val_t* io_nde_to_str(hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_oocs_t*
|
||||
return v;
|
||||
}
|
||||
|
||||
static int fbc_write_print_str (
|
||||
hawk_rtx_t* rtx, hawk_nde_print_t* nde, const hawk_ooch_t* ptr, hawk_oow_t len,
|
||||
hawk_val_t* out_v)
|
||||
static int fbc_write_print_str (hawk_rtx_t* rtx, hawk_nde_print_t* nde, const hawk_ooch_t* ptr, hawk_oow_t len, hawk_val_t* out_v)
|
||||
{
|
||||
hawk_oocs_t out;
|
||||
int n;
|
||||
@@ -7602,10 +7603,8 @@ static hawk_val_t* eval_fncall_fnc (hawk_rtx_t* rtx, hawk_nde_t* nde)
|
||||
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)
|
||||
static HAWK_INLINE hawk_fun_t* resolve_fncall_fun (hawk_rtx_t* rtx, hawk_nde_fncall_t* call)
|
||||
{
|
||||
/* user-defined function */
|
||||
hawk_nde_fncall_t* call = (hawk_nde_fncall_t*)nde;
|
||||
hawk_fun_t* fun;
|
||||
#if defined(HAWK_ATOMIC_CAS_BOOL)
|
||||
hawk_fun_t* expected;
|
||||
@@ -7628,7 +7627,7 @@ static HAWK_INLINE hawk_val_t* eval_fncall_fun (hawk_rtx_t* rtx, hawk_nde_t* nde
|
||||
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);
|
||||
hawk_rtx_seterrfmt(rtx, &call->loc, HAWK_EFUNNF, HAWK_T("function '%.*js' not found"), call->u.fun.name.len, call->u.fun.name.ptr);
|
||||
return HAWK_NULL;
|
||||
}
|
||||
|
||||
@@ -7661,12 +7660,22 @@ static HAWK_INLINE hawk_val_t* eval_fncall_fun (hawk_rtx_t* rtx, hawk_nde_t* nde
|
||||
|
||||
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);
|
||||
hawk_rtx_seterrfmt(rtx, &call->loc, HAWK_EARGTM, HAWK_T("too many arguments to '%.*js'"), fun->name.len, fun->name.ptr);
|
||||
return HAWK_NULL;
|
||||
}
|
||||
|
||||
return fun;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
fun = resolve_fncall_fun(rtx, call);
|
||||
if (!fun) 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
|
||||
@@ -7747,6 +7756,114 @@ static hawk_val_t* eval_fncall_var (hawk_rtx_t* rtx, hawk_nde_t* nde)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static hawk_val_t* fbc_eval_call (hawk_rtx_t* rtx, hawk_fbc_eval_stack_t* evstk, hawk_nde_fncall_t* call)
|
||||
{
|
||||
hawk_val_t* args_fixed[8];
|
||||
hawk_val_t** args = args_fixed;
|
||||
hawk_val_t* callee_val = HAWK_NULL;
|
||||
hawk_val_t* rv = HAWK_NULL;
|
||||
hawk_fun_t* fun = HAWK_NULL;
|
||||
struct pafv_t pafv;
|
||||
hawk_oow_t i;
|
||||
|
||||
if (!call)
|
||||
{
|
||||
hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EINTERN);
|
||||
return HAWK_NULL;
|
||||
}
|
||||
|
||||
if (call->nargs > HAWK_COUNTOF(args_fixed))
|
||||
{
|
||||
args = (hawk_val_t**)hawk_rtx_allocmem(rtx, call->nargs * HAWK_SIZEOF(*args));
|
||||
if (HAWK_UNLIKELY(!args)) return HAWK_NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < call->nargs; i++) args[i] = HAWK_NULL;
|
||||
for (i = call->nargs; i > 0; i--)
|
||||
{
|
||||
args[i - 1] = fbc_eval_stack_pop(evstk);
|
||||
if (!args[i - 1])
|
||||
{
|
||||
hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EINTERN);
|
||||
goto oops;
|
||||
}
|
||||
}
|
||||
|
||||
/* this function combines the subset of these three functions:
|
||||
* eval_fncall_fnc(), eval_fncall_fun(), eval_fncall_var() */
|
||||
switch (call->type)
|
||||
{
|
||||
case HAWK_NDE_FNCALL_FNC: /* builtin function */
|
||||
if (call->u.fnc.flags & HAWK_NDE_FNCALL_FNC_DEFERRED_MODFNC)
|
||||
{
|
||||
hawk_rtx_seterrnum(rtx, &call->loc, HAWK_EINTERN);
|
||||
goto oops;
|
||||
}
|
||||
HAWK_ASSERT(call->nargs >= call->u.fnc.spec.arg.min && call->nargs <= call->u.fnc.spec.arg.max);
|
||||
break;
|
||||
|
||||
case HAWK_NDE_FNCALL_FUN: /* pure hawk function */
|
||||
fun = resolve_fncall_fun(rtx, call);
|
||||
if (!fun) goto oops;
|
||||
break;
|
||||
|
||||
case HAWK_NDE_FNCALL_EXPR: /* function pointed to by another variable or a return value of another call, etc */
|
||||
callee_val = fbc_eval_stack_pop(evstk); /* the stack top has the callee expression result */
|
||||
if (!callee_val)
|
||||
{
|
||||
hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EINTERN);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
fun = hawk_rtx_valtofun(rtx, callee_val);
|
||||
if (!fun)
|
||||
{
|
||||
if (hawk_rtx_geterrnum(rtx) == HAWK_EINVAL)
|
||||
{
|
||||
if (nde_is_var(call->u.expr.callable))
|
||||
{
|
||||
hawk_nde_var_t* v = (hawk_nde_var_t*)call->u.expr.callable;
|
||||
hawk_rtx_seterrfmt(rtx, &call->loc, HAWK_ENOTFUN, HAWK_T("non-function value in '%.*js'"), v->id.name.len, v->id.name.ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
hawk_rtx_seterrnum(rtx, &call->loc, HAWK_ENOTFUN);
|
||||
}
|
||||
}
|
||||
ADJERR_LOC(rtx, &call->loc);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (call->nargs > fun->nargs && !fun->variadic)
|
||||
{
|
||||
hawk_rtx_seterrfmt(rtx, &call->loc, HAWK_EARGTM, HAWK_T("too many arguments to '%.*js'"), fun->name.len, fun->name.ptr);
|
||||
goto oops;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
hawk_rtx_seterrnum(rtx, &call->loc, HAWK_EINTERN);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
/* TODO: this implementation is extremely inefficient... we must be able to call hawk_rtx_evalcall without push_arg_from_vals... */
|
||||
pafv.args = args;
|
||||
pafv.nargs = call->nargs;
|
||||
pafv.argspec = HAWK_NULL;
|
||||
pafv.argspeclen = 0;
|
||||
|
||||
rv = hawk_rtx_evalcall(rtx, call, fun, push_arg_from_vals, (void*)&pafv, HAWK_NULL, HAWK_NULL);
|
||||
|
||||
oops:
|
||||
if (callee_val) hawk_rtx_refdownval(rtx, callee_val);
|
||||
for (i = 0; i < call->nargs; i++)
|
||||
{
|
||||
if (args[i]) hawk_rtx_refdownval(rtx, args[i]);
|
||||
}
|
||||
if (args != args_fixed) hawk_rtx_freemem(rtx, args);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void fbc_eval_stack_unwind (hawk_rtx_t* rtx, hawk_fbc_eval_stack_t* stack, hawk_oow_t base)
|
||||
{
|
||||
while (stack->len > base)
|
||||
@@ -7882,6 +7999,8 @@ static int run_funbc (hawk_rtx_t* rtx, hawk_fun_t* fun)
|
||||
hawk_fbc_ins_t* ins = &bc->code[pc];
|
||||
hawk_val_t* val;
|
||||
|
||||
if (HAWK_UNLIKELY(run_pending_signal_handlers(rtx) <= -1)) goto oops;
|
||||
|
||||
/*hawk_logbfmt(rtx->hawk, HAWK_LOG_STDERR, "opcode = 0x%x [%d]\n", ins->opcode, ins->opcode);*/
|
||||
switch (ins->opcode)
|
||||
{
|
||||
@@ -8252,6 +8371,12 @@ static int run_funbc (hawk_rtx_t* rtx, hawk_fun_t* fun)
|
||||
hawk_rtx_refdownval(rtx, val);
|
||||
break;
|
||||
|
||||
case HAWK_FBC_OP_CALL:
|
||||
val = fbc_eval_call(rtx, evstk, (hawk_nde_fncall_t*)ins->u.nde);
|
||||
if (HAWK_UNLIKELY(!val)) goto oops;
|
||||
if (fbc_eval_stack_push(rtx, evstk, val) <= -1) goto oops;
|
||||
break;
|
||||
|
||||
case HAWK_FBC_OP_RET:
|
||||
val = fbc_eval_stack_pop(evstk);
|
||||
if (!val)
|
||||
|
||||
+1
-1
@@ -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-021.hawk h-022.hawk h-023.hawk
|
||||
|
||||
check_SCRIPTS += regress-filename.sh
|
||||
|
||||
|
||||
+1
-1
@@ -650,7 +650,7 @@ LIBADD_COMMON = ../lib/libhawk.la $(LIBM)
|
||||
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 regress-filename.sh
|
||||
h-020.hawk h-021.hawk h-022.hawk h-023.hawk regress-filename.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 \
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
@pragma implicit off
|
||||
@pragma pedantic on
|
||||
@pragma entry main
|
||||
@pragma xcall on
|
||||
|
||||
@include "tap.inc";
|
||||
|
||||
@global G = func(a, b) {
|
||||
return a + b
|
||||
}
|
||||
|
||||
@global seq;
|
||||
|
||||
function mark(v)
|
||||
{
|
||||
seq = seq sprintf("%d", v);
|
||||
return v;
|
||||
}
|
||||
|
||||
function pair(a, b)
|
||||
{
|
||||
return a * 10 + b;
|
||||
}
|
||||
|
||||
function zero()
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
|
||||
function bump(&x)
|
||||
{
|
||||
x += 1;
|
||||
return x;
|
||||
}
|
||||
|
||||
function main()
|
||||
{
|
||||
@local v, s, f;
|
||||
|
||||
seq = "";
|
||||
tap_ensure(pair(mark(1), mark(2)), 12, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(seq, "12", @SCRIPTNAME, @SCRIPTLINE);
|
||||
|
||||
tap_ensure(zero(), 7, @SCRIPTNAME, @SCRIPTLINE);
|
||||
|
||||
s = sprintf("%d/%d", pair(3, 4), zero());
|
||||
tap_ensure(s, "34/7", @SCRIPTNAME, @SCRIPTLINE);
|
||||
|
||||
tap_ensure(G(5, 6), 11, @SCRIPTNAME, @SCRIPTLINE);
|
||||
f = G;
|
||||
tap_ensure(f(7, 8), 15, @SCRIPTNAME, @SCRIPTLINE);
|
||||
|
||||
v = 9;
|
||||
tap_ensure(bump(v), 10, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(v, 10, @SCRIPTNAME, @SCRIPTLINE);
|
||||
|
||||
tap_end();
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
@pragma entry main
|
||||
@pragma implicit off
|
||||
|
||||
@include "tap.inc";
|
||||
|
||||
@global g_calls = 0;
|
||||
|
||||
function tick (v)
|
||||
{
|
||||
g_calls = g_calls + 1;
|
||||
return v;
|
||||
}
|
||||
|
||||
function main ()
|
||||
{
|
||||
@local i, j, k, l, m, n, o, p, q, r;
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
k = 0;
|
||||
l = 0;
|
||||
m = 0;
|
||||
n = 0;
|
||||
o = 0;
|
||||
p = 0;
|
||||
q = 0;
|
||||
r = 0;
|
||||
|
||||
while (0) { i = i + 1; }
|
||||
while (@false) { j = j + 1; }
|
||||
while ((0)) { k = k + 1; }
|
||||
while ((@false)) { l = l + 1; }
|
||||
|
||||
tap_ensure(i, 0, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(j, 0, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(k, 0, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(l, 0, @SCRIPTNAME, @SCRIPTLINE);
|
||||
|
||||
if ((1, 0))
|
||||
m = 1;
|
||||
else
|
||||
m = 2;
|
||||
|
||||
if (((0, "", 5)))
|
||||
n = 1;
|
||||
else
|
||||
n = 2;
|
||||
|
||||
if (((1, 2, @false)))
|
||||
o = 1;
|
||||
else
|
||||
o = 2;
|
||||
|
||||
if ((((1, 2), (3, 4), 0)))
|
||||
p = 1;
|
||||
else
|
||||
p = 2;
|
||||
|
||||
while ((1, 0)) { q = q + 1; }
|
||||
while ((((1, 2), (3, 4), 0))) { r = r + 1; }
|
||||
|
||||
tap_ensure(m, 2, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(n, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(o, 2, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(p, 2, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(q, 0, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE);
|
||||
|
||||
tap_ensure(2 ^ 10, 1024, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(2 ^ -3, 0.125, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(7.5 \ 2, 3, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(8.5 / 2, 4.25, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(17 % 5, 2, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(17.5 % 5, 2.5, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(6 & 3, 2, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(6 ^^ 3, 5, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(6 | 3, 7, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(3 << 4, 48, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(48 >> 4, 3, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(6.9 & 3, 2, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(8 >> 1.9, 4, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(2 == 2.0, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(2 != 2.0, 0, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(2 < 2.5, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(2.5 >= 2, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(2 === 2.0, 0, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(2 !== 2.0, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(!@true === @false, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(!@false === @true, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(!@nil === @true, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(!"" === @true, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(!"x" === @false, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(!@b"" === @true, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(!@b"x" === @false, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(!((1, 0)) === @true, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(!((1, 2, "x")) === @false, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
|
||||
g_calls = 0;
|
||||
if ((tick(1), 0))
|
||||
m = 10;
|
||||
else
|
||||
m = 20;
|
||||
tap_ensure(m, 20, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(g_calls, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
|
||||
g_calls = 0;
|
||||
if ((((1, tick(0))), 1))
|
||||
n = 10;
|
||||
else
|
||||
n = 20;
|
||||
tap_ensure(n, 10, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(g_calls, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
|
||||
g_calls = 0;
|
||||
while ((tick(1), 0)) { o = o + 1; }
|
||||
tap_ensure(o, 2, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(g_calls, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
|
||||
g_calls = 0;
|
||||
tap_ensure(!(tick(1), 0) === @true, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
tap_ensure(g_calls, 1, @SCRIPTNAME, @SCRIPTLINE);
|
||||
|
||||
tap_end ();
|
||||
}
|
||||
Reference in New Issue
Block a user