enhanced compile_return() to handle 'return' differently in a function block containing return variables

This commit is contained in:
hyung-hwan 2021-05-13 15:54:30 +00:00
parent 550e39e21e
commit ebda2ffa0a
3 changed files with 53 additions and 25 deletions

View File

@ -1893,16 +1893,41 @@ static int compile_return (hcl_t* hcl, hcl_cnode_t* src, int ret_from_home)
{ {
hcl_cnode_t* obj, * val; hcl_cnode_t* obj, * val;
hcl_cframe_t* cf; hcl_cframe_t* cf;
hcl_fnblk_info_t* fbi;
HCL_ASSERT (hcl, HCL_CNODE_IS_CONS(src)); HCL_ASSERT (hcl, HCL_CNODE_IS_CONS(src));
HCL_ASSERT (hcl, HCL_CNODE_IS_SYMBOL_SYNCODED(HCL_CNODE_CONS_CAR(src), HCL_SYNCODE_RETURN) || HCL_ASSERT (hcl, HCL_CNODE_IS_SYMBOL_SYNCODED(HCL_CNODE_CONS_CAR(src), HCL_SYNCODE_RETURN) ||
HCL_CNODE_IS_SYMBOL_SYNCODED(HCL_CNODE_CONS_CAR(src), HCL_SYNCODE_RETURN_FROM_HOME)); HCL_CNODE_IS_SYMBOL_SYNCODED(HCL_CNODE_CONS_CAR(src), HCL_SYNCODE_RETURN_FROM_HOME));
fbi = &hcl->c->fnblk.info[hcl->c->fnblk.depth];
obj = HCL_CNODE_CONS_CDR(src); obj = HCL_CNODE_CONS_CDR(src);
if (fbi->tmpr_nrvars > 0)
{
hcl_cnode_t* tmp = HCL_CNODE_CONS_CAR(src);
if (ret_from_home)
{
hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(src), HCL_NULL, "%.*js not compatible with return variables", HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp));
return -1;
}
/* if a return variable are specified in the current function block, the return statement must not be followed by a return value */
if (obj)
{
hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(src), HCL_NULL, "use of return value in %.*js not compatible with return variables", HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp));
return -1;
}
/* TODO: pop stack if this is not the first statement... */
if (emit_byte_instruction(hcl, HCL_CODE_PUSH_RETURN_R, HCL_CNODE_GET_LOC(tmp)) <= -1) return -1;
POP_CFRAME (hcl);
}
else
{
if (!obj) if (!obj)
{ {
/* TODO: should i allow (return)? does it return the last value on the stack? */ /* TODO: should i allow (return)? does it return the last value on the stack? */
/* no value */ /* no value */
hcl_cnode_t* tmp = HCL_CNODE_CONS_CAR(src); hcl_cnode_t* tmp = HCL_CNODE_CONS_CAR(src);
hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGCOUNT, HCL_CNODE_GET_LOC(src), HCL_NULL, "no value specified in %.*js", HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp)); hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGCOUNT, HCL_CNODE_GET_LOC(src), HCL_NULL, "no value specified in %.*js", HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp));
@ -1930,6 +1955,7 @@ static int compile_return (hcl_t* hcl, hcl_cnode_t* src, int ret_from_home)
PUSH_SUBCFRAME (hcl, COP_EMIT_RETURN, src); PUSH_SUBCFRAME (hcl, COP_EMIT_RETURN, src);
cf = GET_SUBCFRAME(hcl); cf = GET_SUBCFRAME(hcl);
cf->u._return.from_home = ret_from_home; cf->u._return.from_home = ret_from_home;
}
return 0; return 0;
} }

View File

@ -144,6 +144,7 @@ static char* synerrstr[] =
"duplicate variable name", "duplicate variable name",
"disallowed variable name", "disallowed variable name",
"disallowed argument name", "disallowed argument name",
"disallowed",
"elif without if", "elif without if",
"else without if", "else without if",

View File

@ -151,6 +151,7 @@ enum hcl_synerrnum_t
HCL_SYNERR_BANNEDVARNAME, /* disallowed varible name */ HCL_SYNERR_BANNEDVARNAME, /* disallowed varible name */
HCL_SYNERR_BANNEDARGNAME, /* disallowed argument name */ HCL_SYNERR_BANNEDARGNAME, /* disallowed argument name */
HCL_SYNERR_BANNED, /* prohibited */
HCL_SYNERR_ELIF, /* elif without if */ HCL_SYNERR_ELIF, /* elif without if */
HCL_SYNERR_ELSE, /* else without if */ HCL_SYNERR_ELSE, /* else without if */