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 */ * no variable declaration if not enclosed in parentheses */
#define LANG_LIMIT_DO #define LANG_LIMIT_DO
#define FOR_NONE (0)
#define FOR_IF (1)
#define FOR_TRY (2)
enum enum
{ {
VAR_NAMED, 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; 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: no_block:
hcl_setsynerrbfmt ( 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, 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; 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); cdr = HCL_CNODE_CONS_CDR(c);
if (cdr) if (cdr)
{ {
/* there is redundant expression after the block expression */ /* 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; hcl_cnode_t* nxt;
nxt = HCL_CNODE_CONS_CAR(cdr); nxt = HCL_CNODE_CONS_CAR(cdr);
if (for_what == FOR_IF)
{
/* after the body for `if` or `elif`, there can come `elif` or `else` */
if (HCL_CNODE_IS_SYMBOL(nxt)) if (HCL_CNODE_IS_SYMBOL(nxt))
{ {
int syncode = HCL_CNODE_SYMBOL_SYNCODE(nxt); int syncode = HCL_CNODE_SYMBOL_SYNCODE(nxt);
if (syncode == HCL_SYNCODE_ELIF || syncode == HCL_SYNCODE_ELSE) goto ok; 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_setsynerrbfmt (
hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(cdr), HCL_NULL, 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; return -1;
} }
@ -2154,7 +2178,7 @@ static int compile_if (hcl_t* hcl, hcl_cnode_t* src)
if (!obj) if (!obj)
{ {
/* no value */ /* 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; return -1;
} }
else if (!HCL_CNODE_IS_CONS(obj)) else if (!HCL_CNODE_IS_CONS(obj))
@ -2255,7 +2279,7 @@ static HCL_INLINE int compile_elif (hcl_t* hcl)
if (!obj) if (!obj)
{ {
/* no value */ /* 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; return -1;
} }
else if (!HCL_CNODE_IS_CONS(obj)) 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 (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); 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 (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; 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; hcl_cnode_t* blk;
blk = HCL_CNODE_CONS_CDR(obj); 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; obj = blk;
nlvars = 0; /* no known local variables until the actual block is processed */ 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) * (perform yyy)
* ) * )
*/ */
cmd = HCL_CNODE_CONS_CDR(src); cmd = HCL_CNODE_CONS_CAR(src);
obj = HCL_CNODE_CONS_CDR(src); obj = HCL_CNODE_CONS_CDR(src);
if (!obj) if (!obj)
@ -3408,6 +3432,11 @@ static int compile_try (hcl_t* hcl, hcl_cnode_t* src)
jump_inst_pos = hcl->code.bc.len; 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 (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*/ SWITCH_TOP_CFRAME (hcl, COP_COMPILE_TRY_OBJECT_LIST, obj); /* 1*/
PUSH_SUBCFRAME (hcl, COP_POST_TRY, cmd); /* 2 */ PUSH_SUBCFRAME (hcl, COP_POST_TRY, cmd); /* 2 */
cf = GET_SUBCFRAME(hcl); cf = GET_SUBCFRAME(hcl);
@ -3479,7 +3508,7 @@ static HCL_INLINE int compile_catch (hcl_t* hcl)
if (!obj) if (!obj)
{ {
/* TODO: change error code */ /* 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; return -1;
} }
else if (!HCL_CNODE_IS_CONS(obj)) 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); HCL_ASSERT (hcl, fbi->tmpr_nargs + fbi->tmpr_nrvars + fbi->tmpr_nlvars == fbi->tmprcnt - par_tmprcnt);
obj = HCL_CNODE_CONS_CDR(obj); 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. if (check_block_expression_as_body(hcl, obj, cmd, FOR_NONE) <= -1) return -1;
* 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;
} }
/* jump_inst_pos hold the instruction pointer that skips the catch block at the end of the try block */ /* 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 (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 */ 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 (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 */ 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) 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 else
{ {
@ -1558,8 +1558,8 @@ static int feed_process_token (hcl_t* hcl)
#endif #endif
} }
} }
rbrace_ok:
rbrace_ok:
concode = LIST_FLAG_GET_CONCODE(frd->flagv); concode = LIST_FLAG_GET_CONCODE(frd->flagv);
if (concode == HCL_CONCODE_XLIST && (frd->flagv & AUTO_FORGED)) 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)); hcl_setsynerr (hcl, cons_info[concode].synerr, TOKEN_LOC(hcl), TOKEN_NAME(hcl));
goto oops; goto oops;
} }
#if 0 #if 0
if ((flagv & QUOTED) || frd->level <= 0) if ((flagv & QUOTED) || frd->level <= 0)
{ {
@ -2988,6 +2987,7 @@ not_consumed:
static int feed_char (hcl_t* hcl, hcl_ooci_t c) 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));*/ /*hcl_logbfmt (hcl, HCL_LOG_STDERR, "FEED->[%jc] %d STATE->%d\n", c, c, FLX_STATE(hcl));*/
switch (FLX_STATE(hcl)) switch (FLX_STATE(hcl))
{ {
case HCL_FLX_START: return flx_start(hcl, c); 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); x = feed_char(hcl, HCL_OOCI_EOF);
if (x <= -1) 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. /* 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); * 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 { try {
throw "excetion message" throw "excetion message"
} catch (e a) { ##ERROR: syntax error - not proper exception variable } 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