updated the reader to transform the assignment expression to set/set-r expressions.
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
updated the compiler to handle the assignment expression
This commit is contained in:
parent
8602a479d7
commit
8597f532fa
161
lib/comp.c
161
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.
|
||||
|
32
lib/read.c
32
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))
|
||||
{
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user