diff --git a/lib/cnode.c b/lib/cnode.c index 6d65154..a487075 100644 --- a/lib/cnode.c +++ b/lib/cnode.c @@ -107,9 +107,12 @@ hcl_cnode_t* hcl_makecnodesymbol (hcl_t* hcl, int flags, const hcl_loc_t* loc, c return c; } -hcl_cnode_t* hcl_makecnodedsymbol (hcl_t* hcl, int flags, const hcl_loc_t* loc, const hcl_oocs_t* tok) +hcl_cnode_t* hcl_makecnodedsymbol (hcl_t* hcl, int flags, const hcl_loc_t* loc, const hcl_oocs_t* tok, int is_cla) { - return make_cnode(hcl, HCL_CNODE_DSYMBOL, flags, loc, tok); + hcl_cnode_t* c = make_cnode(hcl, HCL_CNODE_DSYMBOL, flags, loc, tok); + if (HCL_UNLIKELY(!c)) return HCL_NULL; + c->u.dsymbol.is_cla = is_cla; + return c; } hcl_cnode_t* hcl_makecnodestrlit (hcl_t* hcl, int flags, const hcl_loc_t* loc, const hcl_oocs_t* tok) diff --git a/lib/comp.c b/lib/comp.c index 08dcaa4..1a2df3f 100644 --- a/lib/comp.c +++ b/lib/comp.c @@ -400,9 +400,24 @@ HCL_INFO2 (hcl, "CLASS NAMED VAR [%.*js]\n", name->len, name->ptr); return 0; /* not found */ } -static int find_variable_backward_with_token (hcl_t* hcl, const hcl_cnode_t* token, hcl_var_info_t* vi) +static int find_variable_backward_with_token (hcl_t* hcl, const hcl_cnode_t* cnode, hcl_var_info_t* vi) { - return find_variable_backward_with_word(hcl, HCL_CNODE_GET_TOK(token), HCL_CNODE_GET_LOC(token), 0, vi); + if (HCL_CNODE_IS_DSYMBOL_CLA(cnode)) + { + /* prefixed with self or super. remove the first segment */ + hcl_oocs_t newtok; + newtok = *HCL_CNODE_GET_TOK(cnode); + while (*newtok.ptr != '.') + { + newtok.ptr++; + newtok.len--; + } + newtok.ptr++; + newtok.len--; + return find_variable_backward_with_word(hcl, &newtok, HCL_CNODE_GET_LOC(cnode), 1, vi); + } + + return find_variable_backward_with_word(hcl, HCL_CNODE_GET_TOK(cnode), HCL_CNODE_GET_LOC(cnode), HCL_CNODE_IS_DSYMBOL_CLA(cnode), vi); } /* ========================================================================= */ @@ -987,7 +1002,7 @@ static void pop_cblk (hcl_t* hcl) hcl->c->cblk.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_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; @@ -1353,7 +1368,7 @@ static int collect_vardcl (hcl_t* hcl, hcl_cnode_t* obj, hcl_cnode_t** nextobj, #if 0 if (!HCL_CNODE_IS_SYMBOL(var)) { - hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGNAME, HCL_CNODE_GET_LOC(var), HCL_CNODE_GET_TOK(var), "local variable not a symbol"); + hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGNAME, HCL_CNODE_GET_LOC(var), HCL_CNODE_GET_TOK(var), "local variable not symbol"); return -1; } @@ -2343,11 +2358,21 @@ static int compile_class (hcl_t* hcl, hcl_cnode_t* src) /* defclass followed by a class name */ if (HCL_CNODE_SYMBOL_SYNCODE(class_name)) /*|| HCL_OBJ_GET_FLAGS_KERNEL(class_name) >= 1) */ { - hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNEDVARNAME, HCL_CNODE_GET_LOC(class_name), HCL_CNODE_GET_TOK(class_name), "special symbol not to be used as a class name"); + hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNEDVARNAME, HCL_CNODE_GET_LOC(class_name), HCL_CNODE_GET_TOK(class_name), "special symbol not to be used as class name"); return -1; } obj = HCL_CNODE_CONS_CDR(obj); } + else if (HCL_CNODE_IS_DSYMBOL(class_name)) + { + if (!HCL_CNODE_IS_DSYMBOL_CLA(class_name)) + { + hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNEDVARNAME, HCL_CNODE_GET_LOC(class_name), HCL_CNODE_GET_TOK(class_name), "dottted symbol not to be used as class name"); + return -1; + } + + obj = HCL_CNODE_CONS_CDR(obj); + } if (obj) { @@ -2636,7 +2661,6 @@ static HCL_INLINE int compile_class_p2 (hcl_t* hcl) } else { - //POP_CFRAME (hcl); SWITCH_TOP_CFRAME (hcl, COP_COMPILE_CLASS_P3, cf->operand); #endif } @@ -2702,7 +2726,7 @@ static int compile_lambda (hcl_t* hcl, hcl_cnode_t* src, int defun) if (!HCL_CNODE_IS_SYMBOL(defun_name)) { - hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(defun_name), HCL_CNODE_GET_TOK(defun_name), "name not a symbol in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); + hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(defun_name), HCL_CNODE_GET_TOK(defun_name), "name not symbol in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); return -1; } @@ -2761,7 +2785,7 @@ static int compile_lambda (hcl_t* hcl, hcl_cnode_t* src, int defun) { if (!HCL_CNODE_IS_SYMBOL(arg)) { - hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(arg), HCL_CNODE_GET_TOK(arg), "return variable not a symbol in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); + hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(arg), HCL_CNODE_GET_TOK(arg), "return variable not symbol in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); return -1; } @@ -2805,7 +2829,7 @@ static int compile_lambda (hcl_t* hcl, hcl_cnode_t* src, int defun) } else if (!HCL_CNODE_IS_SYMBOL(arg)) { - hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGNAME, HCL_CNODE_GET_LOC(arg), HCL_CNODE_GET_TOK(arg), "argument not a symbol in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); + hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGNAME, HCL_CNODE_GET_LOC(arg), HCL_CNODE_GET_TOK(arg), "argument not symbol in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); return -1; } else @@ -3045,13 +3069,13 @@ static int compile_set (hcl_t* hcl, hcl_cnode_t* src) } var = HCL_CNODE_CONS_CAR(obj); - if (!HCL_CNODE_IS_SYMBOL(var)) + if (!HCL_CNODE_IS_SYMBOL(var) && !HCL_CNODE_IS_DSYMBOL_CLA(var)) { - hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(var), HCL_CNODE_GET_TOK(var), "variable name not a symbol in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); + hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(var), HCL_CNODE_GET_TOK(var), "variable name not symbol in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); return -1; } - if (HCL_CNODE_SYMBOL_SYNCODE(var)/* || HCL_OBJ_GET_FLAGS_KERNEL(var) >= 2*/) + if (HCL_CNODE_IS_SYMBOL(var) && HCL_CNODE_SYMBOL_SYNCODE(var)/* || HCL_OBJ_GET_FLAGS_KERNEL(var) >= 2*/) { hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNEDVARNAME, HCL_CNODE_GET_LOC(var), HCL_CNODE_GET_TOK(var), "special symbol not to be used as a variable name in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); return -1; @@ -3085,6 +3109,13 @@ static int compile_set (hcl_t* hcl, hcl_cnode_t* src) if (x == 0) { + if (HCL_CNODE_IS_DSYMBOL_CLA(var)) + { + hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAMEUNKNOWN, HCL_CNODE_GET_LOC(var), HCL_CNODE_GET_TOK(var), "unknown class-level variable name", HCL_CNODE_GET_TOKLEN(var), HCL_CNODE_GET_TOKPTR(var)); + return -1; + + } + PUSH_SUBCFRAME (hcl, COP_EMIT_SET, var); /* set doesn't evaluate the variable name */ cf = GET_SUBCFRAME(hcl); cf->u.set.vi.type = VAR_NAMED; @@ -3133,7 +3164,7 @@ static int compile_set_r (hcl_t* hcl, hcl_cnode_t* src) if (!HCL_CNODE_IS_SYMBOL(var)) { if (nvars > 0) break; - hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(var), HCL_CNODE_GET_TOK(var), "variable name not a symbol in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); + hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(var), HCL_CNODE_GET_TOK(var), "variable name not symbol in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd)); return -1; } @@ -3184,6 +3215,12 @@ static int compile_set_r (hcl_t* hcl, hcl_cnode_t* src) if (x == 0) { + if (HCL_CNODE_IS_DSYMBOL_CLA(var)) + { + hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAMEUNKNOWN, HCL_CNODE_GET_LOC(var), HCL_CNODE_GET_TOK(var), "unknown class-level variable name", HCL_CNODE_GET_TOKLEN(var), HCL_CNODE_GET_TOKPTR(var)); + return -1; + } + PUSH_SUBCFRAME (hcl, COP_EMIT_SET, var); /* set_r doesn't evaluate the variable name */ cf = GET_SUBCFRAME(hcl); cf->u.set.vi.type = VAR_NAMED; @@ -4057,7 +4094,7 @@ HCL_DEBUG1 (hcl, ">>>> instance variable or method %js\n", sep + 1); { name.ptr = sep + 1; name.len -= 6; - x = find_variable_backward_with_word(hcl, &name, HCL_CNODE_GET_LOC(obj), 1, &vi); /* TODO: arrange to skip the current class */ + x = find_variable_backward_with_word(hcl, &name, HCL_CNODE_GET_LOC(obj), 2, &vi); /* TODO: arrange to skip the current class */ } if (x <= -1) return -1; /* error */ @@ -5261,6 +5298,8 @@ static HCL_INLINE int post_lambda (hcl_t* hcl) if (x <= -1) return -1; if (x == 0) { +/* TODO: handle if defun_name is DSYMOL_CLA ... */ + /* arrange to save to the method slot */ switch (cf->u.lambda.fun_type) { diff --git a/lib/err.c b/lib/err.c index dda436f..0ad2ea2 100644 --- a/lib/err.c +++ b/lib/err.c @@ -146,6 +146,8 @@ static char* synerrstr[] = "too many variables defined", "variable declaration disallowed", "duplicate variable name", + "unknown variable name", + "disallowed variable name", "disallowed argument name", "disallowed", diff --git a/lib/hcl-prv.h b/lib/hcl-prv.h index c574b9c..9f203fe 100644 --- a/lib/hcl-prv.h +++ b/lib/hcl-prv.h @@ -174,6 +174,7 @@ enum hcl_tok_type_t HCL_TOK_IDENT, HCL_TOK_IDENT_DOTTED, + HCL_TOK_IDENT_DOTTED_CLA, HCL_TOK_DOT, /* . */ HCL_TOK_DBLDOTS, /* .. */ HCL_TOK_ELLIPSIS, /* ... */ @@ -266,6 +267,7 @@ typedef enum hcl_cnode_flagt hcl_cnode_flag_t; #define HCL_CNODE_SYMBOL_SYNCODE(x) ((x)->u.symbol.syncode) #define HCL_CNODE_IS_DSYMBOL(x) ((x)->cn_type == HCL_CNODE_DSYMBOL) +#define HCL_CNODE_IS_DSYMBOL_CLA(x) ((x)->cn_type == HCL_CNODE_DSYMBOL && (x)->u.dsymbol.is_cla) #define HCL_CNODE_IS_CONS(x) ((x)->cn_type == HCL_CNODE_CONS) #define HCL_CNODE_IS_CONS_CONCODED(x, code) ((x)->cn_type == HCL_CNODE_CONS && (x)->u.cons.concode == (code)) @@ -296,6 +298,10 @@ struct hcl_cnode_t hcl_syncode_t syncode; /* special if non-zero */ } symbol; struct + { + int is_cla; /* class-level accessor. prefixed with self or super */ + } dsymbol; + struct { hcl_oow_t v; } smptrlit; @@ -579,6 +585,7 @@ struct hcl_flx_pi_t hcl_oow_t seg_len; hcl_oow_t non_ident_seg_count; hcl_tok_type_t last_non_ident_type; + int is_cla; /* class-level accrssor. prefixed with self/super */ }; typedef struct hcl_flx_pn_t hcl_flx_pn_t; @@ -1723,7 +1730,7 @@ hcl_cnode_t* hcl_makecnodetrpcolons (hcl_t* hcl, int flags, const hcl_loc_t* loc hcl_cnode_t* hcl_makecnodedcstar (hcl_t* hcl, int flags, const hcl_loc_t* loc, const hcl_oocs_t* tok); hcl_cnode_t* hcl_makecnodecharlit (hcl_t* hcl, int flags, const hcl_loc_t* loc, const hcl_oocs_t* tok, const hcl_ooch_t v); hcl_cnode_t* hcl_makecnodesymbol (hcl_t* hcl, int flags, const hcl_loc_t* loc, const hcl_oocs_t* tok); -hcl_cnode_t* hcl_makecnodedsymbol (hcl_t* hcl, int flags, const hcl_loc_t* loc, const hcl_oocs_t* tok); +hcl_cnode_t* hcl_makecnodedsymbol (hcl_t* hcl, int flags, const hcl_loc_t* loc, const hcl_oocs_t* tok, int is_cla); hcl_cnode_t* hcl_makecnodestrlit (hcl_t* hcl, int flags, const hcl_loc_t* loc, const hcl_oocs_t* tok); hcl_cnode_t* hcl_makecnodenumlit (hcl_t* hcl, int flags, const hcl_loc_t* loc, const hcl_oocs_t* tok); hcl_cnode_t* hcl_makecnoderadnumlit (hcl_t* hcl, int flags, const hcl_loc_t* loc, const hcl_oocs_t* tok); diff --git a/lib/hcl.h b/lib/hcl.h index f8d13ce..18d5ce2 100644 --- a/lib/hcl.h +++ b/lib/hcl.h @@ -150,6 +150,7 @@ enum hcl_synerrnum_t HCL_SYNERR_VARFLOOD, /* too many variables defined */ HCL_SYNERR_VARDCLBANNED, /* variable declaration disallowed */ HCL_SYNERR_VARNAMEDUP, /* duplicate variable name */ + HCL_SYNERR_VARNAMEUNKNOWN, /* unknown variable name */ HCL_SYNERR_BANNEDVARNAME, /* disallowed varible name */ HCL_SYNERR_BANNEDARGNAME, /* disallowed argument name */ diff --git a/lib/read.c b/lib/read.c index c9f1b57..889e939 100644 --- a/lib/read.c +++ b/lib/read.c @@ -1452,7 +1452,11 @@ static int feed_process_token (hcl_t* hcl) goto auto_xlist; case HCL_TOK_IDENT_DOTTED: - frd->obj = hcl_makecnodedsymbol(hcl, 0, TOKEN_LOC(hcl), TOKEN_NAME(hcl)); + frd->obj = hcl_makecnodedsymbol(hcl, 0, TOKEN_LOC(hcl), TOKEN_NAME(hcl), 0); + goto auto_xlist; + + case HCL_TOK_IDENT_DOTTED_CLA: + frd->obj = hcl_makecnodedsymbol(hcl, 0, TOKEN_LOC(hcl), TOKEN_NAME(hcl), 1); goto auto_xlist; auto_xlist: @@ -2165,7 +2169,7 @@ static int flx_plain_ident (hcl_t* hcl, hcl_ooci_t c) /* identifier */ if (pi->seg_count == 0 && (tok_type == HCL_TOK_SELF || tok_type == HCL_TOK_SUPER)) { /* allowed if it begins with self. or super. */ - /* nothing to do */ + pi->is_cla = 1; /* mark that it's prefixed with self or super */ } else { @@ -2202,7 +2206,8 @@ static int flx_plain_ident (hcl_t* hcl, hcl_ooci_t c) /* identifier */ /* if single-segmented, perform classification(call classify_ident_token()) again * bcause self and super as the first segment have not been marked as a non-identifier above */ - tok_type = (pi->seg_count == 1? classify_ident_token(hcl, TOKEN_NAME(hcl)): HCL_TOK_IDENT_DOTTED); + tok_type = (pi->seg_count == 1? classify_ident_token(hcl, TOKEN_NAME(hcl)): + (pi->is_cla? HCL_TOK_IDENT_DOTTED_CLA: HCL_TOK_IDENT_DOTTED)); FEED_WRAP_UP (hcl, tok_type); goto not_consumed; } diff --git a/t/Makefile.am b/t/Makefile.am index 929c1e5..5c1c2fc 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -9,6 +9,7 @@ check_SCRIPTS = \ va-01.hcl check_ERRORS = \ + class-01.err \ do-01.err \ do-02.err \ feed-01.err \ diff --git a/t/Makefile.in b/t/Makefile.in index 150455c..36cb5a2 100644 --- a/t/Makefile.in +++ b/t/Makefile.in @@ -480,6 +480,7 @@ check_SCRIPTS = \ va-01.hcl check_ERRORS = \ + class-01.err \ do-01.err \ do-02.err \ feed-01.err \ diff --git a/t/class-01.err b/t/class-01.err new file mode 100644 index 0000000..6436ff0 --- /dev/null +++ b/t/class-01.err @@ -0,0 +1,23 @@ +defclass B | x y | { + +}; + +defclass X ::: B | a b | { + defun ::* new(t) { + | a | + set self.a t; + set a 100; + set self.b (* t 2); + + set self.c (fun(b) { ##ERROR: syntax error - unknown class-level variable name + printf "xxxx [%d]\n" b; + }); + return self; + }; + + defun print() { + self.c (+ self.a self.b); + printf "a=%d b=%d\n" self.a self.b; + } +}; +