From 2e3fae05e4bea198cee779af45757662757aa236 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 25 Jan 2021 15:23:24 +0000 Subject: [PATCH] fixed the reader and the compiler to process the a dic/array/byte-array item after a period in a data list properly --- lib/cnode.c | 31 ++++++++++++++++++++++++++++--- lib/comp2.c | 14 ++++++++++---- lib/hcl-prv.h | 18 ++++++++++++------ lib/read2.c | 34 ++++++++++++++++++++++++++-------- 4 files changed, 76 insertions(+), 21 deletions(-) diff --git a/lib/cnode.c b/lib/cnode.c index 746dd7d..b03b42e 100644 --- a/lib/cnode.c +++ b/lib/cnode.c @@ -133,11 +133,19 @@ hcl_cnode_t* hcl_makecnodecons (hcl_t* hcl, const hcl_ioloc_t* loc, hcl_cnode_t* return c; } -hcl_cnode_t* hcl_makecnodelist (hcl_t* hcl, const hcl_ioloc_t* loc, hcl_concode_t type) +hcl_cnode_t* hcl_makecnodeelist (hcl_t* hcl, const hcl_ioloc_t* loc, hcl_concode_t type) { - hcl_cnode_t* c = make_cnode(hcl, HCL_CNODE_LIST, loc, HCL_NULL); + hcl_cnode_t* c = make_cnode(hcl, HCL_CNODE_ELIST, loc, HCL_NULL); if (HCL_UNLIKELY(!c)) return HCL_NULL; - c->u.list.concode = type; + c->u.elist.concode = type; + return c; +} + +hcl_cnode_t* hcl_makecnodeshell (hcl_t* hcl, const hcl_ioloc_t* loc, hcl_cnode_t* obj) +{ + hcl_cnode_t* c = make_cnode(hcl, HCL_CNODE_SHELL, loc, HCL_NULL); + if (HCL_UNLIKELY(!c)) return HCL_NULL; + c->u.shell.obj = obj; return c; } @@ -172,6 +180,23 @@ redo: break; } + case HCL_CNODE_SHELL: + { + hcl_cnode_t* tmp; + + tmp = c->u.shell.obj; + + hcl_freemem (hcl, c); + + if (tmp) + { + c = tmp; + goto redo; + } + + break; + } + default: hcl_freemem (hcl, c); break; diff --git a/lib/comp2.c b/lib/comp2.c index 2d677da..5a02a55 100644 --- a/lib/comp2.c +++ b/lib/comp2.c @@ -1950,6 +1950,7 @@ static int compile_object (hcl_t* hcl) HCL_ASSERT (hcl, cf->opcode == COP_COMPILE_OBJECT); oprnd = cf->operand; +redo: switch (HCL_CNODE_GET_TYPE(oprnd)) { case HCL_CNODE_NIL: @@ -2040,10 +2041,10 @@ static int compile_object (hcl_t* hcl) break; } - case HCL_CNODE_LIST: + case HCL_CNODE_ELIST: { /* empty list */ - switch (HCL_CNODE_LIST_CONCODE(oprnd)) + switch (HCL_CNODE_ELIST_CONCODE(oprnd)) { case HCL_CONCODE_XLIST: hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARDCLBANNED, HCL_CNODE_GET_LOC(oprnd), HCL_NULL, "empty executable list"); @@ -2077,6 +2078,11 @@ static int compile_object (hcl_t* hcl) break; } + case HCL_CNODE_SHELL: + /* a shell node is just a wrapper of an actual node */ + oprnd = oprnd->u.shell.obj; + goto redo; + 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; @@ -3229,11 +3235,11 @@ int hcl_compile2 (hcl_t* hcl, hcl_cnode_t* obj) case COP_SUBCOMPILE_AND_EXPR: if (subcompile_and_expr(hcl) <= -1) goto oops; break; - + case COP_SUBCOMPILE_OR_EXPR: if (subcompile_or_expr(hcl) <= -1) goto oops; break; - + case COP_POST_AND_EXPR: if (post_and_expr(hcl) <= -1) goto oops; break; diff --git a/lib/hcl-prv.h b/lib/hcl-prv.h index c6accf2..b2a5ed8 100644 --- a/lib/hcl-prv.h +++ b/lib/hcl-prv.h @@ -197,7 +197,8 @@ enum hcl_cnode_type_t HCL_CNODE_FALSE, HCL_CNODE_CONS, - HCL_CNODE_LIST + HCL_CNODE_ELIST, /* empty list */ + HCL_CNODE_SHELL /* pseudo-node to hold another actual node */ }; typedef enum hcl_cnode_type_t hcl_cnode_type_t; @@ -220,9 +221,9 @@ typedef enum hcl_cnode_type_t hcl_cnode_type_t; #define HCL_CNODE_CONS_CDR(x) ((x)->u.cons.cdr) -#define HCL_CNODE_IS_LIST(x) ((x)->cn_type == HCL_CNODE_LIST) -#define HCL_CNODE_IS_LIST_CONCODED(x) ((x)->cn_type == HCL_CNODE_LIST && (x)->u.list.concode == (code)) -#define HCL_CNODE_LIST_CONCODE(x) ((x)->u.list.concode) +#define HCL_CNODE_IS_ELIST(x) ((x)->cn_type == HCL_CNODE_ELIST) +#define HCL_CNODE_IS_ELIST_CONCODED(x) ((x)->cn_type == HCL_CNODE_ELIST && (x)->u.elist.concode == (code)) +#define HCL_CNODE_ELIST_CONCODE(x) ((x)->u.elist.concode) /* NOTE: hcl_cnode_t used by the built-in compiler is not an OOP object */ struct hcl_cnode_t @@ -260,7 +261,11 @@ struct hcl_cnode_t struct { hcl_concode_t concode; - } list; + } elist; + struct + { + hcl_cnode_t* obj; + } shell; } u; }; @@ -1359,7 +1364,8 @@ hcl_cnode_t* hcl_makecnodefpdeclit (hcl_t* hcl, const hcl_ioloc_t* loc, const h hcl_cnode_t* hcl_makecnodesmptrlit (hcl_t* hcl, const hcl_ioloc_t* loc, const hcl_oocs_t* tok, hcl_oow_t v); hcl_cnode_t* hcl_makecnodeerrlit (hcl_t* hcl, const hcl_ioloc_t* loc, const hcl_oocs_t* tok, hcl_ooi_t v); hcl_cnode_t* hcl_makecnodecons (hcl_t* hcl, const hcl_ioloc_t* loc, hcl_cnode_t* car, hcl_cnode_t* cdr); -hcl_cnode_t* hcl_makecnodelist (hcl_t* hcl, const hcl_ioloc_t* loc, hcl_concode_t type); +hcl_cnode_t* hcl_makecnodeelist (hcl_t* hcl, const hcl_ioloc_t* loc, hcl_concode_t type); +hcl_cnode_t* hcl_makecnodeshell (hcl_t* hcl, const hcl_ioloc_t* loc, hcl_cnode_t* obj); void hcl_freesinglecnode (hcl_t* hcl, hcl_cnode_t* c); void hcl_freecnode (hcl_t* hcl, hcl_cnode_t* c); hcl_oow_t hcl_countcnodecons (hcl_t* hcl, hcl_cnode_t* cons); diff --git a/lib/read2.c b/lib/read2.c index fdd711f..10b98a3 100644 --- a/lib/read2.c +++ b/lib/read2.c @@ -1469,7 +1469,7 @@ static HCL_INLINE hcl_cnode_t* leave_list (hcl_t* hcl, int* flagv, int* oldflagv } /* the list is empty */ - return hcl_makecnodelist(hcl, &loc, concode); + return hcl_makecnodeelist(hcl, &loc, concode); } static HCL_INLINE int can_dot_list (hcl_t* hcl) @@ -1555,12 +1555,12 @@ static int chain_to_list (hcl_t* hcl, hcl_cnode_t* obj) if (flagv & CLOSED) { /* the list has already been closed and cannot add more items - * for instance, see this faulty expression [1 2 . 3 4 ]. + * for instance, see this faulty expression #(1 2 . 3 4 ). * you can have only 1 item after the period. this condition * can only be triggered by a wrong qlist where a period is * allowed. so i can safely hard-code the error code to - * HCL_SYNERR_RBRACK. */ - hcl_setsynerr (hcl, HCL_SYNERR_RBRACK, TOKEN_LOC(hcl), TOKEN_NAME(hcl)); + * HCL_SYNERR_RPAREN */ + hcl_setsynerr (hcl, HCL_SYNERR_RPAREN, TOKEN_LOC(hcl), TOKEN_NAME(hcl)); return -1; } else if (flagv & DOTTED) @@ -1575,7 +1575,25 @@ static int chain_to_list (hcl_t* hcl, hcl_cnode_t* obj) tail = rstl->tail; HCL_ASSERT (hcl, tail != HCL_NULL); HCL_ASSERT (hcl, HCL_CNODE_IS_CONS(tail)); - tail->u.cons.cdr = obj; + + if (HCL_CNODE_IS_CONS(obj) && HCL_CNODE_CONS_CONCODE(obj) != HCL_CONCODE_QLIST) + { + hcl_cnode_t* shell; + + /* if the last element is another non-data list + * for example, #( 1 2 . [ 3 4 5 ]) + * use a shell node to wrap the actual object list node head + * for the compiler. + */ + shell = hcl_makecnodeshell(hcl, HCL_CNODE_GET_LOC(obj), obj); + if (HCL_UNLIKELY(!shell)) return -1; + + tail->u.cons.cdr = shell; + } + else + { + tail->u.cons.cdr = obj; + } /* update the flag to CLOSED so that you can have more than * one item after the dot. */ @@ -1688,7 +1706,8 @@ static hcl_cnode_t* read_vlist (hcl_t* hcl) return vh; } - return hcl_makecnodelist(hcl, &start_loc, HCL_CONCODE_VLIST); + /* this is an empty list */ + return hcl_makecnodeelist(hcl, &start_loc, HCL_CONCODE_VLIST); oops: if (vh) hcl_freecnode (hcl, vh); @@ -1983,8 +2002,7 @@ static hcl_cnode_t* read_object (hcl_t* hcl) /* if so, append the element read into the quote list */ if (chain_to_list(hcl, obj) <= -1) goto oops; - /* exit out of the quoted list. the quoted list can have - * one element only. */ + /* exit out of the quoted list. the quoted list can have one element only. */ obj = leave_list(hcl, &flagv, &oldflagv); /* one level up toward the top */