From 8597f532fa356da4cdf80e6b951eacd8cf3b4556 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Wed, 28 Aug 2024 00:58:56 +0900 Subject: [PATCH] updated the reader to transform the assignment expression to set/set-r expressions. updated the compiler to handle the assignment expression --- lib/comp.c | 161 +++++++++++++++++++++++++++++++++++++++++++++---- lib/read.c | 32 +++++++--- t/var-5001.err | 23 ++++++- 3 files changed, 193 insertions(+), 23 deletions(-) diff --git a/lib/comp.c b/lib/comp.c index ea4134e..25448af 100644 --- a/lib/comp.c +++ b/lib/comp.c @@ -1457,9 +1457,7 @@ static int collect_vardcl_for_class (hcl_t* hcl, hcl_cnode_t* obj, hcl_cnode_t** goto next; } - /* this check isn't needed as the reader guarantees this condition. - if (!HCL_CNODE_IS_SYMBOL_PLAIN(var) || HCL_CNODE_IS_SYMBOL_PLAIN_BINOP(var)) goto synerr_varname;*/ - HCL_ASSERT (hcl, HCL_CNODE_IS_SYMBOL_PLAIN(var) && !HCL_CNODE_IS_SYMBOL_PLAIN_BINOP(var)); + if (!HCL_CNODE_IS_SYMBOL_PLAIN(var) || HCL_CNODE_IS_SYMBOL_PLAIN_BINOP(var)) goto synerr_varname; checkpoint = hcl->c->tv.s.len; n = add_temporary_variable(hcl, HCL_CNODE_GET_TOK(var), tv_slen_saved); @@ -2269,7 +2267,9 @@ static int compile_expression_block (hcl_t* hcl, hcl_cnode_t* src, const hcl_bch static int compile_do (hcl_t* hcl, hcl_cnode_t* xlist) { +#if 0 hcl_cnode_t* cmd, * obj; +#endif int flags = 0; /* (do @@ -2283,8 +2283,10 @@ static int compile_do (hcl_t* hcl, hcl_cnode_t* xlist) HCL_ASSERT (hcl, HCL_CNODE_IS_CONS(xlist)); HCL_ASSERT (hcl, HCL_CNODE_IS_SYMBOL_SYNCODED(HCL_CNODE_CONS_CAR(xlist), HCL_SYNCODE_DO) || HCL_CNODE_IS_TYPED(HCL_CNODE_CONS_CAR(xlist), HCL_CNODE_DO)); +#if 0 cmd = HCL_CNODE_CONS_CAR(xlist); /* do itself */ obj = HCL_CNODE_CONS_CDR(xlist); /* expression list after it */ +#endif if (HCL_CNODE_GET_FLAGS(xlist) & HCL_CNODE_AUTO_FORGED) flags |= CEB_AUTO_FORGED; return compile_expression_block(hcl, xlist, "do", flags); @@ -3889,6 +3891,134 @@ static int compile_cons_qlist_expression (hcl_t* hcl, hcl_cnode_t* obj) return 0; } +static int compile_cons_alist_expression (hcl_t* hcl, hcl_cnode_t* cmd) +{ + /* assignment expression */ + /* (a := 20) + * ([a,b] := (xxx 20)) + */ + + hcl_cframe_t* cf; + hcl_cnode_t* obj, * var, * val; + hcl_var_info_t vi; + int x; + + HCL_ASSERT (hcl, HCL_CNODE_IS_CONS_CONCODED(cmd, HCL_CONCODE_ALIST)); + + var = HCL_CNODE_CONS_CAR(cmd); + obj = HCL_CNODE_CONS_CDR(cmd); + + HCL_ASSERT (hcl, HCL_CNODE_IS_SYMBOL_PLAIN(var) || HCL_CNODE_IS_DSYMBOL_CLA(var) || HCL_CNODE_IS_CONS_CONCODED(var, HCL_CONCODE_TUPLE)); + HCL_ASSERT (hcl, obj && HCL_CNODE_IS_CONS(obj)); /* reader guaranteed */ + + val = HCL_CNODE_CONS_CAR(obj); + HCL_ASSERT (hcl, HCL_CNODE_CONS_CDR(obj) == HCL_NULL); /* reader guaranteed */ + + if (HCL_CNODE_IS_CONS_CONCODED(var, HCL_CONCODE_TUPLE)) + { + /* multi-variable assignment + * fun xxx(x :: p q) { p := x + 1; q := x + 2 } + * ([a,b] := (xxx 20)) */ + hcl_oow_t nvars, i; + + nvars = hcl_countcnodecons(hcl, var); + + SWITCH_TOP_CFRAME (hcl, COP_COMPILE_OBJECT_R, val); /* special for set_r */ + cf = GET_TOP_CFRAME(hcl); + cf->u.obj_r.nrets = nvars; /* number of return variables to get assigned */ + + for (i = 0, obj = var; i < nvars; i++, obj = HCL_CNODE_CONS_CDR(obj)) + { + int x; + + var = HCL_CNODE_CONS_CAR(obj); + + HCL_ASSERT (hcl, HCL_CNODE_IS_SYMBOL_PLAIN(var) || HCL_CNODE_IS_DSYMBOL_CLA(var)); /* reader guaranteed */ + + x = find_variable_backward_with_token(hcl, var, &vi); + if (x <= -1) return -1; + + 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; + } + else + { + PUSH_SUBCFRAME (hcl, COP_EMIT_SET, cmd); + cf = GET_SUBCFRAME(hcl); + cf->u.set.vi = vi; + } + + /* + * (defun f(x y ::: aa bb cc) ....) + * ([a b c] := (f 1 2)) + * + * the call to f + * call 2 3 ; 2 arguments, 3 return variables (CALL_R) + * ; 3 to be emitted from cf->u.obj_r.nrets + * ; this gets remembered in req_nrvars of the created context. + * + * the return from f must push 3 values. + * push_return_r ; as remembered in the ctx->req_nrvars + * + * emit store_into_xxx instruction for the first return variable assignment. + * emit pop_into_xxx instructions for the rest. + * pop_into c + * pop_into b + * store_into a + */ + cf->u.set.mode = (i <= 0)? VAR_ACCESS_STORE: VAR_ACCESS_POP; /* STORE_INTO or POP_INTO */ + } + } + else + { + /* single-variable assignment + * (a := 20) */ + + SWITCH_TOP_CFRAME (hcl, COP_COMPILE_OBJECT, val); + + x = find_variable_backward_with_token(hcl, var, &vi); + if (x <= -1) return -1; + + if (x == 0) + { + /* not found */ + 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; + } + else + { + /* the check in compile_fun() must ensure this condition */ + PUSH_SUBCFRAME (hcl, COP_EMIT_SET, cmd); + cf = GET_SUBCFRAME(hcl); + cf->u.set.vi = vi; + } + cf->u.set.mode = VAR_ACCESS_STORE; + } + + return 0; +} + static int compile_cons_xlist_expression (hcl_t* hcl, hcl_cnode_t* obj, int nrets) { hcl_cnode_t* car; @@ -4377,7 +4507,7 @@ static HCL_INLINE int compile_dsymbol (hcl_t* hcl, hcl_cnode_t* obj) if (fbi->fun_type >> 8) { /* if defined using A::xxx syntax, it's not possible to know the instance position of an instance variable. - * class X | a b | { + * class X [ a b ] { * fun a() { * fun J::t() { * ## J has nothing to to with X in priciple even if J may point to X when a() is executed. @@ -4776,6 +4906,10 @@ redo: { switch (HCL_CNODE_CONS_CONCODE(oprnd)) { + case HCL_CONCODE_ALIST: + if (compile_cons_alist_expression(hcl, oprnd) <= -1) return -1; + break; + case HCL_CONCODE_XLIST: if (compile_cons_xlist_expression(hcl, oprnd, 0) <= -1) return -1; break; @@ -4809,15 +4943,11 @@ redo: hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARDCLBANNED, HCL_CNODE_GET_LOC(oprnd), HCL_NULL, "variable declaration disallowed"); return -1; - case HCL_CONCODE_TUPLE: - /* [a, b] is only allowed as a lvalue for now */ + /* [a, b] is only allowed as a lvalue or in class member varialble declaration for now */ hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(oprnd), HCL_NULL, "tuple disallowed"); return -1; - /* ALIST is transformed to XLIST with or set or set-r by the reader. - * so it must not appear here */ - case HCL_CONCODE_ALIST: default: hcl_setsynerrbfmt (hcl, HCL_SYNERR_INTERN, HCL_CNODE_GET_LOC(oprnd), HCL_NULL, "internal error - unknown cons type %d", HCL_CNODE_CONS_CONCODE(oprnd)); return -1; @@ -4831,6 +4961,10 @@ redo: /* empty list */ switch (HCL_CNODE_ELIST_CONCODE(oprnd)) { + case HCL_CONCODE_ALIST: + hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(oprnd), HCL_NULL, "empty assignment list"); + return -1; + case HCL_CONCODE_XLIST: hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(oprnd), HCL_NULL, "empty executable list"); return -1; @@ -4863,9 +4997,10 @@ redo: hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(oprnd), HCL_NULL, "empty variable declaration"); return -1; - /* ALIST is transformed to XLIST with or set or set-r by the reader. - * so it must not appear here */ - case HCL_CONCODE_ALIST: + case HCL_CONCODE_TUPLE: + hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(oprnd), HCL_NULL, "empty tuple"); + return -1; + default: hcl_setsynerrbfmt (hcl, HCL_SYNERR_INTERN, HCL_CNODE_GET_LOC(oprnd), HCL_NULL, "internal error - unknown list type %d", HCL_CNODE_CONS_CONCODE(oprnd)); return -1; @@ -5854,7 +5989,7 @@ static HCL_INLINE int post_fun (hcl_t* hcl) /* out-of-class definition */ /* TODO: - other types of out-of-class definition - CIM_STORE, CM_STORE... use different marker? */ hcl_oow_t index; - hcl_oop_t lit, cons; + hcl_oop_t lit; int inst; /* treat the class name part as a normal variable. diff --git a/lib/read.c b/lib/read.c index d50c3e1..1f0900f 100644 --- a/lib/read.c +++ b/lib/read.c @@ -621,10 +621,13 @@ static HCL_INLINE hcl_cnode_t* leave_list (hcl_t* hcl, hcl_loc_t* list_loc, int* /* HACK */ if (concode == HCL_CONCODE_ALIST) /* assignment list */ { - /* tranform (var := val) to (set var val) + /* sanitize/tranform (var := val) to (set var val) * - note ALIST doesn't contain the := symbol */ - hcl_cnode_t* sym, * newhead, * lval; + hcl_cnode_t* lval; + #if defined(TRANSFORM_ALIST) + hcl_cnode_t* sym, * newhead; hcl_oocs_t fake_tok, * fake_tok_ptr = HCL_NULL; + #endif lval = HCL_CNODE_CONS_CAR(head); if (lval && HCL_CNODE_IS_ELIST(lval)) @@ -633,7 +636,7 @@ static HCL_INLINE hcl_cnode_t* leave_list (hcl_t* hcl, hcl_loc_t* list_loc, int* hcl_setsynerr (hcl, HCL_SYNERR_LVALUE, HCL_CNODE_GET_LOC(lval), HCL_CNODE_GET_TOK(lval)); goto oops; } - else if (lval && HCL_CNODE_IS_CONS(lval) && HCL_CNODE_CONS_CONCODE(lval) == HCL_CONCODE_TUPLE) + else if (lval && HCL_CNODE_IS_CONS_CONCODED(lval, HCL_CONCODE_TUPLE)) { /* * defun f(a :: b c) { b := (a + 10); c := (a + 20) } @@ -641,21 +644,25 @@ static HCL_INLINE hcl_cnode_t* leave_list (hcl_t* hcl, hcl_loc_t* list_loc, int* */ hcl_cnode_t* tmp, * rval; + #if defined(TRANSFORM_ALIST) fake_tok.ptr = vocas[VOCA_SYM_SET_R].str; fake_tok.len = vocas[VOCA_SYM_SET_R].len; fake_tok_ptr = &fake_tok; + #endif for (tmp = lval; tmp && HCL_CNODE_IS_CONS(tmp); tmp = HCL_CNODE_CONS_CDR(tmp)) { - /* check in avance if the array members are all plain symbols */ + /* check in advance if the array members are all plain symbols */ hcl_cnode_t* lcar; lcar = HCL_CNODE_CONS_CAR(tmp); - if (!HCL_CNODE_IS_SYMBOL_PLAIN(lcar)) + if (!HCL_CNODE_IS_SYMBOL_PLAIN(lcar) && !HCL_CNODE_IS_DSYMBOL_CLA(lcar)) { hcl_setsynerrbfmt (hcl, HCL_SYNERR_LVALUE, HCL_CNODE_GET_LOC(lval), HCL_CNODE_GET_TOK(lval), "invalid lvalue - not symbol in tuple"); goto oops; } } + + #if defined(TRANSFORM_ALIST) /* move the array item up to the main list and join the original lval to the end of it * For [x, y] := (f 9), x and y must be in the same level as set-r after translation. * so make it 'x y (f 9)' first and place set-r in front of it later. */ @@ -670,6 +677,7 @@ static HCL_INLINE hcl_cnode_t* leave_list (hcl_t* hcl, hcl_loc_t* list_loc, int* break; } } + #endif } else { @@ -678,9 +686,11 @@ static HCL_INLINE hcl_cnode_t* leave_list (hcl_t* hcl, hcl_loc_t* list_loc, int* hcl_setsynerrbfmt (hcl, HCL_SYNERR_LVALUE, HCL_CNODE_GET_LOC(lval), HCL_CNODE_GET_TOK(lval), "invalid lvalue - not symbol"); goto oops; } + #if defined(TRANSFORM_ALIST) fake_tok.ptr = vocas[VOCA_SYM_SET].str; fake_tok.len = vocas[VOCA_SYM_SET].len; fake_tok_ptr = &fake_tok; + #endif } HCL_ASSERT (hcl, count >= 2); /* the missing rvalue check has been done above */ @@ -695,6 +705,7 @@ static HCL_INLINE hcl_cnode_t* leave_list (hcl_t* hcl, hcl_loc_t* list_loc, int* goto oops; } + #if defined(TRANSFORM_ALIST) sym = hcl_makecnodesymbol(hcl, 0, &loc, fake_tok_ptr); if (HCL_UNLIKELY(!sym)) { @@ -715,6 +726,7 @@ static HCL_INLINE hcl_cnode_t* leave_list (hcl_t* hcl, hcl_loc_t* list_loc, int* head = newhead; concode = HCL_CONCODE_XLIST; /* switch back to XLIST */ + #endif } else if (concode == HCL_CONCODE_BLIST) { @@ -812,8 +824,9 @@ static HCL_INLINE int can_comma_list (hcl_t* hcl) cc = (hcl_concode_t)LIST_FLAG_GET_CONCODE(rstl->flagv); if (cc == HCL_CONCODE_XLIST) { - /* defun f(a :: b c) { b := (a + 10); c := (a + 20) } - * (x, y) := (f 9) */ + /* 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) @@ -1030,6 +1043,8 @@ static int chain_to_list (hcl_t* hcl, hcl_cnode_t* obj, hcl_loc_t* loc) fake_tok_ptr = &fake_tok; } +#if 0 +/* TODO: remove this part ... */ if (list_concode == HCL_CONCODE_TUPLE && concode != HCL_CONCODE_TUPLE && (!HCL_CNODE_IS_SYMBOL_PLAIN(obj) || HCL_CNODE_IS_SYMBOL_PLAIN_BINOP(obj))) { @@ -1037,6 +1052,7 @@ static int chain_to_list (hcl_t* hcl, hcl_cnode_t* obj, hcl_loc_t* loc) hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(obj), HCL_CNODE_GET_TOK(obj), "invalid name - not symbol in tuple"); return -1; } +#endif cons = hcl_makecnodecons(hcl, 0, (loc? loc: HCL_CNODE_GET_LOC(obj)), fake_tok_ptr, obj, HCL_NULL); if (HCL_UNLIKELY(!cons)) return -1; @@ -2715,7 +2731,9 @@ not_consumed: static int flx_binop (hcl_t* hcl, hcl_ooci_t c) /* identifier */ { +#if 0 hcl_flx_binop_t* binop = FLX_BINOP(hcl); +#endif if (hcl_is_binop_char(c)) { diff --git a/t/var-5001.err b/t/var-5001.err index d2efe0f..e4ac2e8 100644 --- a/t/var-5001.err +++ b/t/var-5001.err @@ -31,7 +31,7 @@ defun String length() { ##ERROR: syntax error - no argument list --- -class A [ 10 ] { ##ERROR: syntax error - invalid name - not symbol in tuple - 10 +class A [ 10 ] { ##ERROR: syntax error - not variable name - 10 } --- @@ -44,9 +44,26 @@ class A [ [ [a] ] ] { ##ERROR: syntax error - not variable name } --- -class A [ a + ] { ##ERROR: syntax error - invalid name - not symbol in tuple - + +class A [ a + ] { ##ERROR: syntax error - not variable name - + } --- -class A [ + ] { ##ERROR: syntax error - invalid name - not symbol in tuple - + +class A [ + ] { ##ERROR: syntax error - not variable name - + } + +--- + +fun xxx(x :: p q) { p := (x + 1); q := (x + 2) } +[a,[b]] := (xxx 20) ##ERROR: syntax error - invalid lvalue - not symbol in tuple +printf "%d %d\n" a b + +--- +20 := 90 ##ERROR: syntax error - invalid lvalue - not symbol - 20 + +--- + +[a b] := 10 ##ERROR: syntax error - non-function call/non-message send disallowed + +--- + +[] := 10 ##ERROR: syntax error - invalid lvalue