diff --git a/bin/hcl.c b/bin/hcl.c index 7e13d7e..53d25f8 100644 --- a/bin/hcl.c +++ b/bin/hcl.c @@ -529,7 +529,7 @@ static int on_fed_cnode_in_interactive_mode (hcl_t* hcl, hcl_cnode_t* obj) { /* 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; + flags = HCL_COMPILE_CLEAR_CODE | HCL_COMPILE_CLEAR_FUNBLK; } if (hcl_compile(hcl, obj, flags) <= -1) diff --git a/configure.ac b/configure.ac index bf14886..944b401 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ AC_PREREQ([2.71]) -AC_INIT([hcl],[0.1.0],[Chung, Hyung-Hwan (hyunghwan.chung@gmail.com)],[],[http://code.miflux.com/@hcl]) +AC_INIT([hcl],[0.1.0],[Chung, Hyung-Hwan (hyunghwan.chung@gmail.com)],[],[http://code.miflux.com/hyung-hwan/hcl]) AC_CONFIG_HEADERS([lib/hcl-cfg.h]) AC_CONFIG_AUX_DIR([ac]) diff --git a/lib/comp.c b/lib/comp.c index 0913a61..6828f99 100644 --- a/lib/comp.c +++ b/lib/comp.c @@ -53,7 +53,7 @@ enum enum { /* these enumerators are stored in the lower 8 bits of - * the fun_type field of hcl_fnblk_info_t. + * the fun_type field of hcl_funblk_info_t. * the 9th bit of the field indicate a method is defined * out of a class */ @@ -243,25 +243,25 @@ static void kill_temporary_variable_at_offset (hcl_t* hcl, hcl_oow_t offset) static int is_in_top_scope (hcl_t* hcl) { - hcl_fnblk_info_t* fbi; -/*printf (">>> ---- fnblk.depth ....%d\n", (int)hcl->c->fnblk.depth);*/ - if (hcl->c->fnblk.depth > 0) return 0; - HCL_ASSERT (hcl, hcl->c->fnblk.depth >= 0); - fbi = &hcl->c->fnblk.info[hcl->c->fnblk.depth]; + hcl_funblk_info_t* fbi; +/*printf (">>> ---- funblk.depth ....%d\n", (int)hcl->c->funblk.depth);*/ + if (hcl->c->funblk.depth > 0) return 0; + HCL_ASSERT (hcl, hcl->c->funblk.depth >= 0); + fbi = &hcl->c->funblk.info[hcl->c->funblk.depth]; /*printf ("fbi->clsblk_top....%d\n", (int)fbi->clsblk_top);*/ return fbi->clsblk_top < 0; } static int is_in_top_fun_scope (hcl_t* hcl) { - return hcl->c->fnblk.depth == 0; + return hcl->c->funblk.depth == 0; } static int is_in_class_init_scope (hcl_t* hcl) { - hcl_fnblk_info_t* fbi; - HCL_ASSERT (hcl, hcl->c->fnblk.depth >= 0); - fbi = &hcl->c->fnblk.info[hcl->c->fnblk.depth]; + hcl_funblk_info_t* fbi; + HCL_ASSERT (hcl, hcl->c->funblk.depth >= 0); + fbi = &hcl->c->funblk.info[hcl->c->funblk.depth]; return fbi->clsblk_top >= 0; } @@ -269,16 +269,16 @@ static int is_in_class_method_scope (hcl_t* hcl) { hcl_oow_t i; - HCL_ASSERT (hcl, hcl->c->fnblk.depth >= 0); - for (i = hcl->c->fnblk.depth + 1; i > 0; ) + HCL_ASSERT (hcl, hcl->c->funblk.depth >= 0); + for (i = hcl->c->funblk.depth + 1; i > 0; ) { - hcl_fnblk_info_t* fbi; + hcl_funblk_info_t* fbi; - fbi = &hcl->c->fnblk.info[--i]; + fbi = &hcl->c->funblk.info[--i]; if (fbi->clsblk_top >= 0) { - if (i >= hcl->c->fnblk.depth) return 0; /* in class initialization scope */ + if (i >= hcl->c->funblk.depth) return 0; /* in class initialization scope */ return 1; /* in class method scope */ } } @@ -290,18 +290,18 @@ static int find_variable_backward_with_word (hcl_t* hcl, const hcl_oocs_t* name, { hcl_oow_t i; - HCL_ASSERT (hcl, hcl->c->fnblk.depth >= 0); - HCL_ASSERT (hcl, hcl->c->fnblk.info[hcl->c->fnblk.depth].tmprlen == hcl->c->tv.s.len); + HCL_ASSERT (hcl, hcl->c->funblk.depth >= 0); + HCL_ASSERT (hcl, hcl->c->funblk.info[hcl->c->funblk.depth].tmprlen == hcl->c->tv.s.len); /* depth begins at -1. so it is the actual index. let looping begin at depth + 1 * to avoid an extra exit check without it */ - for (i = hcl->c->fnblk.depth + 1; i > 0; ) + for (i = hcl->c->funblk.depth + 1; i > 0; ) { - hcl_fnblk_info_t* fbi; + hcl_funblk_info_t* fbi; hcl_oocs_t haystack; hcl_oow_t parent_tmprcnt, parent_tmprlen, index; - fbi = &hcl->c->fnblk.info[--i]; + fbi = &hcl->c->funblk.info[--i]; if (fbi->clsblk_top >= 0) { @@ -325,7 +325,7 @@ static int find_variable_backward_with_word (hcl_t* hcl, const hcl_oocs_t* name, { hcl_oow_t fi; - if (i >= hcl->c->fnblk.depth) + if (i >= hcl->c->funblk.depth) { /* instance variables are accessible only in an instance method defintion scope. * it is in class initialization scope */ @@ -333,10 +333,10 @@ static int find_variable_backward_with_word (hcl_t* hcl, const hcl_oocs_t* name, return -1; } - for (fi = hcl->c->fnblk.depth + 1; fi > i; ) /* TOOD: review this loop for correctness */ + for (fi = hcl->c->funblk.depth + 1; fi > i; ) /* TOOD: review this loop for correctness */ { /* 'i' is the function level that holds the class defintion block. the check must not go past it */ - if ((hcl->c->fnblk.info[--fi].fun_type & 0xFF) == FUN_CM) + if ((hcl->c->funblk.info[--fi].fun_type & 0xFF) == FUN_CM) { /* the function where this variable is defined is a class method or an plain function block within a class method*/ hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNED, loc, name, "prohibited access to instance variable in class method context"); @@ -344,7 +344,7 @@ static int find_variable_backward_with_word (hcl_t* hcl, const hcl_oocs_t* name, } /* instance methods and instantiation methods can access instance variables */ - if ((hcl->c->fnblk.info[fi].fun_type & 0xFF) != FUN_PLAIN) break; + if ((hcl->c->funblk.info[fi].fun_type & 0xFF) != FUN_PLAIN) break; } vi->type = VAR_INST; @@ -366,7 +366,7 @@ HCL_INFO6 (hcl, "FOUND INST VAR [%.*js]...[%.*js]................ ===> ctx_offse { /* TODO: VAR_CLASS_CM vs VAR_CLASS_IM, need to know if it's an instance method or a class method */ /* TODO: check if it's in the class variable .... */ - vi->type = (i >= hcl->c->fnblk.depth? VAR_CLASS_I: VAR_CLASS_IM); + vi->type = (i >= hcl->c->funblk.depth? VAR_CLASS_I: VAR_CLASS_IM); vi->ctx_offset = 0; vi->index_in_ctx = index; /* @@ -379,7 +379,7 @@ HCL_INFO6 (hcl, "FOUND CLASS VAR [%.*js]...[%.*js]................ ===> ctx_offs #if 0 } - if (i == hcl->c->fnblk.depth) + if (i == hcl->c->funblk.depth) { /* this condition indicates that the current function level contains a class defintion * and this variable is looked up inside the class defintion */ @@ -397,8 +397,8 @@ HCL_INFO2 (hcl, "CLASS NAMED VAR [%.*js]\n", name->len, name->ptr); if (HCL_LIKELY(i > 0)) { - parent_tmprlen = hcl->c->fnblk.info[i - 1].tmprlen; - parent_tmprcnt = hcl->c->fnblk.info[i - 1].tmprcnt; + parent_tmprlen = hcl->c->funblk.info[i - 1].tmprlen; + parent_tmprcnt = hcl->c->funblk.info[i - 1].tmprcnt; } else { @@ -414,17 +414,17 @@ HCL_INFO2 (hcl, "CLASS NAMED VAR [%.*js]\n", name->len, name->ptr); { /* temporary variables or arguments */ vi->type = VAR_INDEXED; - vi->ctx_offset = hcl->c->fnblk.depth - i; /* context offset */ + vi->ctx_offset = hcl->c->funblk.depth - i; /* context offset */ vi->index_in_ctx = index; /*HCL_INFO4 (hcl, "FOUND ...[%.*js]................ ===> ctx_offset %d index %d\n", name->len, name->ptr, (int)(vi->ctx_offset), (int)vi->index_in_ctx);*/ if (vi->ctx_offset > 0) { /* the current function block accesses temporaries in an outer function block */ - hcl->c->fnblk.info[hcl->c->fnblk.depth].access_outer = 1; + hcl->c->funblk.info[hcl->c->funblk.depth].access_outer = 1; /* temporaries in an outer function block is accessed by the current function block */ - if (i > 0) hcl->c->fnblk.info[i - 1].accessed_by_inner = 1; + if (i > 0) hcl->c->funblk.info[i - 1].accessed_by_inner = 1; } return 1; @@ -533,7 +533,7 @@ ok: static HCL_INLINE int add_literal (hcl_t* hcl, hcl_oop_t obj, hcl_oow_t* index) { hcl_oow_t lfbase; - lfbase = (hcl->option.trait & HCL_TRAIT_INTERACTIVE)? hcl->c->fnblk.info[hcl->c->fnblk.depth].lfbase: 0; + lfbase = (hcl->option.trait & HCL_TRAIT_INTERACTIVE)? hcl->c->funblk.info[hcl->c->funblk.depth].lfbase: 0; return hcl_addliteraltocode(hcl, &hcl->code, obj, lfbase, index); } @@ -982,26 +982,26 @@ static int emit_variable_access (hcl_t* hcl, int mode, const hcl_var_info_t* vi, } /* ========================================================================= */ -static int push_cblk (hcl_t* hcl, const hcl_loc_t* errloc, hcl_cblk_type_t type) +static int push_ctlblk (hcl_t* hcl, const hcl_loc_t* errloc, hcl_ctlblk_type_t type) { hcl_oow_t new_depth; - HCL_ASSERT (hcl, hcl->c->cblk.depth >= -1); + HCL_ASSERT (hcl, hcl->c->ctlblk.depth >= -1); - if (hcl->c->cblk.depth == HCL_TYPE_MAX(hcl_ooi_t)) + if (hcl->c->ctlblk.depth == HCL_TYPE_MAX(hcl_ooi_t)) { hcl_setsynerrbfmt (hcl, HCL_SYNERR_BLKDEPTH, errloc, HCL_NULL, "control block depth too deep"); return -1; } - new_depth = hcl->c->cblk.depth + 1; - if (hcl->c->cblk.depth >= hcl->c->cblk.info_capa) + new_depth = hcl->c->ctlblk.depth + 1; + if (hcl->c->ctlblk.depth >= hcl->c->ctlblk.info_capa) { - hcl_cblk_info_t* tmp; + hcl_ctlblk_info_t* tmp; hcl_oow_t newcapa; newcapa = HCL_ALIGN(new_depth + 1, BLK_INFO_BUFFER_ALIGN); - tmp = (hcl_cblk_info_t*)hcl_reallocmem(hcl, hcl->c->cblk.info, newcapa * HCL_SIZEOF(*tmp)); + tmp = (hcl_ctlblk_info_t*)hcl_reallocmem(hcl, hcl->c->ctlblk.info, newcapa * HCL_SIZEOF(*tmp)); if (HCL_UNLIKELY(!tmp)) { const hcl_ooch_t* orgmsg = hcl_backuperrmsg(hcl); @@ -1009,32 +1009,34 @@ static int push_cblk (hcl_t* hcl, const hcl_loc_t* errloc, hcl_cblk_type_t type) return -1; } - hcl->c->cblk.info_capa = newcapa; - hcl->c->cblk.info = tmp; + hcl->c->ctlblk.info_capa = newcapa; + hcl->c->ctlblk.info = tmp; } - HCL_MEMSET (&hcl->c->cblk.info[new_depth], 0, HCL_SIZEOF(hcl->c->cblk.info[new_depth])); - hcl->c->cblk.info[new_depth]._type = type; - hcl->c->cblk.depth = new_depth; + HCL_MEMSET (&hcl->c->ctlblk.info[new_depth], 0, HCL_SIZEOF(hcl->c->ctlblk.info[new_depth])); + hcl->c->ctlblk.info[new_depth]._type = type; + hcl->c->ctlblk.depth = new_depth; return 0; } -static void pop_cblk (hcl_t* hcl) +static void pop_ctlblk (hcl_t* hcl) { - HCL_ASSERT (hcl, hcl->c->cblk.depth >= 0); /* depth is of a signed type */ + HCL_ASSERT (hcl, hcl->c->ctlblk.depth >= 0); /* depth is of a signed type */ /* a control block stays inside a function block. * the control block stack must not be popped past the starting base * of the owning function block */ - HCL_ASSERT (hcl, hcl->c->cblk.depth - 1 >= hcl->c->fnblk.info[hcl->c->fnblk.depth].cblk_base); - hcl->c->cblk.depth--; + HCL_ASSERT (hcl, hcl->c->ctlblk.depth - 1 >= hcl->c->funblk.info[hcl->c->funblk.depth].ctlblk_base); + hcl->c->ctlblk.depth--; } -static int push_clsblk (hcl_t* hcl, const hcl_loc_t* errloc, hcl_oow_t nivars, hcl_oow_t ncvars, const hcl_ooch_t* ivars_str, hcl_oow_t ivars_strlen, const hcl_ooch_t* cvars_str, hcl_oow_t cvars_strlen) +static int push_clsblk ( + hcl_t* hcl, const hcl_loc_t* errloc, hcl_cnode_t* class_name, hcl_oow_t nivars, hcl_oow_t ncvars, + const hcl_ooch_t* ivars_str, hcl_oow_t ivars_strlen, const hcl_ooch_t* cvars_str, hcl_oow_t cvars_strlen) { hcl_oow_t new_depth; hcl_clsblk_info_t* ci; - hcl_fnblk_info_t* fbi; + hcl_funblk_info_t* fbi; HCL_ASSERT (hcl, hcl->c->clsblk.depth >= -1); @@ -1065,6 +1067,7 @@ static int push_clsblk (hcl_t* hcl, const hcl_loc_t* errloc, hcl_oow_t nivars, h ci = &hcl->c->clsblk.info[new_depth]; HCL_MEMSET (ci, 0, HCL_SIZEOF(*ci)); + ci->class_name = class_name; ci->nivars = nivars; ci->ncvars = ncvars; @@ -1086,10 +1089,10 @@ static int push_clsblk (hcl_t* hcl, const hcl_loc_t* errloc, hcl_oow_t nivars, h } /* remember the function block depth before the class block is entered */ - ci->fnblk_base = hcl->c->fnblk.depth; + ci->funblk_base = hcl->c->funblk.depth; /* attach the class block to the current function block */ - fbi = &hcl->c->fnblk.info[hcl->c->fnblk.depth]; + fbi = &hcl->c->funblk.info[hcl->c->funblk.depth]; if (fbi->clsblk_base <= -1) fbi->clsblk_base = new_depth; fbi->clsblk_top = new_depth; @@ -1099,13 +1102,13 @@ static int push_clsblk (hcl_t* hcl, const hcl_loc_t* errloc, hcl_oow_t nivars, h static void pop_clsblk (hcl_t* hcl) { - hcl_fnblk_info_t* fbi; + hcl_funblk_info_t* fbi; hcl_clsblk_info_t* cbi; HCL_ASSERT (hcl, hcl->c->clsblk.depth >= 0); /* depth is of a signed type */ - HCL_ASSERT (hcl, hcl->c->fnblk.depth >= 0); + HCL_ASSERT (hcl, hcl->c->funblk.depth >= 0); - fbi = &hcl->c->fnblk.info[hcl->c->fnblk.depth]; + fbi = &hcl->c->funblk.info[hcl->c->funblk.depth]; HCL_ASSERT (hcl, fbi->clsblk_base >= 0 && fbi->clsblk_top >= 0 && fbi->clsblk_top >= fbi->clsblk_base); HCL_ASSERT (hcl, fbi->clsblk_top == hcl->c->clsblk.depth); if (fbi->clsblk_top == fbi->clsblk_base) @@ -1134,28 +1137,28 @@ static void pop_clsblk (hcl_t* hcl) } -static int push_fnblk (hcl_t* hcl, const hcl_loc_t* errloc, +static int push_funblk (hcl_t* hcl, const hcl_loc_t* errloc, hcl_oow_t tmpr_va, hcl_oow_t tmpr_nargs, hcl_oow_t tmpr_nrvars, hcl_oow_t tmpr_nlvars, hcl_oow_t tmpr_count, hcl_oow_t tmpr_len, hcl_oow_t make_inst_pos, hcl_oow_t lfbase, unsigned int fun_type) { hcl_oow_t new_depth; - hcl_fnblk_info_t* fbi; + hcl_funblk_info_t* fbi; - HCL_ASSERT (hcl, hcl->c->fnblk.depth >= -1); - if (hcl->c->fnblk.depth == HCL_TYPE_MAX(hcl_ooi_t)) + HCL_ASSERT (hcl, hcl->c->funblk.depth >= -1); + if (hcl->c->funblk.depth == HCL_TYPE_MAX(hcl_ooi_t)) { hcl_setsynerrbfmt (hcl, HCL_SYNERR_BLKDEPTH, errloc, HCL_NULL, "function block depth too deep"); return -1; } - new_depth = hcl->c->fnblk.depth + 1; - if (hcl->c->fnblk.depth >= hcl->c->fnblk.info_capa) + new_depth = hcl->c->funblk.depth + 1; + if (hcl->c->funblk.depth >= hcl->c->funblk.info_capa) { - hcl_fnblk_info_t* tmp; + hcl_funblk_info_t* tmp; hcl_oow_t newcapa; newcapa = HCL_ALIGN(new_depth + 1, BLK_INFO_BUFFER_ALIGN); - tmp = (hcl_fnblk_info_t*)hcl_reallocmem(hcl, hcl->c->fnblk.info, newcapa * HCL_SIZEOF(*tmp)); + tmp = (hcl_funblk_info_t*)hcl_reallocmem(hcl, hcl->c->funblk.info, newcapa * HCL_SIZEOF(*tmp)); if (HCL_UNLIKELY(!tmp)) { const hcl_ooch_t* orgmsg = hcl_backuperrmsg(hcl); @@ -1163,11 +1166,11 @@ static int push_fnblk (hcl_t* hcl, const hcl_loc_t* errloc, return -1; } - hcl->c->fnblk.info_capa = newcapa; - hcl->c->fnblk.info = tmp; + hcl->c->funblk.info_capa = newcapa; + hcl->c->funblk.info = tmp; } - fbi = &hcl->c->fnblk.info[new_depth]; + fbi = &hcl->c->funblk.info[new_depth]; HCL_MEMSET (fbi, 0, HCL_SIZEOF(*fbi)); fbi->fun_type = fun_type; @@ -1180,7 +1183,7 @@ static int push_fnblk (hcl_t* hcl, const hcl_loc_t* errloc, fbi->tmpr_nlvars = tmpr_nlvars; /* remember the control block depth before the function block is entered */ - fbi->cblk_base = hcl->c->cblk.depth; + fbi->ctlblk_base = hcl->c->ctlblk.depth; /* no class block when the funtion block is entered */ fbi->clsblk_base = -1; @@ -1192,42 +1195,42 @@ static int push_fnblk (hcl_t* hcl, const hcl_loc_t* errloc, fbi->access_outer = 0; fbi->accessed_by_inner = 0; - hcl->c->fnblk.depth = new_depth; + hcl->c->funblk.depth = new_depth; return 0; } -static void clear_fnblk_inners (hcl_t* hcl) +static void clear_funblk_inners (hcl_t* hcl) { - hcl_fnblk_info_t* fbi; - fbi = &hcl->c->fnblk.info[hcl->c->fnblk.depth]; - while (hcl->c->cblk.depth > fbi->cblk_base) pop_cblk (hcl); + hcl_funblk_info_t* fbi; + fbi = &hcl->c->funblk.info[hcl->c->funblk.depth]; + while (hcl->c->ctlblk.depth > fbi->ctlblk_base) pop_ctlblk (hcl); while (!(fbi->clsblk_base <= -1 && fbi->clsblk_top <= -1)) pop_clsblk (hcl); } -static void pop_fnblk (hcl_t* hcl) +static void pop_funblk (hcl_t* hcl) { - hcl_fnblk_info_t* fbi; + hcl_funblk_info_t* fbi; - HCL_ASSERT (hcl, hcl->c->fnblk.depth >= 0); + HCL_ASSERT (hcl, hcl->c->funblk.depth >= 0); - 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 + clear_funblk_inners (hcl); + fbi = &hcl->c->funblk.info[hcl->c->funblk.depth]; + /* if pop_ctlblk() 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, hcl->c->ctlblk.depth == fbi->ctlblk_base); HCL_ASSERT (hcl, fbi->clsblk_base <= -1 && fbi->clsblk_top <= -1); - hcl->c->cblk.depth = fbi->cblk_base; + hcl->c->ctlblk.depth = fbi->ctlblk_base; /* keep hcl->code.lit.len without restoration */ - hcl->c->fnblk.depth--; + hcl->c->funblk.depth--; - if (hcl->c->fnblk.depth >= 0) + if (hcl->c->funblk.depth >= 0) { /* restore the string length and the word count to the values captured * at the previous level */ - hcl->c->tv.s.len = hcl->c->fnblk.info[hcl->c->fnblk.depth].tmprlen; - hcl->c->tv.wcount = hcl->c->fnblk.info[hcl->c->fnblk.depth].tmprcnt; + hcl->c->tv.s.len = hcl->c->funblk.info[hcl->c->funblk.depth].tmprlen; + hcl->c->tv.wcount = hcl->c->funblk.info[hcl->c->funblk.depth].tmprcnt; } else { @@ -1654,7 +1657,6 @@ enum COP_COMPILE_CLASS_P1, COP_COMPILE_CLASS_P2, - COP_COMPILE_CLASS_P3, COP_EMIT_PUSH_NIL, COP_EMIT_PUSH_SYMBOL, @@ -1978,19 +1980,19 @@ static int compile_break (hcl_t* hcl, hcl_cnode_t* src) return -1; } - for (i = hcl->c->cblk.depth; i > hcl->c->fnblk.info[hcl->c->fnblk.depth].cblk_base; --i) + for (i = hcl->c->ctlblk.depth; i > hcl->c->funblk.info[hcl->c->funblk.depth].ctlblk_base; --i) { - switch (hcl->c->cblk.info[i]._type) + switch (hcl->c->ctlblk.info[i]._type) { - case HCL_CBLK_TYPE_LOOP: + case HCL_CTLBLK_TYPE_LOOP: goto inside_loop; - case HCL_CBLK_TYPE_TRY: + case HCL_CTLBLK_TYPE_TRY: /* emit an instruction to exit from the try loop. */ if (emit_byte_instruction(hcl, HCL_CODE_TRY_EXIT, HCL_CNODE_GET_LOC(src)) <= -1) return -1; break; - case HCL_CBLK_TYPE_CLASS: + case HCL_CTLBLK_TYPE_CLASS: /* emit an instruction to exit from the class definition scope being defined */ if (emit_byte_instruction(hcl, HCL_CODE_CLASS_EXIT, HCL_CNODE_GET_LOC(src)) <= -1) return -1; break; @@ -2093,19 +2095,19 @@ static int compile_continue (hcl_t* hcl, hcl_cnode_t* src) return -1; } - for (i = hcl->c->cblk.depth; i > hcl->c->fnblk.info[hcl->c->fnblk.depth].cblk_base; --i) + for (i = hcl->c->ctlblk.depth; i > hcl->c->funblk.info[hcl->c->funblk.depth].ctlblk_base; --i) { - switch (hcl->c->cblk.info[i]._type) + switch (hcl->c->ctlblk.info[i]._type) { - case HCL_CBLK_TYPE_LOOP: + case HCL_CTLBLK_TYPE_LOOP: goto inside_loop; - case HCL_CBLK_TYPE_TRY: + case HCL_CTLBLK_TYPE_TRY: /*must emit an instruction to exit from the try loop.*/ if (emit_byte_instruction(hcl, HCL_CODE_TRY_EXIT, HCL_CNODE_GET_LOC(src)) <= -1) return -1; break; - case HCL_CBLK_TYPE_CLASS: + case HCL_CTLBLK_TYPE_CLASS: if (emit_byte_instruction(hcl, HCL_CODE_CLASS_EXIT, HCL_CNODE_GET_LOC(src)) <= -1) return -1; break; } @@ -2151,7 +2153,7 @@ static int compile_expression_block (hcl_t* hcl, hcl_cnode_t* src, const hcl_bch { hcl_cnode_t* cmd, * obj; hcl_oow_t nlvars, tvslen; - hcl_fnblk_info_t* fbi; + hcl_funblk_info_t* fbi; hcl_cframe_t* cf; if (flags & CEB_IS_BLOCK) @@ -2230,7 +2232,7 @@ static int compile_expression_block (hcl_t* hcl, hcl_cnode_t* src, const hcl_bch } #endif - fbi = &hcl->c->fnblk.info[hcl->c->fnblk.depth]; + fbi = &hcl->c->funblk.info[hcl->c->funblk.depth]; fbi->tmprlen = hcl->c->tv.s.len; fbi->tmprcnt = hcl->c->tv.wcount; fbi->tmpr_nlvars = fbi->tmpr_nlvars + nlvars; @@ -2606,7 +2608,7 @@ static int check_class_attr_list (hcl_t* hcl, hcl_cnode_t* attr_list, unsigned i { hcl_setsynerrbfmt ( hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(attr), HCL_NULL, - "unrecognized class attribute name '%.*js'", toklen, tokptr); + "unrecognized class attribute name '#%.*js'", toklen, tokptr); return -1; } @@ -2810,6 +2812,7 @@ static int compile_class (hcl_t* hcl, hcl_cnode_t* src) cf->u._class.indexed_type = indexed_type; cf->u._class.start_loc = *HCL_CNODE_GET_LOC(src); /* TODO: use *HCL_CNODE_GET_LOC(cmd) instead? */ cf->u._class.cmd_cnode = cmd; + cf->u._class.class_name_cnode = class_name; /* duplicate with operand to COP_COMPILE_CLASS_P2 */ PUSH_CFRAME (hcl, COP_COMPILE_CLASS_P1, obj); /* 2 - variables declaraions and actual body */ cf = GET_TOP_CFRAME(hcl); @@ -2817,6 +2820,7 @@ static int compile_class (hcl_t* hcl, hcl_cnode_t* src) cf->u._class.indexed_type = indexed_type; cf->u._class.start_loc = *HCL_CNODE_GET_LOC(src); /* TODO: use *HCL_CNODE_GET_LOC(cmd) instead? */ cf->u._class.cmd_cnode = cmd; + cf->u._class.class_name_cnode = class_name; if (superclass) PUSH_CFRAME (hcl, COP_COMPILE_OBJECT, superclass); /* 1 - superclass expression */ return 0; @@ -2879,7 +2883,9 @@ static HCL_INLINE int compile_class_p1 (hcl_t* hcl) if (vardcl.ncvars > HCL_SMOOI_MAX) { /* TOOD: change the error location ?? */ - hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARFLOOD, HCL_CNODE_GET_LOC(cf->operand), HCL_NULL, "too many(%zu) class variables", vardcl.ncvars); + hcl_setsynerrbfmt ( + hcl, HCL_SYNERR_VARFLOOD, HCL_CNODE_GET_LOC(cf->operand), HCL_NULL, + "too many(%zu) class variables", vardcl.ncvars); goto oops; } @@ -2891,8 +2897,11 @@ static HCL_INLINE int compile_class_p1 (hcl_t* hcl) if (check_block_expression_as_body(hcl, obj, cf->u._class.cmd_cnode, FOR_CLASS) <= -1) return -1; - if (push_clsblk(hcl, &cf->u._class.start_loc, vardcl.nivars, vardcl.ncvars, &hcl->c->tv.s.ptr[vardcl.ivar_start], vardcl.ivar_len, &hcl->c->tv.s.ptr[vardcl.cvar_start], vardcl.cvar_len) <= -1) goto oops; - if (push_cblk(hcl, &cf->u._class.start_loc, HCL_CBLK_TYPE_CLASS) <= -1) goto oops; /* the class block shall be treated as a control block, too */ + if (push_clsblk(hcl, &cf->u._class.start_loc, + cf->u._class.class_name_cnode, vardcl.nivars, vardcl.ncvars, + &hcl->c->tv.s.ptr[vardcl.ivar_start], vardcl.ivar_len, + &hcl->c->tv.s.ptr[vardcl.cvar_start], vardcl.cvar_len) <= -1) goto oops; + if (push_ctlblk(hcl, &cf->u._class.start_loc, HCL_CTLBLK_TYPE_CLASS) <= -1) goto oops; /* the class block shall be treated as a control block, too */ /* discard the instance variables and class variables in the temporary variable collection buffer * because they have been pushed to the class block structure */ @@ -2921,27 +2930,12 @@ oops: return -1; } -static HCL_INLINE int compile_class_p3 (hcl_t* hcl) -{ - hcl_cframe_t* cf; - - cf = GET_TOP_CFRAME(hcl); - HCL_ASSERT (hcl, cf->opcode == COP_COMPILE_CLASS_P3); - - /* should i make the assignment in POST? or after variable declarations immediately? */ -/* TODO: emit instruction to store into the class name...? */ -/* TODO: NEED TO EMIT POP_STACKTOP???? IN THIS CASE CLASS_EXIT MUST PUSH SOMETHING? */ - if (emit_byte_instruction(hcl, HCL_CODE_CLASS_EXIT, HCL_CNODE_GET_LOC(cf->operand)) <= -1) return -1; - - POP_CFRAME (hcl); - return 0; -} - static HCL_INLINE int compile_class_p2 (hcl_t* hcl) { hcl_cframe_t* cf; hcl_cnode_t* class_name; hcl_loc_t class_loc; + hcl_clsblk_info_t* cbi; cf = GET_TOP_CFRAME(hcl); HCL_ASSERT (hcl, cf->opcode == COP_COMPILE_CLASS_P2); @@ -2956,7 +2950,10 @@ static HCL_INLINE int compile_class_p2 (hcl_t* hcl) if (emit_byte_instruction(hcl, HCL_CODE_POP_STACKTOP, &class_loc) <= -1) return -1; } - pop_cblk (hcl); + cbi = &hcl->c->clsblk.info[hcl->c->clsblk.depth]; +/* TODO: PATCH THE CLASS_ENTER instruction */ + + pop_ctlblk (hcl); pop_clsblk (hcl); /* end of the class block */ if (emit_byte_instruction(hcl, HCL_CODE_CLASS_PEXIT, &class_loc) <= -1) return -1; /* pop + exit */ @@ -3064,7 +3061,7 @@ static int check_fun_attr_list (hcl_t* hcl, hcl_cnode_t* attr_list, unsigned int { hcl_setsynerrbfmt ( hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(a), HCL_NULL, - "unrecognized function attribute name '%.*js'", toklen, tokptr); + "unrecognized function attribute name '#%.*js'", toklen, tokptr); return -1; } @@ -3517,7 +3514,7 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src) HCL_ASSERT (hcl, nargs + nrvars + nlvars == hcl->c->tv.wcount - saved_tv_wcount); - if (push_fnblk( + if (push_funblk( 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, fun_type) <= -1) return -1; @@ -3526,13 +3523,13 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src) /* MAKE_FUNCTION attr_mask_1 attr_mask_2 lfbase lfsize */ if (emit_double_param_instruction(hcl, HCL_CODE_MAKE_FUNCTION, 0, 0, HCL_CNODE_GET_LOC(cmd)) <= -1) return -1; lfbase_pos = hcl->code.bc.len; - if (emit_long_param(hcl, hcl->code.lit.len - hcl->c->fnblk.info[hcl->c->fnblk.depth - 1].lfbase) <= -1) return -1; /* lfbase(literal frame base) */ + if (emit_long_param(hcl, hcl->code.lit.len - hcl->c->funblk.info[hcl->c->funblk.depth - 1].lfbase) <= -1) return -1; /* lfbase(literal frame base) */ lfsize_pos = hcl->code.bc.len; /* literal frame size */ if (emit_long_param(hcl, 0) <= -1) return -1; /* place holder for lfsize */ } else { - /* MAKE_BLOCK attr_mask_1 attr_mask_2 - will patch attr_mask in pop_fnblk() */ + /* MAKE_BLOCK attr_mask_1 attr_mask_2 - will patch attr_mask in pop_funblk() */ if (emit_double_param_instruction(hcl, HCL_CODE_MAKE_BLOCK, 0, 0, HCL_CNODE_GET_LOC(cmd)) <= -1) return -1; } @@ -3561,34 +3558,223 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src) return 0; } +/* ========================================================================= */ + +static int check_var_attr_list (hcl_t* hcl, hcl_cnode_t* attr_list, unsigned int* var_type, hcl_cnode_t* cmd, hcl_cnode_t* class_name, hcl_cnode_t* var_name) +{ + unsigned int ft; + + ft = VAR_INST; + + HCL_ASSERT (hcl, attr_list != HCL_NULL); + HCL_ASSERT (hcl, HCL_CNODE_IS_CONS_CONCODED(attr_list, HCL_CONCODE_XLIST) || + HCL_CNODE_IS_ELIST_CONCODED(attr_list, HCL_CONCODE_XLIST)); + + if (HCL_CNODE_IS_ELIST_CONCODED(attr_list, HCL_CONCODE_XLIST)) + { + /* don't allow empty attribute list */ + if (class_name) + { + hcl_setsynerrbfmt ( + hcl, HCL_SYNERR_VAR, HCL_CNODE_GET_LOC(attr_list), HCL_NULL, + "empty attribute list on '%.*js' in '%.*js' for '%.*js'", + HCL_CNODE_GET_TOKLEN(var_name), HCL_CNODE_GET_TOKPTR(var_name), + HCL_CNODE_GET_TOKLEN(class_name), HCL_CNODE_GET_TOKPTR(class_name), + HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); + } + else + { + hcl_setsynerrbfmt ( + hcl, HCL_SYNERR_VAR, HCL_CNODE_GET_LOC(attr_list), HCL_NULL, + "empty attribute list on '%.*js' in unnamed class for '%.*js'", + HCL_CNODE_GET_TOKLEN(var_name), HCL_CNODE_GET_TOKPTR(var_name), + HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); + } + return -1; + } + + if (HCL_CNODE_IS_CONS_CONCODED(attr_list, HCL_CONCODE_XLIST)) + { + hcl_cnode_t* c, * a; + const hcl_ooch_t* tokptr; + hcl_oow_t toklen; + + c = attr_list; + while (c) + { + a = HCL_CNODE_CONS_CAR(c); + + tokptr = HCL_CNODE_GET_TOKPTR(a); + toklen = HCL_CNODE_GET_TOKLEN(a); + + if (!HCL_CNODE_IS_TYPED(a, HCL_CNODE_SYMLIT)) + { + hcl_setsynerrbfmt ( + hcl, HCL_SYNERR_VAR, HCL_CNODE_GET_LOC(a), HCL_NULL, + "invalid variable attribute name '%.*js'", toklen, tokptr); + return -1; + } + + if (hcl_comp_oochars_bcstr(tokptr, toklen, "class") == 0 || + hcl_comp_oochars_bcstr(tokptr, toklen, "c") == 0) + { + if (ft != FUN_IM) + { + conflicting: + hcl_setsynerrbfmt ( + hcl, HCL_SYNERR_VAR, HCL_CNODE_GET_LOC(a), HCL_NULL, + "conflicting variable attribute name '#%.*js'", toklen, tokptr); + return -1; + } + ft = VAR_CLASS_I; + } + else + { + hcl_setsynerrbfmt ( + hcl, HCL_SYNERR_VAR, HCL_CNODE_GET_LOC(a), HCL_NULL, + "unrecognized variable attribute name '#%.*js'", toklen, tokptr); + return -1; + } + + c = HCL_CNODE_CONS_CDR(c); + } + } + + *var_type = ft; + return 0; +} + +static int compile_var (hcl_t* hcl, hcl_cnode_t* src) +{ + hcl_cnode_t* cmd, * next, * tmp; + hcl_cnode_t* attr_list; + hcl_clsblk_info_t* cbi; + + /* this is for install/class variable declaration. + * and generates no instruction */ + + cmd = HCL_CNODE_CONS_CAR(src); + next = HCL_CNODE_CONS_CDR(src); + attr_list = HCL_NULL; + +/*TODO: put some assertion regarding funblk to cslblk relaion */ + cbi = &hcl->c->clsblk.info[hcl->c->clsblk.depth]; + + HCL_ASSERT (hcl, HCL_CNODE_IS_TYPED(cmd, HCL_CNODE_VAR)); + + if (!next) + { + hcl_setsynerrbfmt ( + hcl, HCL_SYNERR_VAR, HCL_CNODE_GET_LOC(cmd), HCL_NULL, + "'%.*js' not followed by name or (", + HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); + return -1; + } + + /* the reader ensures that the cdr field of a cons cell points to the next cell. + * and only the field of the last cons cell is NULL. */ + HCL_ASSERT (hcl, HCL_CNODE_IS_CONS(next)); + + if (!is_in_class_init_scope(hcl)) + { + hcl_setsynerrbfmt ( + hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(cmd), HCL_NULL, + "'%.*js' prohibited in this context", + HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); + return -1; + } + + tmp = HCL_CNODE_CONS_CAR(next); + if (HCL_CNODE_IS_CONS_CONCODED(tmp, HCL_CONCODE_XLIST) || + HCL_CNODE_IS_ELIST_CONCODED(tmp, HCL_CONCODE_XLIST)) + { + /* probably attribute list */ + attr_list = tmp; + + next = HCL_CNODE_CONS_CDR(next); + if (!next) + { + hcl_setsynerrbfmt ( + hcl, HCL_SYNERR_VAR, HCL_CNODE_GET_LOC(attr_list), HCL_NULL, + "no name after attribute list for '%.*js'", + HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); + return -1; + } + + tmp = HCL_CNODE_CONS_CAR(next); + } + + if (HCL_CNODE_IS_SYMBOL_IDENT(tmp)) + { + unsigned int var_type; + + if (attr_list && check_var_attr_list(hcl, attr_list, &var_type, cmd, cbi->class_name, tmp) <= -1) return -1; + + HCL_ASSERT (hcl, var_type == VAR_INST || var_type == VAR_CLASS_I); + while (1) + { + /* TODO: do something here */ +hcl_logbfmt(hcl, HCL_LOG_STDERR, "VAR=[%.*js]\n", HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp)); + if (var_type == VAR_INST) + { + cbi->nivars++; +/* TODO: update cbi->nivars_name... */ + } + else + { + cbi->ncvars++; +/* TODO: update cbi->ncvars_name... */ + } + + + next = HCL_CNODE_CONS_CDR(next); + if (!next) break; + tmp = HCL_CNODE_CONS_CAR(next); + if (!HCL_CNODE_IS_SYMBOL_IDENT(tmp)) goto not_ident; + } + } + else + { + not_ident: + hcl_setsynerrbfmt ( + hcl, HCL_SYNERR_VAR, HCL_CNODE_GET_LOC(tmp), HCL_NULL, + "invalid variable name '%.*js' for '%.*js'", + HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp), + HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); + return -1; + } + + POP_CFRAME (hcl); + return 0; +} static int compile_return (hcl_t* hcl, hcl_cnode_t* src, int ret_from_home) { hcl_cnode_t* obj, * val; hcl_cframe_t* cf; - hcl_fnblk_info_t* fbi; + hcl_funblk_info_t* fbi; hcl_ooi_t i; HCL_ASSERT (hcl, HCL_CNODE_IS_CONS(src)); HCL_ASSERT (hcl, HCL_CNODE_IS_TYPED(HCL_CNODE_CONS_CAR(src), HCL_CNODE_RETURN) || HCL_CNODE_IS_TYPED(HCL_CNODE_CONS_CAR(src), HCL_CNODE_REVERT)); - fbi = &hcl->c->fnblk.info[hcl->c->fnblk.depth]; + fbi = &hcl->c->funblk.info[hcl->c->funblk.depth]; obj = HCL_CNODE_CONS_CDR(src); - for (i = hcl->c->cblk.depth; i > hcl->c->fnblk.info[hcl->c->fnblk.depth].cblk_base; --i) + for (i = hcl->c->ctlblk.depth; i > hcl->c->funblk.info[hcl->c->funblk.depth].ctlblk_base; --i) { - switch (hcl->c->cblk.info[i]._type) + switch (hcl->c->ctlblk.info[i]._type) { - case HCL_CBLK_TYPE_LOOP: + case HCL_CTLBLK_TYPE_LOOP: /* do nothing */ break; - case HCL_CBLK_TYPE_TRY: + case HCL_CTLBLK_TYPE_TRY: if (emit_byte_instruction(hcl, HCL_CODE_TRY_EXIT, HCL_CNODE_GET_LOC(src)) <= -1) return -1; break; - case HCL_CBLK_TYPE_CLASS: + case HCL_CTLBLK_TYPE_CLASS: if (emit_byte_instruction(hcl, HCL_CODE_CLASS_EXIT, HCL_CNODE_GET_LOC(src)) <= -1) return -1; break; } @@ -3600,7 +3786,10 @@ static int compile_return (hcl_t* hcl, hcl_cnode_t* src, int ret_from_home) if (ret_from_home) { - hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(src), HCL_NULL, "%.*js not compatible with return variables", HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp)); + hcl_setsynerrbfmt ( + hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(src), HCL_NULL, + "%.*js not compatible with return variables", + HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp)); return -1; } @@ -3896,7 +4085,7 @@ static int compile_try (hcl_t* hcl, hcl_cnode_t* src) return -1; } - if (push_cblk(hcl, HCL_CNODE_GET_LOC(src), HCL_CBLK_TYPE_TRY) <= -1) return -1; + if (push_ctlblk(hcl, HCL_CNODE_GET_LOC(src), HCL_CTLBLK_TYPE_TRY) <= -1) return -1; /* TODO: HCL_TRAIT_INTERACTIVE??? */ @@ -3960,7 +4149,7 @@ static HCL_INLINE int compile_catch (hcl_t* hcl) hcl_ooi_t jump_inst_pos; hcl_oow_t exarg_offset; hcl_var_info_t vi; - hcl_fnblk_info_t* fbi; + hcl_funblk_info_t* fbi; hcl_oow_t par_tmprcnt; cf = GET_TOP_CFRAME(hcl); @@ -4009,9 +4198,9 @@ static HCL_INLINE int compile_catch (hcl_t* hcl) /* add the exception variable to the local variable list. increase the number of local variables */ exarg_offset = hcl->c->tv.s.len + 1; /* when the variable name is added, its offset will be the current length + 1 for a space character added */ - if (hcl->c->fnblk.depth > 0) + if (hcl->c->funblk.depth > 0) { - fbi = &hcl->c->fnblk.info[hcl->c->fnblk.depth - 1]; /* parent block */ + fbi = &hcl->c->funblk.info[hcl->c->funblk.depth - 1]; /* parent block */ par_tmprcnt = fbi->tmprcnt; } else @@ -4027,7 +4216,7 @@ static HCL_INLINE int compile_catch (hcl_t* hcl) vi.index_in_ctx = hcl->c->tv.wcount - par_tmprcnt; if (add_temporary_variable(hcl, HCL_CNODE_GET_TOK(exarg), hcl->c->tv.s.len) <= -1) return -1; - fbi = &hcl->c->fnblk.info[hcl->c->fnblk.depth]; + fbi = &hcl->c->funblk.info[hcl->c->funblk.depth]; HCL_ASSERT (hcl, fbi->tmprlen == hcl->c->tv.s.len - HCL_CNODE_GET_TOKLEN(exarg) - 1); HCL_ASSERT (hcl, fbi->tmprcnt == vi.index_in_ctx + par_tmprcnt); fbi->tmprlen = hcl->c->tv.s.len; @@ -4058,7 +4247,7 @@ static HCL_INLINE int compile_catch (hcl_t* hcl) static HCL_INLINE int post_try (hcl_t* hcl) { /* TODO: anything else? */ - pop_cblk (hcl); + pop_ctlblk (hcl); POP_CFRAME (hcl); return 0; } @@ -4179,7 +4368,7 @@ static int compile_while (hcl_t* hcl, hcl_cnode_t* src, int next_cop) return -1; } - if (push_cblk(hcl, HCL_CNODE_GET_LOC(src), HCL_CBLK_TYPE_LOOP) <= -1) return -1; + if (push_ctlblk(hcl, HCL_CNODE_GET_LOC(src), HCL_CTLBLK_TYPE_LOOP) <= -1) return -1; HCL_ASSERT (hcl, hcl->code.bc.len < HCL_SMOOI_MAX); cond_pos = hcl->code.bc.len; /* position where the bytecode for the conditional is emitted */ @@ -4443,6 +4632,10 @@ static int compile_cons_xlist_expression (hcl_t* hcl, hcl_cnode_t* obj, int nret if (compile_fun(hcl, obj) <= -1) return -1; goto done; + case HCL_CNODE_VAR: + if (compile_var(hcl, obj) <= -1) return -1; + goto done; + case HCL_CNODE_DO: if (compile_do(hcl, obj) <= -1) return -1; goto done; @@ -4794,10 +4987,10 @@ static HCL_INLINE int compile_dsymbol (hcl_t* hcl, hcl_cnode_t* obj) hcl_oocs_t name; int x = 0; hcl_var_info_t vi; - hcl_fnblk_info_t* fbi; + hcl_funblk_info_t* fbi; name = *HCL_CNODE_GET_TOK(obj); - fbi = &hcl->c->fnblk.info[hcl->c->fnblk.depth]; + fbi = &hcl->c->funblk.info[hcl->c->funblk.depth]; sep = hcl_find_oochar(name.ptr, name.len, '.'); HCL_ASSERT (hcl, sep != HCL_NULL); @@ -5131,8 +5324,6 @@ static int compile_symbol_literal (hcl_t* hcl) oprnd = cf->operand; HCL_ASSERT (hcl, HCL_CNODE_GET_TYPE(oprnd) == HCL_CNODE_SYMBOL); - /* treat a symbol as a string */ - /* TODO: do i need to create a symbol literal like smalltalk? */ lit = hcl_makesymbol(hcl, HCL_CNODE_GET_TOKPTR(oprnd), HCL_CNODE_GET_TOKLEN(oprnd)); if (HCL_UNLIKELY(!lit)) return -1; @@ -5368,7 +5559,7 @@ redo: return -1; } - /* the control reaches here in case a compile_xxxx() functionse.g. compile_cons_xlist_expression) is called. + /* the control reaches here in case a compile_xxxx() function(e.g. compile_cons_xlist_expression()) is called. * such a function removes the top cframe. so POP_CFRAME() needs not be called here */ return 0; @@ -5920,8 +6111,8 @@ static HCL_INLINE int post_while_body (hcl_t* hcl) POP_CFRAME (hcl); - HCL_ASSERT (hcl, hcl->c->cblk.info[hcl->c->cblk.depth]._type == HCL_CBLK_TYPE_LOOP); - pop_cblk (hcl); + HCL_ASSERT (hcl, hcl->c->ctlblk.info[hcl->c->ctlblk.depth]._type == HCL_CTLBLK_TYPE_LOOP); + pop_ctlblk (hcl); return 0; } @@ -6137,7 +6328,7 @@ static HCL_INLINE int emit_fun (hcl_t* hcl) hcl_cframe_t* cf; hcl_oow_t block_code_size, lfsize; hcl_ooi_t jip; - hcl_fnblk_info_t* fbi; + hcl_funblk_info_t* fbi; hcl_loc_t* oploc; cf = GET_TOP_CFRAME(hcl); @@ -6145,11 +6336,11 @@ static HCL_INLINE int emit_fun (hcl_t* hcl) HCL_ASSERT (hcl, cf->operand != HCL_NULL); oploc = HCL_CNODE_GET_LOC(cf->operand); - fbi = &hcl->c->fnblk.info[hcl->c->fnblk.depth]; + fbi = &hcl->c->funblk.info[hcl->c->funblk.depth]; jip = cf->u.fun.jump_inst_pos; if (hcl->option.trait & HCL_TRAIT_INTERACTIVE) - lfsize = hcl->code.lit.len - hcl->c->fnblk.info[hcl->c->fnblk.depth].lfbase; + lfsize = hcl->code.lit.len - hcl->c->funblk.info[hcl->c->funblk.depth].lfbase; /* HCL_CODE_LONG_PARAM_SIZE + 1 => size of the long JUMP_FORWARD instruction */ block_code_size = hcl->code.bc.len - jip - (HCL_CODE_LONG_PARAM_SIZE + 1); @@ -6232,10 +6423,10 @@ static HCL_INLINE int post_fun (hcl_t* hcl) cf = GET_TOP_CFRAME(hcl); HCL_ASSERT (hcl, cf->opcode == COP_POST_FUN); - /*hcl->c->fnblk.depth--; - hcl->c->tv.s.len = hcl->c->fnblk.info[hcl->c->fnblk.depth].tmprlen; - hcl->c->tv.wcount = hcl->c->fnblk.info[hcl->c->fnblk.depth].tmprcnt;*/ - pop_fnblk (hcl); + /*hcl->c->funblk.depth--; + hcl->c->tv.s.len = hcl->c->funblk.info[hcl->c->funblk.depth].tmprlen; + hcl->c->tv.wcount = hcl->c->funblk.info[hcl->c->funblk.depth].tmprcnt;*/ + pop_funblk (hcl); if (cf->operand) { @@ -6532,15 +6723,15 @@ 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; - hcl_fnblk_info_t top_fnblk_saved; - int top_fnblk_pushed_here = 0; + hcl_funblk_info_t top_funblk_saved; + int top_funblk_pushed_here = 0; hcl->c->flags = flags; - HCL_ASSERT (hcl, hcl->c->fnblk.depth <= 0); /* 0 or 1 fnblk must exist at this phase */ + HCL_ASSERT (hcl, hcl->c->funblk.depth <= 0); /* 0 or 1 funblk must exist at this phase */ HCL_ASSERT (hcl, GET_TOP_CFRAME_INDEX(hcl) < 0); - if (flags & HCL_COMPILE_CLEAR_FNBLK) + if (flags & HCL_COMPILE_CLEAR_FUNBLK) { /* if the program is executed in the interactive mode, * each compiled expression is executed immediately. @@ -6559,7 +6750,7 @@ int hcl_compile (hcl_t* hcl, hcl_cnode_t* obj, int flags) * in the non-interactive mode, * (1) is compiled, (2) is compiled, (3) is compiled * (1), (2), (3) are executed - * fnblk holds information about temporaries seen so far. + * funblk holds information about temporaries seen so far. * (2) has defined two temporary variables. this count * must get carried until (3) has been compiled in the * non-interactive mode. the accumulated count is used @@ -6568,8 +6759,8 @@ int hcl_compile (hcl_t* hcl, hcl_cnode_t* obj, int flags) * in the interactive mode, the information doesn't have * to get carried over. */ - while (hcl->c->fnblk.depth >= 0) pop_fnblk (hcl); - HCL_ASSERT (hcl, hcl->c->fnblk.depth == -1); + while (hcl->c->funblk.depth >= 0) pop_funblk (hcl); + HCL_ASSERT (hcl, hcl->c->funblk.depth == -1); /* it will be recreated below */ } if (flags & HCL_COMPILE_CLEAR_CODE) hcl_clearcode (hcl); @@ -6612,20 +6803,20 @@ 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); + HCL_ASSERT (hcl, hcl->c->ctlblk.depth == -1); - if (hcl->c->fnblk.depth <= -1) + if (hcl->c->funblk.depth <= -1) { - HCL_ASSERT (hcl, hcl->c->fnblk.depth == -1); + HCL_ASSERT (hcl, hcl->c->funblk.depth == -1); HCL_ASSERT (hcl, hcl->c->tv.s.len == 0); HCL_ASSERT (hcl, hcl->c->tv.wcount == 0); /* keep a virtual function block for the top-level compilation. * pass HCL_TYPE_MAX(hcl_oow_t) as make_inst_pos because there is * no actual MAKE_BLOCK/MAKE_FUNCTION instruction which otherwise - * would be patched in pop_fnblk(). */ + * would be patched in pop_funblk(). */ - if (push_fnblk( + if (push_funblk( hcl, HCL_NULL, 0, /* tmpr_va */ 0, /* tmpr_nargs */ @@ -6638,10 +6829,10 @@ int hcl_compile (hcl_t* hcl, hcl_cnode_t* obj, int flags) FUN_PLAIN /* fun_type */ ) <= -1) return -1; /* must not goto oops */ - top_fnblk_pushed_here = 1; + top_funblk_pushed_here = 1; } - top_fnblk_saved = hcl->c->fnblk.info[0]; - HCL_ASSERT (hcl, hcl->c->fnblk.depth == 0); /* ensure the virtual function block is added */ + top_funblk_saved = hcl->c->funblk.info[0]; + HCL_ASSERT (hcl, hcl->c->funblk.depth == 0); /* ensure the virtual function block is added */ PUSH_CFRAME (hcl, COP_COMPILE_OBJECT, obj); @@ -6724,10 +6915,6 @@ int hcl_compile (hcl_t* hcl, hcl_cnode_t* obj, int flags) if (compile_class_p2(hcl) <= -1) goto oops; break; - case COP_COMPILE_CLASS_P3: - if (compile_class_p3(hcl) <= -1) goto oops; - break; - case COP_COMPILE_DO_P1: if (compile_do_p1(hcl) <= -1) goto oops; break; @@ -6872,15 +7059,15 @@ int hcl_compile (hcl_t* hcl, hcl_cnode_t* obj, int flags) if (emit_byte_instruction(hcl, HCL_CODE_POP_STACKTOP, HCL_NULL) <= -1) goto oops; HCL_ASSERT (hcl, GET_TOP_CFRAME_INDEX(hcl) < 0); - HCL_ASSERT (hcl, hcl->c->tv.s.len >= hcl->c->fnblk.info[0].tmprlen); - HCL_ASSERT (hcl, hcl->c->tv.wcount >= hcl->c->fnblk.info[0].tmprcnt); - HCL_ASSERT (hcl, hcl->c->cblk.depth == -1); /* no control blocks expected at this point */ + HCL_ASSERT (hcl, hcl->c->tv.s.len >= hcl->c->funblk.info[0].tmprlen); + HCL_ASSERT (hcl, hcl->c->tv.wcount >= hcl->c->funblk.info[0].tmprcnt); + HCL_ASSERT (hcl, hcl->c->ctlblk.depth == -1); /* no control blocks expected at this point */ - 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 */ + HCL_ASSERT (hcl, hcl->c->funblk.depth == 0); /* ensure the virtual function block be the only one left */ + hcl->code.ngtmprs = hcl->c->funblk.info[0].tmprcnt; /* populate the number of global temporary variables */ -#if defined(CLEAR_FNBLK_ALWAYS) - pop_fnblk (hcl); +#if defined(CLEAR_FUNBLK_ALWAYS) + pop_funblk (hcl); HCL_ASSERT (hcl, hcl->c->tv.s.len == 0); HCL_ASSERT (hcl, hcl->c->tv.wcount == 0); #endif @@ -6897,13 +7084,13 @@ oops: hcl->code.bc.len = saved_bc_len; hcl->code.lit.len = saved_lit_len; - while (hcl->c->fnblk.depth > 0) pop_fnblk (hcl); - HCL_ASSERT (hcl, hcl->c->fnblk.depth == 0); + while (hcl->c->funblk.depth > 0) pop_funblk (hcl); + HCL_ASSERT (hcl, hcl->c->funblk.depth == 0); - if (top_fnblk_pushed_here) + if (top_funblk_pushed_here) { - pop_fnblk (hcl); - HCL_ASSERT (hcl, hcl->c->fnblk.depth == -1); + pop_funblk (hcl); + HCL_ASSERT (hcl, hcl->c->funblk.depth == -1); HCL_ASSERT (hcl, hcl->c->tv.s.len == 0); HCL_ASSERT (hcl, hcl->c->tv.wcount == 0); } @@ -6919,11 +7106,11 @@ oops: */ /* 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; - hcl->c->tv.s.len = top_fnblk_saved.tmprlen; - hcl->c->tv.wcount = top_fnblk_saved.tmprcnt; + clear_funblk_inners (hcl); + HCL_ASSERT (hcl, hcl->c->funblk.depth == 0); + hcl->c->funblk.info[0] = top_funblk_saved; + hcl->c->tv.s.len = top_funblk_saved.tmprlen; + hcl->c->tv.wcount = top_funblk_saved.tmprcnt; } return -1; diff --git a/lib/err.c b/lib/err.c index 3570beb..376b57b 100644 --- a/lib/err.c +++ b/lib/err.c @@ -154,6 +154,7 @@ static const char* synerrstr[] = "invalid class definition", "invalid function definition", + "invalid variable declaration", "elif without if", "else without if", "catch without try", diff --git a/lib/exec.c b/lib/exec.c index ba0b13a..46c16f2 100644 --- a/lib/exec.c +++ b/lib/exec.c @@ -4102,8 +4102,6 @@ static int execute (hcl_t* hcl) #if 0 hcl_logbfmt (hcl, HCL_LOG_STDERR, ">>>%O c->sc=%O sc=%O b2=%d b3=%d nivars=%d ncvars=%d<<<\n", class_obj, class_obj->superclass, superclass, b2, b3, (int)HCL_CLASS_SPEC_NAMED_INSTVARS(spec), (int)HCL_CLASS_SELFSPEC_CLASSVARS(spec)); #endif - -hcl_logbfmt (hcl, HCL_LOG_STDERR, " spec %d %d | selfspec %d %d\n", expected_spec, spec, expected_selfspec, selfspec); if (class_obj->superclass != superclass || expected_spec != spec || expected_selfspec != selfspec || diff --git a/lib/gc.c b/lib/gc.c index 102a81b..6f40a2f 100644 --- a/lib/gc.c +++ b/lib/gc.c @@ -1746,8 +1746,6 @@ oops: int hcl_ignite (hcl_t* hcl, hcl_oow_t heapsize) { - hcl_oow_t i; - if (!hcl->heap) { hcl->heap = hcl_makeheap(hcl, heapsize); diff --git a/lib/hcl-prv.h b/lib/hcl-prv.h index 1984cfe..f800bf2 100644 --- a/lib/hcl-prv.h +++ b/lib/hcl-prv.h @@ -308,6 +308,7 @@ enum hcl_tok_type_t HCL_TOK_CLASS, HCL_TOK_FUN, + HCL_TOK_VAR, HCL_TOK_DO, HCL_TOK_IF, HCL_TOK_ELIF, @@ -420,6 +421,7 @@ enum hcl_cnode_type_t * these represent syntactical elements of the language only. */ HCL_CNODE_CLASS, /* first item for HCL_CNODE_IS_FOR_LANG */ HCL_CNODE_FUN, + HCL_CNODE_VAR, HCL_CNODE_DO, HCL_CNODE_IF, HCL_CNODE_ELIF, @@ -684,28 +686,29 @@ struct hcl_cframe_t unsigned int indexed_type; hcl_loc_t start_loc; hcl_cnode_t* cmd_cnode; + hcl_cnode_t* class_name_cnode; } _class; } u; }; typedef struct hcl_cframe_t hcl_cframe_t; -enum hcl_cblk_type_t +enum hcl_ctlblk_type_t { - HCL_CBLK_TYPE_LOOP, - HCL_CBLK_TYPE_TRY, - HCL_CBLK_TYPE_CLASS + HCL_CTLBLK_TYPE_LOOP, + HCL_CTLBLK_TYPE_TRY, + HCL_CTLBLK_TYPE_CLASS }; -typedef enum hcl_cblk_type_t hcl_cblk_type_t; +typedef enum hcl_ctlblk_type_t hcl_ctlblk_type_t; /* control block information for the compiler */ -struct hcl_cblk_info_t +struct hcl_ctlblk_info_t { - hcl_cblk_type_t _type; + hcl_ctlblk_type_t _type; }; -typedef struct hcl_cblk_info_t hcl_cblk_info_t; +typedef struct hcl_ctlblk_info_t hcl_ctlblk_info_t; /* function block information for the compiler */ -struct hcl_fnblk_info_t +struct hcl_funblk_info_t { unsigned int fun_type; @@ -720,7 +723,7 @@ struct hcl_fnblk_info_t hcl_oow_t make_inst_pos; hcl_oow_t lfbase; - hcl_ooi_t cblk_base; + hcl_ooi_t ctlblk_base; hcl_ooi_t clsblk_base; hcl_ooi_t clsblk_top; @@ -728,19 +731,21 @@ struct hcl_fnblk_info_t unsigned int access_outer: 1; unsigned int accessed_by_inner: 1; }; -typedef struct hcl_fnblk_info_t hcl_fnblk_info_t; +typedef struct hcl_funblk_info_t hcl_funblk_info_t; /* class block information for the compiler */ struct hcl_clsblk_info_t { + hcl_cnode_t* class_name; + hcl_oow_t nivars; hcl_oow_t ncvars; hcl_ooch_t* ivars_str; hcl_ooch_t* cvars_str; hcl_oow_t spec; /* TODO: byte indexed, word indexed? */ - hcl_ooi_t fnblk_base; + hcl_ooi_t funblk_base; hcl_ooi_t class_start_inst_pos; /* the position of the first instruction in the class body after CLASS_ENTER */ }; typedef struct hcl_clsblk_info_t hcl_clsblk_info_t; @@ -998,16 +1003,16 @@ struct hcl_compiler_t struct { hcl_ooi_t depth; /* signed because it starts with -1 */ - hcl_cblk_info_t* info; + hcl_ctlblk_info_t* info; hcl_oow_t info_capa; - } cblk; /* control block - loop, try-catch */ + } ctlblk; /* control block - loop, try-catch */ struct { hcl_ooi_t depth; /* signed because it starts with -1 */ - hcl_fnblk_info_t* info; + hcl_funblk_info_t* info; hcl_oow_t info_capa; - } fnblk; /* function block */ + } funblk; /* function block */ struct { diff --git a/lib/hcl.h b/lib/hcl.h index 1dcb935..937035a 100644 --- a/lib/hcl.h +++ b/lib/hcl.h @@ -158,6 +158,7 @@ enum hcl_synerrnum_t HCL_SYNERR_CLASS, /* invalid class definition */ HCL_SYNERR_FUN, /* invalid function definition */ + HCL_SYNERR_VAR, /* invalid variable declaration */ HCL_SYNERR_ELIF, /* elif without if */ HCL_SYNERR_ELSE, /* else without if */ HCL_SYNERR_CATCH, /* catch outside try */ @@ -1577,7 +1578,7 @@ enum hcl_compile_flag_t HCL_COMPILE_CLEAR_CODE = (1 << 0), /* clear the top-level function block at the end of hcl_compile() */ - HCL_COMPILE_CLEAR_FNBLK = (1 << 1) + HCL_COMPILE_CLEAR_FUNBLK = (1 << 1) }; typedef enum hcl_compile_flag_t hcl_compile_flag_t; #endif diff --git a/lib/read.c b/lib/read.c index 4b2186d..fe6958d 100644 --- a/lib/read.c +++ b/lib/read.c @@ -60,6 +60,7 @@ static struct voca_t { 5, { 'c','l','a','s','s' } }, { 3, { 'f','u','n' } }, + { 3, { 'v','a','r' } }, { 2, { 'd','o' } }, { 2, { 'i','f' } }, { 4, { 'e','l','i','f' } }, @@ -120,6 +121,7 @@ enum voca_id_t VOCA_KW_CLASS, VOCA_KW_FUN, + VOCA_KW_VAR, VOCA_KW_DO, VOCA_KW_IF, VOCA_KW_ELIF, @@ -470,6 +472,7 @@ static hcl_tok_type_t classify_ident_token (hcl_t* hcl, const hcl_oocs_t* v) { VOCA_KW_CLASS, HCL_TOK_CLASS }, { VOCA_KW_FUN, HCL_TOK_FUN }, + { VOCA_KW_VAR, HCL_TOK_VAR }, { VOCA_KW_DO, HCL_TOK_DO }, { VOCA_KW_IF, HCL_TOK_IF }, { VOCA_KW_ELIF, HCL_TOK_ELIF }, @@ -861,14 +864,7 @@ static HCL_INLINE int can_comma_list (hcl_t* hcl) if (rstl->flagv & (COMMAED | COLONED | COLONEQED | BINOPED)) return 0; cc = (hcl_concode_t)LIST_FLAG_GET_CONCODE(rstl->flagv); - if (cc == HCL_CONCODE_XLIST) - { - /* fun f(a :: b c) { b := (a + 10); c := (a + 20) } - * [x y] := (f 9) - * [x,y] := (f 9) */ - LIST_FLAG_SET_CONCODE(rstl->flagv, HCL_CONCODE_ALIST); - } - else if (cc == HCL_CONCODE_DIC) + if (cc == HCL_CONCODE_DIC) { if (rstl->count & 1) return 0; } @@ -1443,6 +1439,7 @@ static hcl_cnode_type_t kw_to_cnode_type (int tok_type) HCL_CNODE_CLASS, HCL_CNODE_FUN, + HCL_CNODE_VAR, HCL_CNODE_DO, HCL_CNODE_IF, HCL_CNODE_ELIF, @@ -1882,6 +1879,7 @@ static int feed_process_token (hcl_t* hcl) case HCL_TOK_CLASS: case HCL_TOK_FUN: + case HCL_TOK_VAR: case HCL_TOK_DO: case HCL_TOK_IF: case HCL_TOK_ELIF: @@ -3926,12 +3924,12 @@ static void fini_compiler_cb (hcl_t* hcl) HCL_ASSERT (hcl, hcl->c->tv.capa == 0); HCL_ASSERT (hcl, hcl->c->tv.wcount == 0); - if (hcl->c->cblk.info) + if (hcl->c->ctlblk.info) { - hcl_freemem (hcl, hcl->c->cblk.info); - hcl->c->cblk.info = HCL_NULL; - hcl->c->cblk.info_capa = 0; - hcl->c->cblk.depth = -1; + hcl_freemem (hcl, hcl->c->ctlblk.info); + hcl->c->ctlblk.info = HCL_NULL; + hcl->c->ctlblk.info_capa = 0; + hcl->c->ctlblk.depth = -1; } if (hcl->c->clsblk.info) @@ -3942,12 +3940,12 @@ static void fini_compiler_cb (hcl_t* hcl) hcl->c->clsblk.depth = -1; } - if (hcl->c->fnblk.info) + if (hcl->c->funblk.info) { - hcl_freemem (hcl, hcl->c->fnblk.info); - hcl->c->fnblk.info = HCL_NULL; - hcl->c->fnblk.info_capa = 0; - hcl->c->fnblk.depth = -1; + hcl_freemem (hcl, hcl->c->funblk.info); + hcl->c->funblk.info = HCL_NULL; + hcl->c->funblk.info_capa = 0; + hcl->c->funblk.depth = -1; } clear_sr_names (hcl); @@ -3999,9 +3997,9 @@ static int init_compiler (hcl_t* hcl) hcl->c->r.e = hcl->_nil; hcl->c->cfs.top = -1; - hcl->c->cblk.depth = -1; + hcl->c->ctlblk.depth = -1; hcl->c->clsblk.depth = -1; - hcl->c->fnblk.depth = -1; + hcl->c->funblk.depth = -1; init_feed (hcl); hcl->c->cbp = cbp; diff --git a/lib/xchg.c b/lib/xchg.c index f500ce9..160740e 100644 --- a/lib/xchg.c +++ b/lib/xchg.c @@ -73,7 +73,7 @@ int hcl_marshalcode (hcl_t* hcl, const hcl_code_t* code, hcl_xchg_writer_t wrtr, hcl_oow_t w; hcl_xchg_hdr_t h; - lfbase = (hcl->option.trait & HCL_TRAIT_INTERACTIVE)? hcl->c->fnblk.info[hcl->c->fnblk.depth].lfbase: 0; + lfbase = (hcl->option.trait & HCL_TRAIT_INTERACTIVE)? hcl->c->funblk.info[hcl->c->funblk.depth].lfbase: 0; /* start with a header */ h.ver = 1; diff --git a/src/kernel.hcl b/src/kernel.hcl index bd620cd..83fbbb1 100644 --- a/src/kernel.hcl +++ b/src/kernel.hcl @@ -1,4 +1,7 @@ class Apex { + fun isNil?() { return false } + fun notNil?() { return true } + fun(#class) basicNew(size) { return (core.basicNew self size) } @@ -30,9 +33,8 @@ class Apex { fun basicSize() { return (core.basicSize self) } -} -class Object: Apex { + ## TODO: fun perform(name ...) {} } class(#uncopyable #varying #limited #final) Class: Apex [ @@ -62,6 +64,14 @@ class(#uncopyable #varying #limited #final) Class: Apex [ } } +class UndefinedObject: Apex { + fun isNil?() { return true } + fun notNil?() { return false } +} + +class Object: Apex { +} + class Collection: Object { fun length() { return (core.basicSize self) @@ -113,6 +123,455 @@ class(#char #varying) String: FixedSizedCollection { } +## --------------------------------------------------------------------------------- + + +## // TODO: consider if System can replace Apex itself. +## // System, being the top class, seems to give very natural way of +## // offering global system-level functions and interfaces. +## // +## // class System { ... } +## // class Object: System { .... } +## // System at: # +## // System logNl: 'xxxxx'. +## // System getUint8(ptr,offset) +## +## class System: Apex [ +## [ +## asyncsg ## async semaphore group +## gcfin_sem ## gc finalization semaphore +## gcfin_should_exit +## ossig_pid +## shr ## signal handler registry +## ] +## +## ] { +## ## var(#class) asyncsg. +## ## var(#class) gcfin_sem. +## ## var(#class) gcfin_should_exit := false. +## ## var(#class) ossig_pid. +## ## var(#class) shr. // signal handler registry +## +## ## pooldic Log +## ## { +## ## // ----------------------------------------------------------- +## ## // defines log levels +## ## // these items must follow defintions in moo.h +## ## // ----------------------------------------------------------- +## ## +## ## DEBUG := 1, +## ## INFO := 2, +## ## WARN := 4, +## ## ERROR := 8, +## ## FATAL := 16 +## ## } +## +## ## initialize class variables +## shr := (OrderedCollection:new) +## asyncsg := (SemaphoreGroup:new) +## +## fun(#class) _initialize { +## self.shr := OrderedCollection new. +## self.asyncsg := SemaphoreGroup new. +## } +## +## fun(#class) addAsyncSemaphore: sem { +## return (self.asyncsg addSemaphore: sem) +## } +## +## fun(#class) removeAsyncSemaphore: sem { +## return (self.asyncsg removeSemaphore: sem) +## } +## +## fun(#class) handleAsyncEvent { +## return (self.asyncsg wait). +## } +## +## fun(#class) installSignalHandler: block { +## return (self.shr addLast: block) +## } +## +## fun(#class) uninstallSignalHandler: block { +## self.shr remove: block. +## } +## +## fun(#class) startup(class_name, fun_name) { +## | class ret gcfin_proc ossig_proc | +## +## System gc. +## +## class := self at: class_name. // System at: class_name. +## if (class isError) +## { +## self error: ("Unable to find the class - " & class_name). +## }. +## +## self _initialize. +## +## // start the gc finalizer process and os signal handler process +## //[ self __gc_finalizer ] fork. +## //[ self __os_sig_handler ] fork. +## gcfin_proc := [ self __gc_finalizer ] newSystemProcess. +## ossig_proc := [ :caller | self __os_sig_handler: caller ] newSystemProcess(thisProcess). +## +## self.ossig_pid := ossig_proc id. +## +## gcfin_proc resume. +## ossig_proc resume. +## +## [ +## // TODO: change the fun signature to variadic and pass extra arguments to perform??? +## ret := class perform: fun_name. +## ] +## ensure: [ +## // signal end of the main process. +## // __os_sig_handler will terminate all running subprocesses. +## self _setSig: 16rFF. +## ]. +## +## ^ret. +## } +## +## fun(#class) __gc_finalizer +## { +## | tmp gc | +## +## gc := false. +## +## self.gcfin_should_exit := false. +## self.gcfin_sem := Semaphore new. +## self.gcfin_sem signalOnGCFin. // tell VM to signal this semaphore when it schedules gc finalization. +## +## [ +## while (true) +## { +## while ((tmp := self _popCollectable) notError) +## { +## if (tmp respondsTo: #finalize) +## { +## // finalize is protected with an exception handler. +## // the exception is ignored except it is logged. +## [ tmp finalize ] on: Exception do: [:ex | System longNl: "Exception in finalize - " & ex messageText ] +## }. +## }. +## +## //if (Processor total_count == 1) +## //if (Processor gcfin_should_exit) +## if (self.gcfin_should_exit) +## { +## // exit from this loop when there are no other processes running except this finalizer process +## if (gc) +## { +## System logNl: "Exiting the GC finalization process " & (thisProcess id) asString. +## break. +## }. +## +## System logNl: "Forcing garbage collection before termination in " & (thisProcess id) asString. +## self collectGarbage. +## gc := true. +## } +## else +## { +## gc := false. +## }. +## +## self.gcfin_sem wait. +## } +## ] ensure: [ +## self.gcfin_sem signal. // in case the process is stuck in wait. +## self.gcfin_sem unsignal. +## System logNl: "End of GC finalization process " & (thisProcess id) asString. +## ]. +## } +## +## fun(#class) __os_sig_handler: caller { +## | os_intr_sem signo sh | +## +## os_intr_sem := Semaphore new. +## os_intr_sem signalOnInput: System _getSigfd. +## +## [ +## while (true) { +## until ((signo := self _getSig) isError) { +## // TODO: Do i have to protected this in an exception handler??? +## //TODO: Execute Handler for signo. +## +## System logNl: "Interrupt detected - signal no - " & signo asString. +## +## //System logNl: "WWWWWWWWWWWWWWWWWWWWWWWWW ". +## // user-defined signal handler is not allowed for 16rFF +## if (signo == 16rFF) { goto done }. +## //System logNl: "OHHHHHHHHHHHHHH ". +## +## ifnot (self.shr isEmpty) +## { +## //System logNl: "About to execute handler for the signal detected - " & signo asString. +## self.shr do: [ :handler | handler value: signo ]. +## } +## else +## { +## //System logNl: "Jumping to done detected - signal no - " & signo asString. +## if (signo == 2) { goto done }. +## }. +## }. +## //System logNl: "Waiting for signal on os_intr_sem...". +## os_intr_sem wait. +## }. +## done: +## //System logNl: "Jumped to done detected - signal no - " & signo asString. +## nil. +## ] +## ensure: [ +## | pid proc oldps | +## +## //System logNl: "Aborting signal handler......". +## // stop subscribing to signals. +## os_intr_sem signal. +## os_intr_sem unsignal. +## +## // the caller must request to terminate all its child processes.. +## +## // this disables autonomous process switching only. +## // TODO: check if the ensure block code can trigger process switching? +## // what happens if the ensure block creates new processes? this is likely to affect the termination loop below. +## // even the id of the terminated process may get reused.... +## oldps := self _toggleProcessSwitching: false. +## +## /* +## 0 -> startup <--- this should also be stored in the "caller" variable. +## 1 -> __gc_finalizer +## 2 -> __os_sig_handler +## 3 .. -> other processes started by application. +## +## from the second run onwards, the starting pid may not be 0. +## */ +## //proc := System _findNextProcess: self.ossig_pid. +## proc := System _findFirstProcess. +## while (proc notError) +## { +## pid := proc id. +## if (proc isNormal) +## { +## System logNl: ("Requesting to terminate process of id - " & pid asString). +## proc terminate. +## }. +## proc := System _findNextProcess: pid. +## }. +## +## System logNl: "Requesting to terminate the caller process of id " & (caller id) asString. +## caller terminate. // terminate the startup process. +## self _toggleProcessSwitching: oldps. +## +## System logNl: ">>>>End of OS signal handler process " & (thisProcess id) asString. +## +## self.gcfin_should_exit := true. +## self.gcfin_sem signal. // wake the gcfin process. +## +## self _halting. // inform VM that it should get ready for halting. +## ]. +## } +## +## fun(#class,#primitive) _getSig. +## fun(#class,#primitive) _getSigfd. +## fun(#class,#primitive) _setSig: signo. +## fun(#class,#primitive) _halting. +## fun(#class,#primitive) _toggleProcessSwitching: v. +## fun(#class,#primitive,#lenient) _findProcessById: id. +## fun(#class,#primitive,#lenient) _findFirstProcess. +## fun(#class,#primitive,#lenient) _findLastProcess. +## fun(#class,#primitive,#lenient) _findPreviousProcess: p. // process id or process object +## fun(#class,#primitive,#lenient) _findNextProcess: p. // process id or process object +## +## fun(#class,#primitive) _popCollectable. +## fun(#class,#primitive) collectGarbage. +## fun(#class,#primitive) gc. +## fun(#class,#primitive) return: object to: context. +## +## // ======================================================================================= +## +## fun(#class) sleepForSecs: secs { +## // ----------------------------------------------------- +## // put the calling process to sleep for given seconds. +## // ----------------------------------------------------- +## | s | +## s := Semaphore new. +## s signalAfterSecs: secs. +## s wait. +## } +## +## fun(#class) sleepForSecs: secs nanosecs: nanosecs +## { +## // ----------------------------------------------------- +## // put the calling process to sleep for given seconds. +## // ----------------------------------------------------- +## | s | +## s := Semaphore new. +## s signalAfterSecs: secs nanosecs: nanosecs. +## s wait. +## } +## +## // the following funs may not look suitable to be placed +## // inside a system dictionary. but they are here for quick and dirty +## // output production from the moo code. +## // System logNl: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'. +## // +## fun(#class,#variadic,#primitive) log(level,msg1). +## +## /* +## TODO: how to pass all variadic arguments to another variadic funs??? +## fun(#class,#variadic) logInfo (msg1) +## { +## ^self log (System.Log.INFO,msg1) +## } +## */ +## fun(#class) atLevel: level log: message +## { +## +## // do nothing upon logging failure +## } +## +## fun(#class) atLevel: level log: message and: message2 +## { +## +## // do nothing upon logging failure +## } +## +## fun(#class) atLevel: level log: message and: message2 and: message3 +## { +## +## // do nothing upon logging failure +## } +## +## fun(#class) atLevel: level logNl: message +## { +## // the #_log primitive accepts an array. +## // so the following lines should work also. +## // | x | +## // x := Array new: 2. +## // x at: 0 put: message. +## // x at: 1 put: "\n". +## // ^self atLevel: level log: x. +## +## ^self atLevel: level log: message and: "\n". +## } +## +## fun(#class) atLevel: level logNl: message and: message2 +## { +## ^self atLevel: level log: message and: message2 and: "\n". +## } +## +## fun(#class) log: message +## { +## ^self atLevel: System.Log.INFO log: message. +## } +## +## fun(#class) log: message and: message2 +## { +## ^self atLevel: System.Log.INFO log: message and: message2. +## } +## +## fun(#class) logNl +## { +## ^self atLevel: System.Log.INFO log: "\n". +## } +## +## fun(#class) logNl: message +## { +## ^self atLevel: System.Log.INFO logNl: message. +## } +## +## fun(#class) logNl: message and: message2 +## { +## ^self atLevel: System.Log.INFO logNl: message and: message2. +## } +## +## fun(#class) backtrace +## { +## | ctx oldps | +## // TOOD: IMPROVE THIS EXPERIMENTAL BACKTRACE... MOVE THIS TO System>>backtrace and skip the first fun context for backtrace itself. +## // TODO: make this fun atomic? no other process should get scheduled while this function is running? +## // possible imementation funs: +## // 1. disable task switching? -> +## // 2. use a global lock. +## // 3. make this a primitive function. -> natually no callback. +## // 4. introduce a new fun attribute. e.g. #atomic -> vm disables task switching or uses a lock to achieve atomicity. +## // >>>> i think it should not be atomic as a while. only logging output should be produeced at one go. +## +## oldps := System _toggleProcessSwitching: false. +## System logNl: "== BACKTRACE ==". +## +## //ctx := thisContext. +## ctx := thisContext sender. // skip the current context. skip to the caller context. +## while (ctx notNil) +## { +## // if (ctx sender isNil) { break }. // to skip the fake top level call context... +## +## if (ctx class == MethodContext) +## { +## System log: " "; +## log: ctx fun owner name; +## log: ">>"; +## log: ctx fun name; +## log: " ("; +## log: ctx fun sourceFile; +## log: " "; +## log: (ctx fun ipSourceLine: (ctx pc)) asString; +## logNl: ")". +## //System logNl: (" " & ctx fun owner name & ">>" & ctx fun name & +## // " (" & ctx fun sourceFile & " " & (ctx fun ipSourceLine: (ctx pc)) asString & ")"). +## }. +## // TODO: include blockcontext??? +## ctx := ctx sender. +## }. +## System logNl: "== END OF BACKTRACE ==". +## System _toggleProcessSwitching: oldps. +## } +## +## ## /* nsdic access */ +## ## fun(#class) at: key +## ## { +## ## ^self nsdic at: key +## ## } +## ## +## ## fun(#class) at: key put: value +## ## { +## ## ^self nsdic at: key put: value +## ## } +## ## +## ## /* raw memory allocation */ +## ## fun(#class,#primitive) malloc (size). +## ## fun(#class,#primitive) calloc (size). +## ## fun(#class,#primitive) free (rawptr). +## ## +## ## fun(#class,#primitive) malloc: size. +## ## fun(#class,#primitive) calloc: size. +## ## fun(#class,#primitive) free: rawptr. +## ## +## ## /* raw memory access */ +## ## fun(#class,#primitive) getInt8 (rawptr, offset). // +## ## fun(#class,#primitive) getInt16 (rawptr, offset). +## ## fun(#class,#primitive) getInt32 (rawptr, offset). +## ## fun(#class,#primitive) getInt64 (rawptr, offset). +## ## fun(#class,#primitive) getUint8 (rawptr, offset). // +## ## fun(#class,#primitive) getUint16 (rawptr, offset). +## ## fun(#class,#primitive) getUint32 (rawptr, offset). +## ## fun(#class,#primitive) getUint64 (rawptr, offset). +## ## +## ## fun(#class,#primitive) putInt8 (rawptr, offset, value). +## ## fun(#class,#primitive) putInt16 (rawptr, offset, value). +## ## fun(#class,#primitive) putInt32 (rawptr, offset, value). +## ## fun(#class,#primitive) putInt64 (rawptr, offset, value). +## ## fun(#class,#primitive) putUint8 (rawptr, offset, value). +## ## fun(#class,#primitive) putUint16 (rawptr, offset, value). +## ## fun(#class,#primitive) putUint32 (rawptr, offset, value). +## ## fun(#class,#primitive) putUint64 (rawptr, offset, value). +## ## +## ## fun(#class,#primitive) getBytes (rawptr, offset, byte_array, offset_in_buffer, len_in_buffer). +## ## fun(#class,#primitive) putBytes (rawptr, offset, byte_array, offset_in_buffer, len_in_buffer). +## } + +## --------------------------------------------------------------------------------- + k := "abcdefghijklmn" printf "string length %d\n" ("aaaa":length) printf "substring [%s]\n" (k:slice 5 6) @@ -178,4 +637,3 @@ k := (Z:new) printf "%O\n" (k:basicAt 2) - diff --git a/t/class-5001.err b/t/class-5001.err index cccd261..576fb52 100644 --- a/t/class-5001.err +++ b/t/class-5001.err @@ -270,5 +270,5 @@ class(#byte #limited #final #limited) Kuduro { ##ERROR: syntax error - conflicti --- -class(#byte #bytes) Kuduro { ##ERROR: syntax error - unrecognized class attribute name 'bytes' +class(#byte #bytes) Kuduro { ##ERROR: syntax error - unrecognized class attribute name '#bytes' }