diff --git a/lib/cnode.c b/lib/cnode.c index b03b42e..8cae366 100644 --- a/lib/cnode.c +++ b/lib/cnode.c @@ -67,6 +67,11 @@ hcl_cnode_t* hcl_makecnodefalse (hcl_t* hcl, const hcl_ioloc_t* loc, const hcl_ return make_cnode(hcl, HCL_CNODE_FALSE, loc, tok); } +hcl_cnode_t* hcl_makecnodeellipsis (hcl_t* hcl, const hcl_ioloc_t* loc, const hcl_oocs_t* tok) +{ + return make_cnode(hcl, HCL_CNODE_ELLIPSIS, loc, tok); +} + hcl_cnode_t* hcl_makecnodecharlit (hcl_t* hcl, const hcl_ioloc_t* loc, const hcl_oocs_t* tok, const hcl_ooch_t v) { hcl_cnode_t* c = make_cnode(hcl, HCL_CNODE_CHARLIT, loc, tok); diff --git a/lib/comp.c b/lib/comp.c index 7f3cdd4..0f9d347 100644 --- a/lib/comp.c +++ b/lib/comp.c @@ -751,7 +751,7 @@ static void pop_fnblk (hcl_t* hcl) { hcl_oow_t tmpr_mask; - /* patch the temporary mask parameter for the MAKE_BLOCK or MAKE_FUNCTION instruction */ + /* patch the temporaries mask parameter for the MAKE_BLOCK or MAKE_FUNCTION instruction */ HCL_ASSERT (hcl, hcl->code.bc.ptr[fbi->make_inst_pos] == HCL_CODE_MAKE_BLOCK || hcl->code.bc.ptr[fbi->make_inst_pos] == HCL_CODE_MAKE_FUNCTION); @@ -759,6 +759,8 @@ static void pop_fnblk (hcl_t* hcl) * the number of arguments, return variables and local variables */ HCL_ASSERT (hcl, fbi->tmprcnt - hcl->c->tv.wcount == fbi->tmpr_nargs + fbi->tmpr_nrvars + fbi->tmpr_nlvars); + /* the temporaries mask is a bit-mask that encodes the counts of different temporary variables. + * and it's split to two intruction parameters when used with MAKE_BLOCK and MAKE_FUNCTION */ tmpr_mask = ENCODE_BLKTMPR_MASK(fbi->tmpr_va, fbi->tmpr_nargs, fbi->tmpr_nrvars, fbi->tmpr_nlvars); patch_double_long_params_with_oow (hcl, fbi->make_inst_pos + 1, tmpr_mask); } @@ -1641,7 +1643,7 @@ static int collect_local_vardcl (hcl_t* hcl, hcl_cnode_t* obj, hcl_cnode_t** nex static int compile_lambda (hcl_t* hcl, hcl_cnode_t* src, int defun) { hcl_cnode_t* cmd, * obj, * args; - hcl_oow_t nargs, nrvars, nlvars; + hcl_oow_t va, nargs, nrvars, nlvars; hcl_ooi_t jump_inst_pos, lfbase_pos, lfsize_pos; hcl_oow_t saved_tv_wcount, tv_dup_start; hcl_cnode_t* defun_name; @@ -1701,6 +1703,7 @@ static int compile_lambda (hcl_t* hcl, hcl_cnode_t* src, int defun) } /* process the argument list */ + va = 0; args = HCL_CNODE_CONS_CAR(obj); HCL_ASSERT (hcl, args != HCL_NULL); if (HCL_CNODE_IS_ELIST_CONCODED(args, HCL_CONCODE_XLIST)) @@ -1723,9 +1726,10 @@ static int compile_lambda (hcl_t* hcl, hcl_cnode_t* src, int defun) do { arg = HCL_CNODE_CONS_CAR(dcl); - if (HCL_CNODE_IS_CONS(arg)) + if (HCL_CNODE_IS_ELLIPSIS(arg)) { - + va = 1; + break; } else if (!HCL_CNODE_IS_SYMBOL(arg)) { @@ -1792,7 +1796,7 @@ static int compile_lambda (hcl_t* hcl, hcl_cnode_t* src, int defun) HCL_ASSERT (hcl, nargs + nrvars + nlvars == hcl->c->tv.wcount - saved_tv_wcount); - if (push_fnblk(hcl, HCL_CNODE_GET_LOC(src), 0, nargs, nrvars, nlvars, hcl->c->tv.wcount, hcl->c->tv.s.len, hcl->code.bc.len, hcl->code.lit.len) <= -1) return -1; + if (push_fnblk(hcl, HCL_CNODE_GET_LOC(src), va, nargs, nrvars, nlvars, hcl->c->tv.wcount, hcl->c->tv.s.len, hcl->code.bc.len, hcl->code.lit.len) <= -1) return -1; if (hcl->option.trait & HCL_TRAIT_INTERACTIVE) { @@ -2880,7 +2884,7 @@ redo: goto done; case HCL_CONCODE_VLIST: - hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARDCLBANNED, HCL_CNODE_GET_LOC(oprnd), HCL_NULL, "variable declaration disallowed"); + hcl_setsynerrbfmt (hcl, HCL_SYNERR_ELLIPSISBANNED, HCL_CNODE_GET_LOC(oprnd), HCL_NULL, "variable declaration disallowed"); return -1; default: @@ -2896,6 +2900,10 @@ redo: oprnd = oprnd->u.shell.obj; goto redo; + case HCL_CNODE_ELLIPSIS: + hcl_setsynerrbfmt (hcl, HCL_SYNERR_INTERN, HCL_CNODE_GET_LOC(oprnd), HCL_CNODE_GET_TOK(oprnd), "ellipsis disallowed in this context", HCL_CNODE_GET_TYPE(oprnd)); + return -1; + default: hcl_setsynerrbfmt (hcl, HCL_SYNERR_INTERN, HCL_CNODE_GET_LOC(oprnd), HCL_CNODE_GET_TOK(oprnd), "internal error - unexpected object type %d", HCL_CNODE_GET_TYPE(oprnd)); return -1; diff --git a/lib/err.c b/lib/err.c index 5158d67..f152c44 100644 --- a/lib/err.c +++ b/lib/err.c @@ -125,6 +125,7 @@ static char* synerrstr[] = "no separator between array/dictionary elements", "#include error", + "... disallowed", "loop body too big", "if body too big", "lambda block too big", diff --git a/lib/hcl-prv.h b/lib/hcl-prv.h index 47ff894..ad61a59 100644 --- a/lib/hcl-prv.h +++ b/lib/hcl-prv.h @@ -148,6 +148,7 @@ enum hcl_iotok_type_t HCL_IOTOK_IDENT, HCL_IOTOK_IDENT_DOTTED, HCL_IOTOK_DOT, + HCL_IOTOK_ELLIPSIS, HCL_IOTOK_COLON, HCL_IOTOK_COMMA, HCL_IOTOK_LPAREN, @@ -195,6 +196,7 @@ enum hcl_cnode_type_t HCL_CNODE_NIL, HCL_CNODE_TRUE, HCL_CNODE_FALSE, + HCL_CNODE_ELLIPSIS, HCL_CNODE_CONS, HCL_CNODE_ELIST, /* empty list */ @@ -208,6 +210,8 @@ typedef enum hcl_cnode_type_t hcl_cnode_type_t; #define HCL_CNODE_GET_TOKPTR(x) ((x)->cn_tok.ptr) #define HCL_CNODE_GET_TOKLEN(x) ((x)->cn_tok.len) +#define HCL_CNODE_IS_ELLIPSIS(x) ((x)->cn_type == HCL_CNODE_ELLIPSIS) + #define HCL_CNODE_IS_SYMBOL(x) ((x)->cn_type == HCL_CNODE_SYMBOL) #define HCL_CNODE_IS_SYMBOL_SYNCODED(x, code) ((x)->cn_type == HCL_CNODE_SYMBOL && (x)->u.symbol.syncode == (code)) #define HCL_CNODE_SYMBOL_SYNCODE(x) ((x)->u.symbol.syncode) @@ -220,7 +224,6 @@ typedef enum hcl_cnode_type_t hcl_cnode_type_t; #define HCL_CNODE_CONS_CAR(x) ((x)->u.cons.car) #define HCL_CNODE_CONS_CDR(x) ((x)->u.cons.cdr) - #define HCL_CNODE_IS_ELIST(x) ((x)->cn_type == HCL_CNODE_ELIST) #define HCL_CNODE_IS_ELIST_CONCODED(x, code) ((x)->cn_type == HCL_CNODE_ELIST && (x)->u.elist.concode == (code)) #define HCL_CNODE_ELIST_CONCODE(x) ((x)->u.elist.concode) @@ -1404,6 +1407,7 @@ int hcl_emitbyteinstruction ( hcl_cnode_t* hcl_makecnodenil (hcl_t* hcl, const hcl_ioloc_t* loc, const hcl_oocs_t* tok); hcl_cnode_t* hcl_makecnodetrue (hcl_t* hcl, const hcl_ioloc_t* loc, const hcl_oocs_t* tok); hcl_cnode_t* hcl_makecnodefalse (hcl_t* hcl, const hcl_ioloc_t* loc, const hcl_oocs_t* tok); +hcl_cnode_t* hcl_makecnodeellipsis (hcl_t* hcl, const hcl_ioloc_t* loc, const hcl_oocs_t* tok); hcl_cnode_t* hcl_makecnodecharlit (hcl_t* hcl, const hcl_ioloc_t* loc, const hcl_oocs_t* tok, const hcl_ooch_t v); hcl_cnode_t* hcl_makecnodesymbol (hcl_t* hcl, const hcl_ioloc_t* loc, const hcl_oocs_t* tok); hcl_cnode_t* hcl_makecnodedsymbol (hcl_t* hcl, const hcl_ioloc_t* loc, const hcl_oocs_t* tok); diff --git a/lib/hcl.h b/lib/hcl.h index 4a230fc..c64660f 100644 --- a/lib/hcl.h +++ b/lib/hcl.h @@ -131,6 +131,7 @@ enum hcl_synerrnum_t HCL_SYNERR_NOSEP, /* no seperator between array/dictionary elements */ HCL_SYNERR_INCLUDE, /* #include error */ + HCL_SYNERR_ELLIPSISBANNED, /* ... disallowed */ HCL_SYNERR_LOOPFLOOD, /* loop body too big */ HCL_SYNERR_IFFLOOD, /* if body too big */ HCL_SYNERR_BLKFLOOD, /* lambda block too big */ diff --git a/lib/read.c b/lib/read.c index a341db4..bca754e 100644 --- a/lib/read.c +++ b/lib/read.c @@ -1078,6 +1078,35 @@ retry: break; case '.': + oldc = c; + GET_CHAR_TO (hcl, c); + if(c == '.') + { + hcl_iolxc_t sd; + hcl_ooci_t oldc2; + + sd = hcl->c->lxc; /* back up '#' */ + + oldc2 = c; + GET_CHAR_TO (hcl, c); + if (c == '.') + { + SET_TOKEN_TYPE (hcl, HCL_IOTOK_ELLIPSIS); + ADD_TOKEN_CHAR (hcl, oldc); + ADD_TOKEN_CHAR (hcl, oldc2); + ADD_TOKEN_CHAR (hcl, c); + break; + } + + unget_char (hcl, &hcl->c->lxc); + unget_char (hcl, &sd); + } + else + { + unget_char (hcl, &hcl->c->lxc); + } + c = oldc; + SET_TOKEN_TYPE (hcl, HCL_IOTOK_DOT); ADD_TOKEN_CHAR (hcl, c); break; @@ -1910,6 +1939,10 @@ static hcl_cnode_t* read_object (hcl_t* hcl) obj = hcl_makecnodefalse(hcl, TOKEN_LOC(hcl), TOKEN_NAME(hcl)); break; + case HCL_IOTOK_ELLIPSIS: + obj = hcl_makecnodeellipsis(hcl, TOKEN_LOC(hcl), TOKEN_NAME(hcl)); + break; + case HCL_IOTOK_SMPTRLIT: { hcl_oow_t i; @@ -1987,6 +2020,7 @@ static hcl_cnode_t* read_object (hcl_t* hcl) case HCL_IOTOK_IDENT_DOTTED: obj = hcl_makecnodedsymbol(hcl, TOKEN_LOC(hcl), TOKEN_NAME(hcl)); break; + } if (!obj) goto oops;