diff --git a/bin/main-c.c b/bin/main-c.c index 3d441f0..7edcb5b 100644 --- a/bin/main-c.c +++ b/bin/main-c.c @@ -551,7 +551,7 @@ static int receive_raw_bytes (hcl_xproto_t* proto, int sck, hcl_ntime_t* idle_tm { /* timeout explicity set. no activity for that duration. considered idle */ hcl_seterrbfmt (hcl, HCL_EGENERIC, "no activity on the socket %d", sck); - return -1; + return -1; } return 0; /* didn't read yet */ @@ -559,7 +559,7 @@ static int receive_raw_bytes (hcl_xproto_t* proto, int sck, hcl_ntime_t* idle_tm if (pfd.revents & POLLERR) { - hcl_seterrbfmt (hcl, HCL_EGENERIC, "error condition detected on socket %d", sck); + hcl_seterrbfmt (hcl, HCL_EGENERIC, "error condition detected on socket %d", sck); return -1; } @@ -754,7 +754,20 @@ static int handle_request (hcl_client_t* client, const char* ipaddr, const char* iov[0].iov_len = HCL_SIZEOF(hdr); send_iov (sck, iov, 1); - if (shut_wr_after_req) shutdown (sck, SHUT_WR); + if (shut_wr_after_req) + { + shutdown (sck, SHUT_WR); + } + else + { + hdr.type = HCL_XPKT_DISCONNECT; + hdr.id = 1; /* TODO: */ + hdr.len = 0; + + iov[0].iov_base = &hdr; + iov[0].iov_len = HCL_SIZEOF(hdr); + send_iov (sck, iov, 1); + } } } diff --git a/lib/comp.c b/lib/comp.c index ca4a22f..6510ff7 100644 --- a/lib/comp.c +++ b/lib/comp.c @@ -27,6 +27,7 @@ /* limit the `do` expression to have not more than 1 expression and * no variable declaration if not enclosed in parentheses */ #define LANG_LIMIT_DO +#define CLEAR_FNBLK_ALWAYS #define FOR_NONE (0) #define FOR_IF (1) @@ -1197,12 +1198,11 @@ static void pop_fnblk (hcl_t* hcl) hcl_fnblk_info_t* fbi; HCL_ASSERT (hcl, hcl->c->fnblk.depth >= 0); - /* if pop_cblk() has been called properly, the following assertion must be true - * and the assignment on the next line isn't necessary */ clear_fnblk_inners (hcl); - fbi = &hcl->c->fnblk.info[hcl->c->fnblk.depth]; + /* if pop_cblk() has been called properly, the following assertion must be true + * and the assignment on the next line isn't necessary */ HCL_ASSERT (hcl, hcl->c->cblk.depth == fbi->cblk_base); HCL_ASSERT (hcl, fbi->clsblk_base <= -1 && fbi->clsblk_top <= -1); @@ -5856,16 +5856,24 @@ int hcl_compile (hcl_t* hcl, hcl_cnode_t* obj, int flags) { hcl_oow_t saved_bc_len, saved_lit_len; hcl_bitmask_t log_default_type_mask; +#if !defined(CLEAR_FNBLK_ALWAYS) hcl_fnblk_info_t top_fnblk_saved; + int fnblk_pushed_here = 0; +#endif hcl->c->flags = flags; + HCL_ASSERT (hcl, hcl->c->fnblk.depth <= 0); /* 0 or 1 fnblk must exist at this phase */ HCL_ASSERT (hcl, GET_TOP_CFRAME_INDEX(hcl) < 0); - if (flags & HCL_COMPILE_CLEAR_CODE) +#if !defined(CLEAR_FNBLK_ALWAYS) + if (flags & HCL_COMPILE_CLEAR_FNBLK) { - hcl->code.bc.len = 0; - hcl->code.lit.len = 0; + while (hcl->c->fnblk.depth >= 0) pop_fnblk (hcl); + HCL_ASSERT (hcl, hcl->c->fnblk.depth == -1); + /* it will be recreated below */ } +#endif + if (flags & HCL_COMPILE_CLEAR_CODE) hcl_clearcode (hcl); saved_bc_len = hcl->code.bc.len; saved_lit_len = hcl->code.lit.len; @@ -5907,8 +5915,10 @@ int hcl_compile (hcl_t* hcl, hcl_cnode_t* obj, int flags) /* TODO: in case i implement all global variables as block arguments at the top level...what should i do? */ HCL_ASSERT (hcl, hcl->c->cblk.depth == -1); +#if !defined(CLEAR_FNBLK_ALWAYS) if (hcl->c->fnblk.depth <= -1) { +#endif HCL_ASSERT (hcl, hcl->c->fnblk.depth == -1); HCL_ASSERT (hcl, hcl->c->tv.s.len == 0); HCL_ASSERT (hcl, hcl->c->tv.wcount == 0); @@ -5917,9 +5927,25 @@ int hcl_compile (hcl_t* hcl, hcl_cnode_t* obj, int flags) * pass HCL_TYPE_MAX(hcl_oow_t) as make_inst_pos because there is * no actual MAKE_LAMBDA/MAKE_FUNCTION instruction which otherwise * would be patched in pop_fnblk(). */ - if (push_fnblk(hcl, HCL_NULL, 0, 0, 0, hcl->c->tv.wcount, hcl->c->tv.wcount, hcl->c->tv.s.len, HCL_TYPE_MAX(hcl_oow_t), 0, FUN_PLAIN) <= -1) return -1; /* must not goto oops */ + + if (push_fnblk( + hcl, HCL_NULL, + 0, /* tmpr_va */ + 0, /* tmpr_nargs */ + 0, /* tmpr_nrvars */ + hcl->c->tv.wcount, /* tmpr_nlvars */ + hcl->c->tv.wcount, /* tmpr_count */ + hcl->c->tv.s.len, /* tmpr_len */ + HCL_TYPE_MAX(hcl_oow_t), /* make_inst_pos */ + 0, /* lfbase */ + FUN_PLAIN /* fun_type */ + ) <= -1) return -1; /* must not goto oops */ + +#if !defined(CLEAR_FNBLK_ALWAYS) + fnblk_pushed_here = 1; } top_fnblk_saved = hcl->c->fnblk.info[0]; +#endif HCL_ASSERT (hcl, hcl->c->fnblk.depth == 0); /* ensure the virtual function block is added */ PUSH_CFRAME (hcl, COP_COMPILE_OBJECT, obj); @@ -6153,11 +6179,15 @@ int hcl_compile (hcl_t* hcl, hcl_cnode_t* obj, int flags) HCL_ASSERT (hcl, hcl->c->fnblk.depth == 0); /* ensure the virtual function block be the only one left */ hcl->code.ngtmprs = hcl->c->fnblk.info[0].tmprcnt; /* populate the number of global temporary variables */ - if (flags & HCL_COMPILE_CLEAR_FNBLK) - { - pop_fnblk (hcl); - HCL_ASSERT (hcl, hcl->c->fnblk.depth == -1); - } + + /* TODO: delete all !defined(CLEAR_FNBLK_ALWAYS) code + * keep only defined(CLEAR_FNBLK_ALWAYS) code. + * not clearing the top fnblk for the reuse doesn't look very beneficial */ +#if defined(CLEAR_FNBLK_ALWAYS) + pop_fnblk (hcl); + HCL_ASSERT (hcl, hcl->c->tv.s.len == 0); + HCL_ASSERT (hcl, hcl->c->tv.wcount == 0); +#endif hcl->log.default_type_mask = log_default_type_mask; return 0; @@ -6171,23 +6201,30 @@ oops: hcl->code.bc.len = saved_bc_len; hcl->code.lit.len = saved_lit_len; - hcl->c->tv.s.len = 0; - hcl->c->tv.wcount = 0; - while (hcl->c->fnblk.depth > 0) pop_fnblk (hcl); + HCL_ASSERT (hcl, hcl->c->fnblk.depth == 0); - if (flags & HCL_COMPILE_CLEAR_FNBLK) +#if !defined(CLEAR_FNBLK_ALWAYS) + if (fnblk_pushed_here) { +#endif pop_fnblk (hcl); HCL_ASSERT (hcl, hcl->c->fnblk.depth == -1); + HCL_ASSERT (hcl, hcl->c->tv.s.len == 0); + HCL_ASSERT (hcl, hcl->c->tv.wcount == 0); +#if !defined(CLEAR_FNBLK_ALWAYS) } else { - /* restore the top level function block as it's first captured in this functio */ + hcl->c->tv.s.len = 0; + hcl->c->tv.wcount = 0; + + /* restore the top level function block as it's first captured in this function */ clear_fnblk_inners (hcl); HCL_ASSERT (hcl, hcl->c->fnblk.depth == 0); hcl->c->fnblk.info[0] = top_fnblk_saved; } +#endif return -1; } diff --git a/lib/hcl-x.c b/lib/hcl-x.c index f7b4e80..0e14f28 100644 --- a/lib/hcl-x.c +++ b/lib/hcl-x.c @@ -123,7 +123,6 @@ struct hcl_server_proto_t hcl_server_proto_rcv_state_t state; hcl_oow_t len_needed; unsigned int eof: 1; - unsigned int polled: 1; hcl_oow_t len; hcl_uint8_t buf[4096]; @@ -135,11 +134,6 @@ struct hcl_server_proto_t { } snd; - - struct - { - int ongoing; - } feed; }; enum hcl_server_worker_state_t @@ -692,8 +686,8 @@ static void fini_hcl (hcl_t* hcl) static int on_fed_cnode (hcl_t* hcl, hcl_cnode_t* obj) { - worker_hcl_xtn_t* xtn = (worker_hcl_xtn_t*)hcl_getxtn(hcl); - hcl_server_proto_t* proto = xtn->proto; + /*worker_hcl_xtn_t* xtn = (worker_hcl_xtn_t*)hcl_getxtn(hcl);*/ + /*hcl_server_proto_t* proto = xtn->proto;*/ int flags = 0; printf ("on_fed_cnode......\n"); @@ -703,15 +697,6 @@ printf ("on_fed_cnode......\n"); * if a single line or continued lines contain multiple expressions, * execution is delayed until the last expression is compiled. */ - if (!proto->feed.ongoing) - { - /* the first expression in the current user input line. - * arrange to clear byte-codes before compiling the expression. */ - flags = HCL_COMPILE_CLEAR_CODE | HCL_COMPILE_CLEAR_FNBLK; - proto->feed.ongoing = 1; -printf ("CLEARING...\n"); - } - printf ("COMPILING hcl_copingll......\n"); if (hcl_compile(hcl, obj, flags) <= -1) { @@ -742,7 +727,6 @@ hcl_server_proto_t* hcl_server_proto_open (hcl_oow_t xtnsize, hcl_server_worker_ proto->rcv.state = HCL_SERVER_PROTO_RCV_HEADER; proto->rcv.len_needed = HCL_SIZEOF(proto->rcv.hdr); proto->rcv.eof = 0; - proto->rcv.polled = 0; proto->hcl = hcl_openstdwithmmgr(hcl_server_getmmgr(proto->worker->server), HCL_SIZEOF(*xtn), HCL_NULL); if (HCL_UNLIKELY(!proto->hcl)) goto oops; @@ -1016,77 +1000,64 @@ static int kill_server_worker (hcl_server_proto_t* proto, hcl_oow_t wid) return xret; } -static int receive_raw_request (hcl_server_proto_t* proto) +static int handle_packet (hcl_server_proto_t* proto, hcl_xpkt_type_t type, void* data, hcl_oow_t len) { - hcl_server_worker_t* worker = proto->worker; - hcl_server_t* server = worker->server; hcl_t* hcl = proto->hcl; - struct pollfd pfd; - int tmout, actual_tmout; - ssize_t x; - int n; - HCL_ASSERT (hcl, proto->rcv.len < proto->rcv.len_needed); - - if (HCL_UNLIKELY(proto->rcv.eof)) + switch (type) { - hcl_seterrbfmt (hcl, HCL_EGENERIC, "connection closed"); - return -1; - } - - if (HCL_LIKELY(!proto->rcv.polled)) - { - tmout = HCL_SECNSEC_TO_MSEC(server->cfg.worker_idle_timeout.sec, server->cfg.worker_idle_timeout.nsec); - actual_tmout = (tmout <= 0)? 10000: tmout; - - pfd.fd = worker->sck; - pfd.events = POLLIN | POLLERR; - pfd.revents = 0; - n = poll(&pfd, 1, actual_tmout); - if (n <= -1) - { - if (errno == EINTR) return 0; - hcl_seterrwithsyserr (hcl, 0, errno); - return -1; - } - else if (n == 0) - { - /* timed out - no activity on the pfd */ - if (tmout > 0) + case HCL_XPKT_CODEIN: +printf ("FEEDING [%.*s]\n", (int)len, data); + if (hcl_feedbchars(hcl, data, len) <= -1) { - /* timeout explicity set. no activity for that duration. considered idle */ - hcl_seterrbfmt (hcl, HCL_EGENERIC, "no activity on the worker socket %d", worker->sck); - return -1; + /* TODO: backup error message...and create a new message */ + goto oops; + } + break; + + case HCL_XPKT_EXECUTE: + { + hcl_oop_t retv; +printf ("EXECUTING hcl_executing......\n"); + + hcl_decode (hcl, hcl_getcode(hcl), 0, hcl_getbclen(hcl)); + + retv = hcl_execute(hcl); + hcl_flushudio (hcl); + hcl_clearcode (hcl); + if (!retv) + { + /* TODO: backup error message...and create a new message */ + goto oops; } - return 0; /* didn't read yet */ + break; } - if (pfd.revents & POLLERR) - { - hcl_seterrbfmt (hcl, HCL_EGENERIC, "error condition detected on workder socket %d", worker->sck); - return -1; - } + case HCL_XPKT_STDIN: + /* store ... push stdin pipe... */ + /*if (hcl_feedstdin() <= -1) */ + break; - proto->rcv.polled = 1; + case HCL_XPKT_LIST_WORKERS: + break; + case HCL_XPKT_KILL_WORKER: + break; + case HCL_XPKT_DISCONNECT: + return 0; /* disconnect received */ + + default: + /* unknown packet type */ + /* TODO: proper error message */ + goto oops; } - x = recv(worker->sck, &proto->rcv.buf[proto->rcv.len], HCL_COUNTOF(proto->rcv.buf) - proto->rcv.len, 0); - if (x <= -1) - { - if (errno == EINTR) return 0; /* didn't read read */ + return 1; - proto->rcv.polled = 0; - hcl_seterrwithsyserr (hcl, 0, errno); - return -1; - } - proto->rcv.polled = 0; - if (x == 0) proto->rcv.eof = 1; - - proto->rcv.len += x; - return 1; /* read some data */ +oops: + return -1; } @@ -1094,12 +1065,12 @@ static int handle_received_data (hcl_server_proto_t* proto) { hcl_server_worker_t* worker = proto->worker; hcl_t* hcl = proto->hcl; - hcl_xpkt_hdr_t* hdr; + int n; switch (proto->rcv.state) { case HCL_SERVER_PROTO_RCV_HEADER: - if (proto->rcv.len < HCL_SIZEOF(proto->rcv.hdr)) return 0; /* need more data */ + if (proto->rcv.len < HCL_SIZEOF(proto->rcv.hdr)) goto carry_on; /* need more data */ HCL_MEMCPY (&proto->rcv.hdr, proto->rcv.buf, HCL_SIZEOF(proto->rcv.hdr)); /*proto->rcv.hdr.len = hcl_ntoh16(proto->rcv.hdr.len);*/ /* keep this in the host byte order */ @@ -1109,54 +1080,26 @@ static int handle_received_data (hcl_server_proto_t* proto) proto->rcv.len -= HCL_SIZEOF(proto->rcv.hdr); /* switch to the payload mode */ - proto->rcv.state = HCL_SERVER_PROTO_RCV_PAYLOAD; - proto->rcv.len_needed = proto->rcv.hdr.len; - return 0; - - case HCL_SERVER_PROTO_RCV_PAYLOAD: - if (proto->rcv.len < proto->rcv.hdr.len) return 0; /* need more payload data */ - - if (proto->rcv.hdr.type == HCL_XPKT_CODEIN) - { -printf ("FEEDING [%.*s]\n", proto->rcv.hdr.len, proto->rcv.buf); - if (hcl_feedbchars(hcl, (const hcl_bch_t*)proto->rcv.buf, proto->rcv.hdr.len) <= -1) - { - /* TODO: backup error message...and create a new message */ - goto fail_with_errmsg; - } - } - else if (proto->rcv.hdr.type == HCL_XPKT_EXECUTE) - { - hcl_oop_t retv; -printf ("EXECUTING hcl_executing......\n"); - proto->feed.ongoing = 0; - - hcl_decode (hcl, hcl_getcode(hcl), 0, hcl_getbclen(hcl)); - - retv = hcl_execute(hcl); - hcl_flushudio (hcl); - if (!retv) - { - /* TODO: backup error message...and create a new message */ - goto fail_with_errmsg; - } - } - else if (proto->rcv.hdr.type == HCL_XPKT_STDIN) - { - /* store ... push stdin pipe... */ - /*if (hcl_feedstdin() <= -1) */ - } - else if (proto->rcv.hdr.type == HCL_XPKT_LIST_WORKERS) - { - } - else if (proto->rcv.hdr.type == HCL_XPKT_KILL_WORKER) + if (proto->rcv.hdr.len > 0) { + proto->rcv.state = HCL_SERVER_PROTO_RCV_PAYLOAD; + proto->rcv.len_needed = proto->rcv.hdr.len; } else { - /* error ... unknown request type */ + /* take shortcut */ + n = handle_packet(proto, proto->rcv.hdr.type, proto->rcv.buf, proto->rcv.hdr.len); + if (n <= -1) goto fail_with_errmsg; + if (n == 0) return 0; } + break; + + case HCL_SERVER_PROTO_RCV_PAYLOAD: + if (proto->rcv.len < proto->rcv.hdr.len) goto carry_on; /* need more payload data */ + + n = handle_packet(proto, proto->rcv.hdr.type, proto->rcv.buf, proto->rcv.hdr.len); + /* TODO: minimize the use of HCL_MEMOVE... use the buffer */ /* switch to the header mode */ if (proto->rcv.hdr.len > 0) @@ -1167,6 +1110,9 @@ printf ("EXECUTING hcl_executing......\n"); proto->rcv.state = HCL_SERVER_PROTO_RCV_HEADER; proto->rcv.len_needed = HCL_SIZEOF(proto->rcv.hdr); + if (n <= -1) goto fail_with_errmsg; + if (n == 0) return 0; + break; default: @@ -1174,7 +1120,8 @@ printf ("EXECUTING hcl_executing......\n"); goto fail_with_errmsg; } - return 1; /* processed 1 packet */ +carry_on: + return 1; fail_with_errmsg: // TODO: proper error handling @@ -1650,7 +1597,7 @@ static int worker_step (hcl_server_worker_t* worker) return -1; } - return 0; /* didn't read yet */ + goto carry_on; } if (pfd.revents & POLLERR) @@ -1668,9 +1615,8 @@ static int worker_step (hcl_server_worker_t* worker) x = recv(worker->sck, &proto->rcv.buf[proto->rcv.len], HCL_COUNTOF(proto->rcv.buf) - proto->rcv.len, 0); if (x <= -1) { - if (errno == EINTR) return 0; /* didn't read read */ + if (errno == EINTR) goto carry_on; /* didn't read read */ - proto->rcv.polled = 0; hcl_seterrwithsyserr (hcl, 0, errno); return -1; } @@ -1684,14 +1630,20 @@ static int worker_step (hcl_server_worker_t* worker) /* the receiver buffer has enough data */ while (/*proto->rcv.len > 0 && */proto->rcv.len >= proto->rcv.len_needed) { - if (handle_received_data(proto) <= -1) + if ((n = handle_received_data(proto)) <= -1) { /* TODO: proper error message */ return -1; } + if (n == 0) + { + /* TODO: chceck if there is remaining data in the buffer...?? */ + return 0; /* tell the caller to break the step loop */ + } } - return 0; +carry_on: + return 1; /* carry on */ } static void* worker_main (void* ctx) @@ -1718,11 +1670,12 @@ static void* worker_main (void* ctx) /* the worker loop */ while (!server->stopreq) { + int n; worker->opstate = HCL_SERVER_WORKER_OPSTATE_WAIT; - if (worker_step(worker) <= -1) + if ((n = worker_step(worker)) <= 0) { - worker->opstate = HCL_SERVER_WORKER_OPSTATE_ERROR; + worker->opstate = (n <= -1)? HCL_SERVER_WORKER_OPSTATE_ERROR: HCL_SERVER_WORKER_OPSTATE_IDLE; break; } } diff --git a/lib/hcl-x.h b/lib/hcl-x.h index 6c8a353..ff66840 100644 --- a/lib/hcl-x.h +++ b/lib/hcl-x.h @@ -38,7 +38,9 @@ enum hcl_xpkt_type_t HCL_XPKT_STDOUT, HCL_XPKT_LIST_WORKERS, - HCL_XPKT_KILL_WORKER + HCL_XPKT_KILL_WORKER, + + HCL_XPKT_DISCONNECT }; typedef enum hcl_xpkt_type_t hcl_xpkt_type_t; diff --git a/lib/hcl.c b/lib/hcl.c index d14d06e..8d7cbda 100644 --- a/lib/hcl.c +++ b/lib/hcl.c @@ -397,6 +397,13 @@ void hcl_reset (hcl_t* hcl) hcl_gc (hcl, 1); } +void hcl_clearcode (hcl_t* hcl) +{ + /* clear the code buffer and the literal frame only */ + hcl->code.bc.len = 0; + hcl->code.lit.len = 0; +} + static int dup_str_opt (hcl_t* hcl, const hcl_ooch_t* value, hcl_oocs_t* tmp) { if (value) diff --git a/lib/hcl.h b/lib/hcl.h index 2b8c26b..7ebc8a8 100644 --- a/lib/hcl.h +++ b/lib/hcl.h @@ -2548,6 +2548,10 @@ HCL_EXPORT int hcl_decode ( hcl_oow_t end ); +HCL_EXPORT void hcl_clearcode ( + hcl_t* hcl +); + #if defined(HCL_HAVE_INLINE) static HCL_INLINE hcl_code_t* hcl_getcode (hcl_t* hcl) { return &hcl->code; } static HCL_INLINE hcl_oob_t* hcl_getbcptr (hcl_t* hcl) { return hcl->code.bc.ptr; } diff --git a/lib/read.c b/lib/read.c index 8343127..403601d 100644 --- a/lib/read.c +++ b/lib/read.c @@ -667,7 +667,7 @@ static HCL_INLINE hcl_cnode_t* leave_list (hcl_t* hcl, hcl_loc_t* list_loc, int* } else { - if (!HCL_CNODE_IS_SYMBOL_PLAIN(lval)) + if (!HCL_CNODE_IS_SYMBOL_PLAIN(lval) && !HCL_CNODE_IS_DSYMBOL_CLA(lval)) { hcl_setsynerrbfmt (hcl, HCL_SYNERR_LVALUE, HCL_CNODE_GET_LOC(lval), HCL_CNODE_GET_TOK(lval), "invalid lvalue - not symbol"); goto oops; diff --git a/t/insta-02.hcl b/t/insta-02.hcl index f2a0594..e2062b4 100644 --- a/t/insta-02.hcl +++ b/t/insta-02.hcl @@ -24,3 +24,30 @@ else { printf "OK: value is %d\n" v }; v := (dic.get j 4512); if (nqv? v 1234) { printf "ERROR: v is not 1234\n" } \ else { printf "OK: value is %d\n" v }; + +## -------------------------------------------------------------- + +class X | a b c d | { + fun :*new() { + return self; + } + + fun x() { + a := 20 ; self.b:=(a + 10); c := (b + 20) + printf "%d %d %d\n" self.a self.b self.c + return (+ self.a self.b self.c) + } + fun y() { + self.d := (fun(k) { + return (k + 1) + }) + return self.d + } + +}; a := (X:new); v := (a:x) +if (nqv? v 100) { printf "ERROR: v is not 100\n" } \ +else { printf "OK: value is %d\n" v } + +v := ((a:y) 20); +if (nqv? v 21) { printf "ERROR: v is not 21\n" } \ +else { printf "OK: value is %d\n" v }