From 637e8ba3c410dca714aa70cc367a72fe660827e0 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sat, 13 Apr 2024 00:48:23 +0900 Subject: [PATCH] fixed the compiler's check for block expression after if, elif, else, try, catch --- lib/comp.c | 70 +++++++++++++++++++++++++++++++++---------------- lib/read.c | 9 ++++--- t/call-5001.err | 55 +++++++++++++++++++++++++++++++++++++- 3 files changed, 107 insertions(+), 27 deletions(-) diff --git a/lib/comp.c b/lib/comp.c index 3df15ed..37783ae 100644 --- a/lib/comp.c +++ b/lib/comp.c @@ -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 */ diff --git a/lib/read.c b/lib/read.c index eefedf9..2a8a7af 100644 --- a/lib/read.c +++ b/lib/read.c @@ -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); diff --git a/t/call-5001.err b/t/call-5001.err index e018463..a576414 100644 --- a/t/call-5001.err +++ b/t/call-5001.err @@ -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