fixed the compiler's check for block expression after if, elif, else, try, catch
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
hyung-hwan 2024-04-13 00:48:23 +09:00
parent 2437fadedf
commit 637e8ba3c4
3 changed files with 107 additions and 27 deletions

View File

@ -28,6 +28,10 @@
* no variable declaration if not enclosed in parentheses */
#define LANG_LIMIT_DO
#define FOR_NONE (0)
#define FOR_IF (1)
#define FOR_TRY (2)
enum
{
VAR_NAMED,
@ -443,7 +447,7 @@ static int find_variable_backward_with_token (hcl_t* hcl, const hcl_cnode_t* cno
/* ========================================================================= */
static int check_block_expression_as_body (hcl_t* hcl, hcl_cnode_t* c, const hcl_cnode_t* ctx, int for_if)
static int check_block_expression_as_body (hcl_t* hcl, hcl_cnode_t* c, const hcl_cnode_t* ctx, int for_what)
{
hcl_cnode_t* car = HCL_NULL, * cdr;
@ -462,30 +466,50 @@ static int check_block_expression_as_body (hcl_t* hcl, hcl_cnode_t* c, const hcl
no_block:
hcl_setsynerrbfmt (
hcl, HCL_SYNERR_BLOCK, (car? HCL_CNODE_GET_LOC(car): c? HCL_CNODE_GET_LOC(c): HCL_CNODE_GET_LOC(ctx)), HCL_NULL,
"block expression expected as body for %.*js", HCL_CNODE_GET_TOKLEN(ctx), HCL_CNODE_GET_TOKPTR(ctx)
"block expression expected as '%.*js' body", HCL_CNODE_GET_TOKLEN(ctx), HCL_CNODE_GET_TOKPTR(ctx)
);
return -1;
}
/* there are special words that can't start a new expression */
if (HCL_CNODE_IS_SYMBOL_SYNCODED(car, HCL_SYNCODE_ELIF) ||
HCL_CNODE_IS_SYMBOL_SYNCODED(car, HCL_SYNCODE_ELSE) ||
HCL_CNODE_IS_SYMBOL_SYNCODED(car, HCL_SYNCODE_CATCH))
{
goto no_block;
}
cdr = HCL_CNODE_CONS_CDR(c);
if (cdr)
{
/* there is redundant expression after the block expression */
if (for_if && HCL_CNODE_IS_CONS(cdr))
if (HCL_CNODE_IS_CONS(cdr))
{
/* after the body for `if` or `elif`, there can come `elif` or `else` */
hcl_cnode_t* nxt;
nxt = HCL_CNODE_CONS_CAR(cdr);
if (HCL_CNODE_IS_SYMBOL(nxt))
if (for_what == FOR_IF)
{
int syncode = HCL_CNODE_SYMBOL_SYNCODE(nxt);
if (syncode == HCL_SYNCODE_ELIF || syncode == HCL_SYNCODE_ELSE) goto ok;
/* after the body for `if` or `elif`, there can come `elif` or `else` */
if (HCL_CNODE_IS_SYMBOL(nxt))
{
int syncode = HCL_CNODE_SYMBOL_SYNCODE(nxt);
if (syncode == HCL_SYNCODE_ELIF || syncode == HCL_SYNCODE_ELSE) goto ok;
}
}
else if (for_what == FOR_TRY)
{
if (HCL_CNODE_IS_SYMBOL(nxt))
{
int syncode = HCL_CNODE_SYMBOL_SYNCODE(nxt);
if (syncode == HCL_SYNCODE_CATCH) goto ok;
}
}
}
hcl_setsynerrbfmt (
hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(cdr), HCL_NULL,
"redundant code prohibited after body for %.*js", HCL_CNODE_GET_TOKLEN(ctx), HCL_CNODE_GET_TOKPTR(ctx)
"redundant expression prohibited after '%.*js' body", HCL_CNODE_GET_TOKLEN(ctx), HCL_CNODE_GET_TOKPTR(ctx)
);
return -1;
}
@ -2154,7 +2178,7 @@ static int compile_if (hcl_t* hcl, hcl_cnode_t* src)
if (!obj)
{
/* no value */
hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGCOUNT, HCL_CNODE_GET_LOC(src), HCL_NULL, "no condition specified in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGCOUNT, HCL_CNODE_GET_LOC(src), HCL_NULL, "no conditional expression after %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
return -1;
}
else if (!HCL_CNODE_IS_CONS(obj))
@ -2255,7 +2279,7 @@ static HCL_INLINE int compile_elif (hcl_t* hcl)
if (!obj)
{
/* no value */
hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGCOUNT, HCL_CNODE_GET_LOC(src), HCL_NULL, "no condition in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGCOUNT, HCL_CNODE_GET_LOC(src), HCL_NULL, "no conditional expression after %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
return -1;
}
else if (!HCL_CNODE_IS_CONS(obj))
@ -2301,7 +2325,7 @@ static HCL_INLINE int compile_else (hcl_t* hcl)
if (hcl->option.trait & HCL_TRAIT_LANG_ENABLE_BLOCK)
{
if (check_block_expression_as_body(hcl, obj, cmd, 0) <= -1) return -1;
if (check_block_expression_as_body(hcl, obj, cmd, FOR_NONE) <= -1) return -1;
}
SWITCH_TOP_CFRAME (hcl, COP_COMPILE_OBJECT_LIST, obj);
@ -2592,7 +2616,7 @@ static HCL_INLINE int compile_class_p1 (hcl_t* hcl)
if (hcl->option.trait & HCL_TRAIT_LANG_ENABLE_BLOCK)
{
if (check_block_expression_as_body(hcl, obj, cf->u._class.cmd_cnode, 0) <= -1) return -1;
if (check_block_expression_as_body(hcl, obj, cf->u._class.cmd_cnode, FOR_NONE) <= -1) return -1;
}
if (push_clsblk(hcl, &cf->u._class.start_loc, nivars, ncvars, &hcl->c->tv.s.ptr[ivar_start], ivar_len, &hcl->c->tv.s.ptr[cvar_start], cvar_len) <= -1) goto oops;
@ -3001,7 +3025,7 @@ static int compile_lambda (hcl_t* hcl, hcl_cnode_t* src, int defun)
*/
hcl_cnode_t* blk;
blk = HCL_CNODE_CONS_CDR(obj);
if (check_block_expression_as_body(hcl, blk, cmd, 0) <= -1) return -1;
if (check_block_expression_as_body(hcl, blk, cmd, FOR_NONE) <= -1) return -1;
obj = blk;
nlvars = 0; /* no known local variables until the actual block is processed */
}
@ -3386,7 +3410,7 @@ static int compile_try (hcl_t* hcl, hcl_cnode_t* src)
* (perform yyy)
* )
*/
cmd = HCL_CNODE_CONS_CDR(src);
cmd = HCL_CNODE_CONS_CAR(src);
obj = HCL_CNODE_CONS_CDR(src);
if (!obj)
@ -3408,6 +3432,11 @@ static int compile_try (hcl_t* hcl, hcl_cnode_t* src)
jump_inst_pos = hcl->code.bc.len;
if (emit_single_param_instruction(hcl, HCL_CODE_TRY_ENTER, MAX_CODE_JUMP, HCL_CNODE_GET_LOC(cmd)) <= -1) return -1;
if (hcl->option.trait & HCL_TRAIT_LANG_ENABLE_BLOCK)
{
if (check_block_expression_as_body(hcl, obj, cmd, FOR_TRY) <= -1) return -1;
}
SWITCH_TOP_CFRAME (hcl, COP_COMPILE_TRY_OBJECT_LIST, obj); /* 1*/
PUSH_SUBCFRAME (hcl, COP_POST_TRY, cmd); /* 2 */
cf = GET_SUBCFRAME(hcl);
@ -3479,7 +3508,7 @@ static HCL_INLINE int compile_catch (hcl_t* hcl)
if (!obj)
{
/* TODO: change error code */
hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(src), HCL_NULL, "no exception variable in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(src), HCL_NULL, "no exception variable for '%.*js'", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
return -1;
}
else if (!HCL_CNODE_IS_CONS(obj))
@ -3533,12 +3562,9 @@ static HCL_INLINE int compile_catch (hcl_t* hcl)
HCL_ASSERT (hcl, fbi->tmpr_nargs + fbi->tmpr_nrvars + fbi->tmpr_nlvars == fbi->tmprcnt - par_tmprcnt);
obj = HCL_CNODE_CONS_CDR(obj);
if (!obj)
if (hcl->option.trait & HCL_TRAIT_LANG_ENABLE_BLOCK)
{
/* the error message is no exception handler. but what is expected is an expression.
* e.g. a number, nil, a block expression, etc */
hcl_setsynerrbfmt (hcl, HCL_SYNERR_NOVALUE, HCL_CNODE_GET_LOC(exarg), HCL_NULL, "no exception handler after %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
return -1;
if (check_block_expression_as_body(hcl, obj, cmd, FOR_NONE) <= -1) return -1;
}
/* jump_inst_pos hold the instruction pointer that skips the catch block at the end of the try block */
@ -3688,7 +3714,7 @@ static int compile_while (hcl_t* hcl, hcl_cnode_t* src, int next_cop)
if (hcl->option.trait & HCL_TRAIT_LANG_ENABLE_BLOCK)
{
if (check_block_expression_as_body(hcl, body, cmd, 0) <= -1) return -1;
if (check_block_expression_as_body(hcl, body, cmd, FOR_NONE) <= -1) return -1;
}
SWITCH_TOP_CFRAME (hcl, COP_COMPILE_OBJECT, cond); /* 1 */
@ -5090,7 +5116,7 @@ static HCL_INLINE int post_if_cond (hcl_t* hcl)
if (hcl->option.trait & HCL_TRAIT_LANG_ENABLE_BLOCK)
{
if (check_block_expression_as_body(hcl, cf->operand, cf->u.post_if.cmd_cnode, 1) <= -1) return -1;
if (check_block_expression_as_body(hcl, cf->operand, cf->u.post_if.cmd_cnode, FOR_IF) <= -1) return -1;
}
SWITCH_TOP_CFRAME (hcl, COP_COMPILE_IF_OBJECT_LIST, cf->operand); /* 1 */

View File

@ -577,7 +577,7 @@ static HCL_INLINE hcl_cnode_t* leave_list (hcl_t* hcl, hcl_loc_t* list_loc, int*
}
else if (concode == HCL_CONCODE_BLIST)
{
hcl_setsynerrbfmt (hcl, HCL_SYNERR_NOVALUE, TOKEN_LOC(hcl), HCL_NULL, "missing value after binary operator");
hcl_setsynerrbfmt (hcl, HCL_SYNERR_NOVALUE, TOKEN_LOC(hcl), HCL_NULL, "missing expression after binary operator");
}
else
{
@ -1558,8 +1558,8 @@ static int feed_process_token (hcl_t* hcl)
#endif
}
}
rbrace_ok:
rbrace_ok:
concode = LIST_FLAG_GET_CONCODE(frd->flagv);
if (concode == HCL_CONCODE_XLIST && (frd->flagv & AUTO_FORGED))
{
@ -1574,7 +1574,6 @@ static int feed_process_token (hcl_t* hcl)
hcl_setsynerr (hcl, cons_info[concode].synerr, TOKEN_LOC(hcl), TOKEN_NAME(hcl));
goto oops;
}
#if 0
if ((flagv & QUOTED) || frd->level <= 0)
{
@ -2988,6 +2987,7 @@ not_consumed:
static int feed_char (hcl_t* hcl, hcl_ooci_t c)
{
/*hcl_logbfmt (hcl, HCL_LOG_STDERR, "FEED->[%jc] %d STATE->%d\n", c, c, FLX_STATE(hcl));*/
switch (FLX_STATE(hcl))
{
case HCL_FLX_START: return flx_start(hcl, c);
@ -3268,7 +3268,8 @@ int hcl_feed (hcl_t* hcl, const hcl_ooch_t* data, hcl_oow_t len)
x = feed_char(hcl, HCL_OOCI_EOF);
if (x <= -1)
{
if (hcl->c->feed.rd.level <= 0 && HCL_ERRNUM(hcl) == HCL_ESYNERR && hcl_getsynerrnum(hcl) == HCL_SYNERR_EOF)
int exp_level = !(hcl->option.trait & HCL_TRAIT_LANG_ENABLE_EOL); /* 0 if EOL is on, 1 if EOL is off */
if (hcl->c->feed.rd.level <= exp_level && HCL_ERRNUM(hcl) == HCL_ESYNERR && hcl_getsynerrnum(hcl) == HCL_SYNERR_EOF)
{
/* convert this EOF error to success as the caller knows EOF in the feed mode.
* the caller can safely stop feeding after gettting success from hcl_feed(hcl, HCL_NULL, 0);

View File

@ -4,6 +4,53 @@
---
if ##ERROR: syntax error - no conditional expression after if
---
if (< 2 3) elif ##ERROR: syntax error - block expression expected as 'if' body
---
if (< 2 3) {} elif true else ##ERROR: syntax error - block expression expected as 'elif' body
---
if else ##ERROR: syntax error - special symbol not to be used as variable name
---
if elif else ##ERROR: syntax error - special symbol not to be used as variable name
---
if (< 20 30) ##ERROR: syntax error - block expression expected as 'if' body
---
if (< 20 30) {
printf "ok\n"
} { ##ERROR: syntax error - redundant expression prohibited after 'if' body
printf "ok2\n"
}
---
if (< 20 30) else { ##ERROR: syntax error - block expression expected as 'if' body
printf "ok\n"
}
---
catch (e) {} ##ERROR: syntax error - catch without try
---
try {} catch ##ERROR: syntax error - no exception variable for 'catch'
---
try {
throw "excetion message"
} catch (e a) { ##ERROR: syntax error - not proper exception variable
@ -12,4 +59,10 @@ try {
---
try { throw "1111"; } catch (e) ##ERROR: syntax error - no exception handler
try { throw "1111"; } catch (e) ##ERROR: syntax error - block expression expected as 'catch' body
---
try { throw "1111"; } catch (e) {
printf "EXCEPTION - %s\n" e
} 20 ##ERROR: syntax error - redundant expression prohibited after