rewrote compile_fun() to support attribute list for a function
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
29af1562fc
commit
3d0cdb5366
566
lib/comp.c
566
lib/comp.c
@ -473,7 +473,8 @@ static int check_block_expression_as_body (hcl_t* hcl, hcl_cnode_t* c, const hcl
|
|||||||
{
|
{
|
||||||
no_block:
|
no_block:
|
||||||
hcl_setsynerrbfmt (
|
hcl_setsynerrbfmt (
|
||||||
hcl, HCL_SYNERR_BLOCK, (car? HCL_CNODE_GET_LOC(car): c? HCL_CNODE_GET_LOC(c): HCL_CNODE_GET_LOC(ctx)), HCL_NULL,
|
hcl, HCL_SYNERR_BLOCK,
|
||||||
|
(car? HCL_CNODE_GET_LOC(car): c? HCL_CNODE_GET_LOC(c): HCL_CNODE_GET_LOC(ctx)), HCL_NULL,
|
||||||
"block expression expected as '%.*js' body", HCL_CNODE_GET_TOKLEN(ctx), HCL_CNODE_GET_TOKPTR(ctx)
|
"block expression expected as '%.*js' body", HCL_CNODE_GET_TOKLEN(ctx), HCL_CNODE_GET_TOKPTR(ctx)
|
||||||
);
|
);
|
||||||
return -1;
|
return -1;
|
||||||
@ -534,7 +535,8 @@ static int check_block_expression_as_body (hcl_t* hcl, hcl_cnode_t* c, const hcl
|
|||||||
|
|
||||||
hcl_setsynerrbfmt (
|
hcl_setsynerrbfmt (
|
||||||
hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(cdr), HCL_NULL,
|
hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(cdr), HCL_NULL,
|
||||||
"redundant expression prohibited after '%.*js' body", HCL_CNODE_GET_TOKLEN(ctx), HCL_CNODE_GET_TOKPTR(ctx)
|
"redundant expression prohibited after '%.*js' body",
|
||||||
|
HCL_CNODE_GET_TOKLEN(ctx), HCL_CNODE_GET_TOKPTR(ctx)
|
||||||
);
|
);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -2639,7 +2641,8 @@ static int compile_class (hcl_t* hcl, hcl_cnode_t* src, int defclass)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (emit_byte_instruction(hcl, HCL_CODE_PUSH_NIL,HCL_CNODE_GET_LOC(cmd)) <= -1) return -1; /* push nil for class name of an anonymous class */
|
/* push nil for class name of an anonymous class */
|
||||||
|
if (emit_byte_instruction(hcl, HCL_CODE_PUSH_NIL, HCL_CNODE_GET_LOC(cmd)) <= -1) return -1;
|
||||||
}
|
}
|
||||||
POP_CFRAME (hcl);
|
POP_CFRAME (hcl);
|
||||||
|
|
||||||
@ -2814,35 +2817,109 @@ static HCL_INLINE int compile_class_p2 (hcl_t* hcl)
|
|||||||
|
|
||||||
/* ========================================================================= */
|
/* ========================================================================= */
|
||||||
|
|
||||||
|
static int check_fun_attr_list (hcl_t* hcl, hcl_cnode_t* attr_list, unsigned int* fun_type)
|
||||||
|
{
|
||||||
|
unsigned int ft;
|
||||||
|
|
||||||
|
ft = 0;
|
||||||
|
|
||||||
|
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_CONS(attr_list))
|
||||||
|
{
|
||||||
|
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_FUN, HCL_CNODE_GET_LOC(a), HCL_NULL,
|
||||||
|
"invalid function 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 != 0)
|
||||||
|
{
|
||||||
|
conflicting:
|
||||||
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(a), HCL_NULL,
|
||||||
|
"conflicting function attribute name '%.*js'", toklen, tokptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ft = FUN_CM;
|
||||||
|
}
|
||||||
|
else if (hcl_comp_oochars_bcstr(tokptr, toklen, "classinst") == 0 ||
|
||||||
|
hcl_comp_oochars_bcstr(tokptr, toklen, "ci") == 0)
|
||||||
|
{
|
||||||
|
if (ft != 0) goto conflicting;
|
||||||
|
ft = FUN_CIM;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(a), HCL_NULL,
|
||||||
|
"unrecognized function attribute name '%.*js'", toklen, tokptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = HCL_CNODE_CONS_CDR(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*fun_type = ft;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
||||||
{
|
{
|
||||||
hcl_cnode_t* cmd, * obj, * args;
|
hcl_cnode_t* cmd, * next;
|
||||||
hcl_oow_t va, nargs, nrvars, nlvars;
|
hcl_oow_t va, nargs, nrvars, nlvars;
|
||||||
hcl_ooi_t jump_inst_pos, lfbase_pos, lfsize_pos;
|
hcl_ooi_t jump_inst_pos, lfbase_pos, lfsize_pos;
|
||||||
hcl_oow_t saved_tv_wcount, tv_dup_start;
|
hcl_oow_t saved_tv_wcount, tv_dup_start;
|
||||||
hcl_cnode_t* fun_name;
|
hcl_cnode_t* fun_name;
|
||||||
hcl_cnode_t* class_name;
|
hcl_cnode_t* class_name;
|
||||||
|
hcl_cnode_t* arg_list;
|
||||||
|
hcl_cnode_t* fun_body;
|
||||||
hcl_cframe_t* cf;
|
hcl_cframe_t* cf;
|
||||||
unsigned int fun_type = FUN_PLAIN;
|
unsigned int fun_type;
|
||||||
int named = 0;
|
|
||||||
|
|
||||||
HCL_ASSERT (hcl, HCL_CNODE_IS_CONS(src));
|
HCL_ASSERT (hcl, HCL_CNODE_IS_CONS(src));
|
||||||
|
|
||||||
saved_tv_wcount = hcl->c->tv.wcount;
|
saved_tv_wcount = hcl->c->tv.wcount;
|
||||||
cmd = HCL_CNODE_CONS_CAR(src);
|
cmd = HCL_CNODE_CONS_CAR(src);
|
||||||
obj = HCL_CNODE_CONS_CDR(src);
|
next = HCL_CNODE_CONS_CDR(src);
|
||||||
|
fun_name = HCL_NULL;
|
||||||
class_name = HCL_NULL;
|
class_name = HCL_NULL;
|
||||||
|
arg_list = HCL_NULL;
|
||||||
|
fun_body = HCL_NULL;
|
||||||
|
fun_type = FUN_PLAIN;
|
||||||
|
|
||||||
HCL_ASSERT (hcl, HCL_CNODE_IS_SYMBOL_SYNCODED(cmd, HCL_SYNCODE_FUN) ||
|
HCL_ASSERT (hcl, HCL_CNODE_IS_SYMBOL_SYNCODED(cmd, HCL_SYNCODE_FUN) ||
|
||||||
HCL_CNODE_IS_TYPED(cmd, HCL_CNODE_FUN));
|
HCL_CNODE_IS_TYPED(cmd, HCL_CNODE_FUN));
|
||||||
|
|
||||||
if (obj)
|
if (next)
|
||||||
{
|
{
|
||||||
hcl_cnode_t* tmp, * next;
|
hcl_cnode_t* tmp;
|
||||||
|
hcl_cnode_t* attr_list;
|
||||||
|
|
||||||
/* the reader ensures that the cdr field of a cons cell points to the next cell.
|
/* 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. */
|
* and only the field of the last cons cell is NULL. */
|
||||||
HCL_ASSERT (hcl, HCL_CNODE_IS_CONS(obj));
|
HCL_ASSERT (hcl, HCL_CNODE_IS_CONS(next));
|
||||||
|
attr_list = HCL_NULL;
|
||||||
|
|
||||||
/* fun (arg..)
|
/* fun (arg..)
|
||||||
* fun name (arg..)
|
* fun name (arg..)
|
||||||
@ -2850,12 +2927,12 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
* fun(#attr..) (arg..)
|
* fun(#attr..) (arg..)
|
||||||
* fun(#attr..) class:name(arg..)
|
* fun(#attr..) class:name(arg..)
|
||||||
*/
|
*/
|
||||||
next = obj;
|
|
||||||
tmp = HCL_CNODE_CONS_CAR(next);
|
tmp = HCL_CNODE_CONS_CAR(next);
|
||||||
if (HCL_CNODE_IS_SYMBOL_PLAIN(tmp))
|
if (HCL_CNODE_IS_SYMBOL_PLAIN(tmp))
|
||||||
{
|
{
|
||||||
/* 'fun' followed by name */
|
/* 'fun' followed by name */
|
||||||
got_name:
|
fun_got_name:
|
||||||
/* name must be followed by argument list */
|
/* name must be followed by argument list */
|
||||||
fun_name = tmp;
|
fun_name = tmp;
|
||||||
|
|
||||||
@ -2863,10 +2940,10 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
if (!next)
|
if (!next)
|
||||||
{
|
{
|
||||||
hcl_setsynerrbfmt (
|
hcl_setsynerrbfmt (
|
||||||
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(cmd), HCL_NULL,
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(fun_name), HCL_NULL,
|
||||||
"'%.*js' name '%.*js' not followed by ( or :",
|
"function name '%.*js' not followed by ( or : for '%.*js'",
|
||||||
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd),
|
HCL_CNODE_GET_TOKLEN(fun_name), HCL_CNODE_GET_TOKPTR(fun_name),
|
||||||
HCL_CNODE_GET_TOKLEN(fun_name), HCL_CNODE_GET_TOKPTR(fun_name));
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2881,10 +2958,10 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
if (!next)
|
if (!next)
|
||||||
{
|
{
|
||||||
hcl_setsynerrbfmt (
|
hcl_setsynerrbfmt (
|
||||||
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(cmd), HCL_NULL,
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(class_name), HCL_NULL,
|
||||||
"no '%.*js' name after class name '%.*js' and :",
|
"no function name after class name '%.*js:' for '%.*js'",
|
||||||
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd),
|
HCL_CNODE_GET_TOKLEN(class_name), HCL_CNODE_GET_TOKPTR(class_name),
|
||||||
HCL_CNODE_GET_TOKLEN(class_name), HCL_CNODE_GET_TOKPTR(class_name));
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2892,54 +2969,187 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
if (!HCL_CNODE_IS_SYMBOL_PLAIN(tmp))
|
if (!HCL_CNODE_IS_SYMBOL_PLAIN(tmp))
|
||||||
{
|
{
|
||||||
hcl_setsynerrbfmt (
|
hcl_setsynerrbfmt (
|
||||||
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(cmd), HCL_NULL,
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(tmp), HCL_NULL,
|
||||||
"invalid '%.*js' name '%.*js' after class name and :",
|
"invalid function name '%.*js' after '%.*js:' for '%.*js'",
|
||||||
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd),
|
HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp),
|
||||||
HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp));
|
HCL_CNODE_GET_TOKLEN(class_name), HCL_CNODE_GET_TOKPTR(class_name),
|
||||||
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fun_name = tmp;
|
fun_name = tmp;
|
||||||
|
fun_type = FUN_IM;
|
||||||
|
if (attr_list && check_fun_attr_list(hcl, attr_list, &fun_type) <= -1) return -1;
|
||||||
|
fun_type |= 0x100; /* indicate that the function was defined in 'fun class:name()' style */
|
||||||
|
|
||||||
|
next = HCL_CNODE_CONS_CDR(next);
|
||||||
|
if (!next)
|
||||||
|
{
|
||||||
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(fun_name), HCL_NULL,
|
||||||
|
"function name '%.*js:%.*js' not followed by ( for '%.*js'",
|
||||||
|
HCL_CNODE_GET_TOKLEN(class_name), HCL_CNODE_GET_TOKPTR(class_name),
|
||||||
|
HCL_CNODE_GET_TOKLEN(fun_name), HCL_CNODE_GET_TOKPTR(fun_name),
|
||||||
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = HCL_CNODE_CONS_CAR(next); /* pointing to argument list */
|
||||||
|
|
||||||
|
if (is_in_class_init_scope(hcl))
|
||||||
|
{
|
||||||
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(fun_name), HCL_NULL,
|
||||||
|
"class name '%.*js' before :'%.*js' prohibited in class initialization context",
|
||||||
|
HCL_CNODE_GET_TOKLEN(class_name), HCL_CNODE_GET_TOKPTR(class_name),
|
||||||
|
HCL_CNODE_GET_TOKLEN(fun_name), HCL_CNODE_GET_TOKPTR(fun_name));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* no 'class:' part after 'fun' */
|
||||||
|
if (is_in_class_init_scope(hcl))
|
||||||
|
{
|
||||||
|
/* TODO:THIS IS ALSO WRONG.
|
||||||
|
* class X {
|
||||||
|
* a := (fun x(){}) ## this context is also class_init_scope. so the check above isn't good enough
|
||||||
|
* } */
|
||||||
|
fun_type = FUN_IM;
|
||||||
|
if (attr_list && check_fun_attr_list(hcl, attr_list, &fun_type) <= -1) return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* as of now, the plain function doesn't support attribute list.
|
||||||
|
* this can change in the future. */
|
||||||
|
if (attr_list)
|
||||||
|
{
|
||||||
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(attr_list), HCL_NULL,
|
||||||
|
"unsupported attribute list for plain function '%.*js'",
|
||||||
|
HCL_CNODE_GET_TOKLEN(fun_name), HCL_CNODE_GET_TOKPTR(fun_name));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (HCL_CNODE_IS_CONS(tmp))
|
|
||||||
|
if (HCL_CNODE_IS_CONS_CONCODED(tmp, HCL_CONCODE_XLIST) ||
|
||||||
|
HCL_CNODE_IS_ELIST_CONCODED(tmp, HCL_CONCODE_XLIST))
|
||||||
{
|
{
|
||||||
/* 'fun' followed by attribute or argument list */
|
/* 'fun' followed by attribute or argument list */
|
||||||
next = HCL_CNODE_CONS_CDR(next);
|
arg_list = tmp;
|
||||||
if (!next)
|
if (fun_name)
|
||||||
{
|
{
|
||||||
|
/* argument list for sure
|
||||||
|
* fun class:name()
|
||||||
|
* fun name ()
|
||||||
|
* ^ */
|
||||||
|
next = HCL_CNODE_CONS_CDR(next); /* point past argument list */
|
||||||
|
if (!next)
|
||||||
|
{
|
||||||
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(cmd), HCL_NULL,
|
||||||
|
"no function body after argument list of function '%.*js' for '%.*js'",
|
||||||
|
HCL_CNODE_GET_TOKLEN(fun_name), HCL_CNODE_GET_TOKPTR(fun_name),
|
||||||
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fun_body = next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* not clear if it is attribute list or argument list */
|
||||||
|
next = HCL_CNODE_CONS_CDR(next); /* point past attribute/argument list */
|
||||||
|
if (!next)
|
||||||
|
{
|
||||||
|
/* TODO: guess if the current list looks like attribute list or
|
||||||
|
* not by inspecting elements and produce better error mesage.
|
||||||
|
* another hack is to disallow ELIST as attribute list? */
|
||||||
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(cmd), HCL_NULL,
|
||||||
|
"unamed function not followed by function body 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_PLAIN(tmp))
|
||||||
|
{
|
||||||
|
/* it is attribute list for sure. fun(#attr..) name */
|
||||||
|
attr_list = arg_list;
|
||||||
|
arg_list = HCL_NULL;
|
||||||
|
goto fun_got_name;
|
||||||
|
}
|
||||||
|
else if (HCL_CNODE_IS_CONS_CONCODED(tmp, HCL_CONCODE_XLIST) ||
|
||||||
|
HCL_CNODE_IS_ELIST_CONCODED(tmp, HCL_CONCODE_XLIST))
|
||||||
|
{
|
||||||
|
/* fun(#attr..) (arg..) .. */
|
||||||
|
attr_list = arg_list;
|
||||||
|
arg_list = tmp;
|
||||||
|
|
||||||
|
next = HCL_CNODE_CONS_CDR(next); /* point past argument list */
|
||||||
|
if (!next)
|
||||||
|
{
|
||||||
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(cmd), HCL_NULL,
|
||||||
|
"no function body after attribute list and argument list of unamed function for '%.*js'",
|
||||||
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fun_body = next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* fun(arg..) .. */
|
||||||
|
fun_body = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fun_name && is_in_class_init_scope(hcl))
|
||||||
|
{
|
||||||
|
/* TODO: it must allow as rvalue..
|
||||||
|
* class X {
|
||||||
|
* b := (fun() {}) ## this is allowed <- TODO: not supported yet
|
||||||
|
* fun() {} ## this is prohibited
|
||||||
|
* }
|
||||||
|
*/
|
||||||
hcl_setsynerrbfmt (
|
hcl_setsynerrbfmt (
|
||||||
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(cmd), HCL_NULL,
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(cmd), HCL_NULL,
|
||||||
"'%.*js' not defined with body",
|
"unnamed function defined with '%.*js' prohibited in class initialziation context",
|
||||||
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd),
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = HCL_CNODE_CONS_CAR(next);
|
|
||||||
if (HCL_CNODE_IS_SYMBOL_PLAIN(tmp))
|
|
||||||
{
|
|
||||||
/* fun(#attr..) name */
|
|
||||||
goto got_name;
|
|
||||||
}
|
|
||||||
else if (HCL_CNODE_IS_CONS(tmp))
|
|
||||||
{
|
|
||||||
/* fun(#attr..) (arg..) */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fall down to handle the function body */
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hcl_setsynerrbfmt (
|
/* not valid argument list or attribute list
|
||||||
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(cmd), HCL_NULL,
|
* fun if ## cmd is 'fun', fun_name is nil
|
||||||
"'%.*js' not followed by name or (, but followed by '%.*js'",
|
* fun a if ## cmd is 'fun', fun_name is 'a'
|
||||||
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd),
|
* fun a:b if ## cmd is 'fun', fun_name is 'b'
|
||||||
HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp));
|
* fun self.a ## cmd is 'fun', fun_name is nil
|
||||||
|
*/
|
||||||
|
if (fun_name)
|
||||||
|
{
|
||||||
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(tmp), HCL_NULL,
|
||||||
|
"'%.*js' not followed by ( but followed by '%.*js'",
|
||||||
|
HCL_CNODE_GET_TOKLEN(fun_name), HCL_CNODE_GET_TOKPTR(fun_name),
|
||||||
|
HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(tmp), HCL_NULL,
|
||||||
|
"invalid function 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;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* nothing after 'fun' (e.g. fun ) */
|
||||||
hcl_setsynerrbfmt (
|
hcl_setsynerrbfmt (
|
||||||
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(cmd), HCL_NULL,
|
hcl, HCL_SYNERR_FUN, HCL_CNODE_GET_LOC(cmd), HCL_NULL,
|
||||||
"'%.*js' not followed by name or (",
|
"'%.*js' not followed by name or (",
|
||||||
@ -2947,180 +3157,17 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj && HCL_CNODE_IS_CONS(obj))
|
|
||||||
{
|
|
||||||
/* inaccurate pre-check if 'fun' is followed by an argument list
|
|
||||||
* without a function name. */
|
|
||||||
args = HCL_CNODE_CONS_CAR(obj);
|
|
||||||
if (!HCL_CNODE_IS_ELIST_CONCODED(args, HCL_CONCODE_XLIST) &&
|
|
||||||
!HCL_CNODE_IS_CONS_CONCODED(args, HCL_CONCODE_XLIST))
|
|
||||||
{
|
|
||||||
/* not followed by an argument list */
|
|
||||||
named = 1;
|
|
||||||
goto named_function;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (named)
|
|
||||||
{
|
|
||||||
named_function:
|
|
||||||
if (!obj)
|
|
||||||
{
|
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGNAMELIST, HCL_CNODE_GET_LOC(src), HCL_NULL, "no name in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else if (!HCL_CNODE_IS_CONS(obj))
|
|
||||||
{
|
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_DOTBANNED, HCL_CNODE_GET_LOC(obj), HCL_CNODE_GET_TOK(obj), "redundant cdr in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fun_name = HCL_CNODE_CONS_CAR(obj);
|
|
||||||
if (is_in_class_init_scope(hcl))
|
|
||||||
{
|
|
||||||
if ((HCL_CNODE_IS_DBLCOLONS(fun_name) || HCL_CNODE_IS_COLONSTAR(fun_name)))
|
|
||||||
{
|
|
||||||
/* class method - (fun ::xxxx () ...) inside class definition */
|
|
||||||
/* class instantiation method - (fun :*xxxx() ...) inside class definition */
|
|
||||||
obj = HCL_CNODE_CONS_CDR(obj);
|
|
||||||
if (!obj)
|
|
||||||
{
|
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGNAMELIST, HCL_CNODE_GET_LOC(src), HCL_NULL, "no name in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fun_type = HCL_CNODE_IS_DBLCOLONS(fun_name)? FUN_CM: FUN_CIM;
|
|
||||||
fun_name = HCL_CNODE_CONS_CAR(obj); /* advance to the actual name */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (HCL_CNODE_IS_SYMBOL_PLAIN(fun_name))
|
|
||||||
{
|
|
||||||
/* probably this form - fun XXX:yyy () ...
|
|
||||||
* the class name must not be specified in the class initialization scope */
|
|
||||||
hcl_cnode_t* tmp;
|
|
||||||
tmp = HCL_CNODE_CONS_CDR(obj);
|
|
||||||
if (tmp && HCL_CNODE_IS_CONS(tmp))
|
|
||||||
{
|
|
||||||
tmp = HCL_CNODE_CONS_CAR(tmp);
|
|
||||||
if (HCL_CNODE_IS_COLON(tmp) || HCL_CNODE_IS_DBLCOLONS(tmp) || HCL_CNODE_IS_COLONSTAR(tmp)/*(HCL_CNODE_IS_SYMBOL_PLAIN(tmp)*/)
|
|
||||||
{
|
|
||||||
hcl_setsynerrbfmt (
|
|
||||||
hcl, HCL_SYNERR_VARNAME,
|
|
||||||
HCL_CNODE_GET_LOC(fun_name), HCL_CNODE_GET_TOK(fun_name),
|
|
||||||
"function name not valid followed by %.*js",
|
|
||||||
HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun_type = FUN_IM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (HCL_CNODE_IS_SYMBOL_PLAIN(fun_name))
|
|
||||||
{
|
|
||||||
hcl_cnode_t* tmp, marker;
|
|
||||||
tmp = HCL_CNODE_CONS_CDR(obj);
|
|
||||||
if (tmp && HCL_CNODE_IS_CONS(tmp))
|
|
||||||
{
|
|
||||||
hcl_cnode_t* marker;
|
|
||||||
marker = HCL_CNODE_CONS_CAR(tmp);
|
|
||||||
if (HCL_CNODE_IS_COLON(marker) || HCL_CNODE_IS_DBLCOLONS(marker) || HCL_CNODE_IS_COLONSTAR(marker))
|
|
||||||
{
|
|
||||||
/* fun A:aaa A::aaa A:*aaa */
|
|
||||||
|
|
||||||
tmp = HCL_CNODE_CONS_CDR(tmp);
|
|
||||||
if (tmp && HCL_CNODE_IS_CONS(tmp))
|
|
||||||
{
|
|
||||||
hcl_cnode_t* cand;
|
|
||||||
cand = HCL_CNODE_CONS_CAR(tmp);
|
|
||||||
if (HCL_CNODE_IS_SYMBOL_PLAIN(cand))
|
|
||||||
{
|
|
||||||
/* out-of-class method definition
|
|
||||||
* for fun String:length() { ... },
|
|
||||||
* class_name is String, fun_name is length. */
|
|
||||||
fun_type = HCL_CNODE_IS_DBLCOLONS(marker)? FUN_CM:
|
|
||||||
HCL_CNODE_IS_COLONSTAR(marker)? FUN_CIM: FUN_IM;
|
|
||||||
|
|
||||||
/* indicates that this method is defined using the AAA:bbb syntax.
|
|
||||||
* the form of method defintion can still be inside a class if this
|
|
||||||
* form is place inside another normal method.
|
|
||||||
* class X {
|
|
||||||
* fun x() {
|
|
||||||
* fun J:q() { .... } ## this defintion
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* */
|
|
||||||
fun_type |= 0x100;
|
|
||||||
|
|
||||||
class_name = fun_name;
|
|
||||||
fun_name = HCL_CNODE_CONS_CAR(tmp);
|
|
||||||
obj = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!HCL_CNODE_IS_SYMBOL(fun_name))
|
|
||||||
{
|
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME,
|
|
||||||
HCL_CNODE_GET_LOC(fun_name), HCL_NULL,
|
|
||||||
"invalid function name '%.*js' for '%.*js'",
|
|
||||||
HCL_CNODE_GET_TOKLEN(fun_name), HCL_CNODE_GET_TOKPTR(fun_name),
|
|
||||||
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HCL_CNODE_SYMBOL_SYNCODE(fun_name)) /*|| HCL_OBJ_GET_FLAGS_KERNEL(fun_name) >= 1) */
|
|
||||||
{
|
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNEDVARNAME,
|
|
||||||
HCL_CNODE_GET_LOC(fun_name), HCL_NULL,
|
|
||||||
"special symbol '%.*js' not to be used as function name",
|
|
||||||
HCL_CNODE_GET_TOKLEN(fun_name), HCL_CNODE_GET_TOKPTR(fun_name));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj = HCL_CNODE_CONS_CDR(obj);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HCL_ASSERT (hcl, HCL_CNODE_IS_SYMBOL_SYNCODED(cmd, HCL_SYNCODE_FUN) ||
|
|
||||||
HCL_CNODE_IS_TYPED(cmd, HCL_CNODE_FUN));
|
|
||||||
fun_name = HCL_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!obj)
|
|
||||||
{
|
|
||||||
no_arg_list:
|
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGNAMELIST, HCL_CNODE_GET_LOC(src), HCL_NULL,
|
|
||||||
"argument list missing in %.*js",
|
|
||||||
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else if (!HCL_CNODE_IS_CONS(obj))
|
|
||||||
{
|
|
||||||
redundant_cdr:
|
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_DOTBANNED, HCL_CNODE_GET_LOC(obj), HCL_CNODE_GET_TOK(obj), "redundant cdr in argument list in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* process the argument list */
|
/* process the argument list */
|
||||||
va = 0;
|
va = 0;
|
||||||
nargs = 0;
|
nargs = 0;
|
||||||
nrvars = 0;
|
nrvars = 0;
|
||||||
args = HCL_CNODE_CONS_CAR(obj);
|
|
||||||
HCL_ASSERT (hcl, args != HCL_NULL);
|
|
||||||
|
|
||||||
if (HCL_CNODE_IS_ELIST_CONCODED(args, HCL_CONCODE_XLIST))
|
HCL_ASSERT (hcl, HCL_CNODE_IS_ELIST_CONCODED(arg_list, HCL_CONCODE_XLIST) ||
|
||||||
|
HCL_CNODE_IS_CONS_CONCODED(arg_list, HCL_CONCODE_XLIST));
|
||||||
|
if (HCL_CNODE_IS_ELIST_CONCODED(arg_list, HCL_CONCODE_XLIST))
|
||||||
{
|
{
|
||||||
/* empty list - no argument - (fun () (+ 10 20)) */
|
/* empty list - no argument - fun () {+ 10 20} */
|
||||||
}
|
/* do nothing */
|
||||||
else if (!HCL_CNODE_IS_CONS_CONCODED(args, HCL_CONCODE_XLIST))
|
|
||||||
{
|
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGNAMELIST, HCL_CNODE_GET_LOC(args), HCL_CNODE_GET_TOK(args), "no argument list in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3128,22 +3175,33 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
int in_ret_args = 0;
|
int in_ret_args = 0;
|
||||||
|
|
||||||
tv_dup_start = hcl->c->tv.s.len;
|
tv_dup_start = hcl->c->tv.s.len;
|
||||||
dcl = args;
|
dcl = arg_list;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
arg = HCL_CNODE_CONS_CAR(dcl);
|
arg = HCL_CNODE_CONS_CAR(dcl);
|
||||||
|
|
||||||
if (in_ret_args)
|
if (in_ret_args)
|
||||||
{
|
{
|
||||||
if (!HCL_CNODE_IS_SYMBOL(arg))
|
if (!HCL_CNODE_IS_SYMBOL_PLAIN_IDENT(arg))
|
||||||
{
|
{
|
||||||
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));
|
/* in 'fun x (x :: 20) { }', '20' is not a valid return variable name.
|
||||||
|
* in 'fun x (x :: if) { }', 'if' is not a valid return variable name. */
|
||||||
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(arg), HCL_NULL,
|
||||||
|
"invalid return variable '%.*js' for '%.*js'",
|
||||||
|
HCL_CNODE_GET_TOKLEN(arg), HCL_CNODE_GET_TOKPTR(arg),
|
||||||
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: delete this error check once SYNCODE stuffs are all deleted */
|
||||||
if (HCL_CNODE_IS_SYMBOL(arg) && HCL_CNODE_SYMBOL_SYNCODE(arg) /* || HCL_OBJ_GET_FLAGS_KERNEL(arg) >= 2 */)
|
if (HCL_CNODE_IS_SYMBOL(arg) && HCL_CNODE_SYMBOL_SYNCODE(arg) /* || HCL_OBJ_GET_FLAGS_KERNEL(arg) >= 2 */)
|
||||||
{
|
{
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNEDVARNAME, HCL_CNODE_GET_LOC(arg), HCL_CNODE_GET_TOK(arg), "special symbol not to be declared as return variable in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_BANNEDVARNAME, HCL_CNODE_GET_LOC(arg), HCL_NULL,
|
||||||
|
"special symbol '%.*js' used as return variable for '%.*js'",
|
||||||
|
HCL_CNODE_GET_TOKLEN(arg), HCL_CNODE_GET_TOKPTR(arg),
|
||||||
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3151,7 +3209,12 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
{
|
{
|
||||||
if (hcl->errnum == HCL_EEXIST)
|
if (hcl->errnum == HCL_EEXIST)
|
||||||
{
|
{
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAMEDUP, HCL_CNODE_GET_LOC(arg), HCL_CNODE_GET_TOK(arg), "return variable duplicate in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
/* in 'fun x (y :: z z) {}', the second 'z' is duplicate */
|
||||||
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_VARNAMEDUP, HCL_CNODE_GET_LOC(arg), HCL_NULL,
|
||||||
|
"duplicate return variable '%.*js' for '%.*js'",
|
||||||
|
HCL_CNODE_GET_TOKLEN(arg), HCL_CNODE_GET_TOKPTR(arg),
|
||||||
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -3165,7 +3228,13 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_CNODE, HCL_CNODE_GET_LOC(arg), HCL_CNODE_GET_TOK(arg), "unexpected element in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
/* in 'fun x (... a) {}', 'a' is an unexpected token.
|
||||||
|
* only ')' or '::' can follow ... */
|
||||||
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_CNODE, HCL_CNODE_GET_LOC(arg), HCL_NULL,
|
||||||
|
"unexpected token '%.*js' after '...' for '%.*js'",
|
||||||
|
HCL_CNODE_GET_TOKLEN(arg), HCL_CNODE_GET_TOKPTR(arg),
|
||||||
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3179,16 +3248,25 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
{
|
{
|
||||||
va = 1;
|
va = 1;
|
||||||
}
|
}
|
||||||
else if (!HCL_CNODE_IS_SYMBOL(arg))
|
else if (!HCL_CNODE_IS_SYMBOL_PLAIN_IDENT(arg))
|
||||||
{
|
{
|
||||||
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));
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_ARGNAME, HCL_CNODE_GET_LOC(arg), HCL_NULL,
|
||||||
|
"invalid argument name '%.*js' for '%.*js'",
|
||||||
|
HCL_CNODE_GET_TOKLEN(arg), HCL_CNODE_GET_TOKPTR(arg),
|
||||||
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* TODO: delete this error check once SYNCODE stuffs are all deleted */
|
||||||
if (HCL_CNODE_IS_SYMBOL(arg) && HCL_CNODE_SYMBOL_SYNCODE(arg) /* || HCL_OBJ_GET_FLAGS_KERNEL(arg) >= 2 */)
|
if (HCL_CNODE_IS_SYMBOL(arg) && HCL_CNODE_SYMBOL_SYNCODE(arg) /* || HCL_OBJ_GET_FLAGS_KERNEL(arg) >= 2 */)
|
||||||
{
|
{
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_BANNEDARGNAME, HCL_CNODE_GET_LOC(arg), HCL_CNODE_GET_TOK(arg), "special symbol not to be declared as argument in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_BANNEDARGNAME, HCL_CNODE_GET_LOC(arg), HCL_NULL,
|
||||||
|
"special symbol '%.*js' used as argument name for '%.*js'",
|
||||||
|
HCL_CNODE_GET_TOKLEN(arg), HCL_CNODE_GET_TOKPTR(arg),
|
||||||
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3196,7 +3274,11 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
{
|
{
|
||||||
if (hcl->errnum == HCL_EEXIST)
|
if (hcl->errnum == HCL_EEXIST)
|
||||||
{
|
{
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGNAMEDUP, HCL_CNODE_GET_LOC(arg), HCL_CNODE_GET_TOK(arg), "argument duplicate in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_ARGNAMEDUP, HCL_CNODE_GET_LOC(arg), HCL_NULL,
|
||||||
|
"duplicate argument name '%.*js' for '%.*js'",
|
||||||
|
HCL_CNODE_GET_TOKLEN(arg), HCL_CNODE_GET_TOKPTR(arg),
|
||||||
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -3209,7 +3291,8 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
|
|
||||||
if (!HCL_CNODE_IS_CONS(dcl))
|
if (!HCL_CNODE_IS_CONS(dcl))
|
||||||
{
|
{
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_DOTBANNED, HCL_CNODE_GET_LOC(dcl), HCL_CNODE_GET_TOK(dcl), "redundant cdr in argument list in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
hcl_setsynerrbfmt (hcl, HCL_SYNERR_DOTBANNED, HCL_CNODE_GET_LOC(dcl), HCL_CNODE_GET_TOK(dcl),
|
||||||
|
"redundant cdr in argument list in %.*js", HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3222,18 +3305,23 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
* block arguments, evaluation which is done by message passing
|
* block arguments, evaluation which is done by message passing
|
||||||
* limits the number of arguments that can be passed. so the
|
* limits the number of arguments that can be passed. so the
|
||||||
* check is implemented */
|
* check is implemented */
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_ARGFLOOD, HCL_CNODE_GET_LOC(args), HCL_NULL, "too many(%zu) arguments in %.*js", nargs, HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_ARGFLOOD, HCL_CNODE_GET_LOC(arg_list), HCL_NULL,
|
||||||
|
"too many(%zu) arguments in %.*js", nargs,
|
||||||
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nrvars > MAX_CODE_NBLKLVARS)
|
if (nrvars > MAX_CODE_NBLKLVARS)
|
||||||
{
|
{
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARFLOOD, HCL_CNODE_GET_LOC(args), HCL_NULL, "too many(%zu) return variables in %.*js", nrvars, HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_VARFLOOD, HCL_CNODE_GET_LOC(arg_list), HCL_NULL,
|
||||||
|
"too many(%zu) return variables in %.*js", nrvars,
|
||||||
|
HCL_CNODE_GET_TOKLEN(cmd), HCL_CNODE_GET_TOKPTR(cmd));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
HCL_ASSERT (hcl, nargs + nrvars == hcl->c->tv.wcount - saved_tv_wcount);
|
HCL_ASSERT (hcl, nargs + nrvars == hcl->c->tv.wcount - saved_tv_wcount);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fun aa(a b) { ... };
|
* fun aa(a b) { ... };
|
||||||
* (fun aa(a b) { ... })
|
* (fun aa(a b) { ... })
|
||||||
@ -3242,10 +3330,9 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
* the variable declaration can't be placed before the block expression.
|
* the variable declaration can't be placed before the block expression.
|
||||||
* it is supported inside the block expression itself.
|
* it is supported inside the block expression itself.
|
||||||
*/
|
*/
|
||||||
hcl_cnode_t* blk;
|
if (check_block_expression_as_body(hcl, fun_body, cmd, FOR_NONE) <= -1) return -1;
|
||||||
blk = HCL_CNODE_CONS_CDR(obj);
|
|
||||||
if (check_block_expression_as_body(hcl, blk, cmd, FOR_NONE) <= -1) return -1;
|
HCL_ASSERT (hcl, fun_body != HCL_NULL);
|
||||||
obj = blk;
|
|
||||||
nlvars = 0; /* no known local variables until the actual block is processed */
|
nlvars = 0; /* no known local variables until the actual block is processed */
|
||||||
|
|
||||||
HCL_ASSERT (hcl, nargs + nrvars + nlvars == hcl->c->tv.wcount - saved_tv_wcount);
|
HCL_ASSERT (hcl, nargs + nrvars + nlvars == hcl->c->tv.wcount - saved_tv_wcount);
|
||||||
@ -3273,7 +3360,7 @@ static int compile_fun (hcl_t* hcl, hcl_cnode_t* src)
|
|||||||
* produce the long jump instruction (HCL_CODE_JUMP_FORWARD_X) */
|
* produce the long jump instruction (HCL_CODE_JUMP_FORWARD_X) */
|
||||||
if (emit_single_param_instruction(hcl, HCL_CODE_JUMP_FORWARD_0, MAX_CODE_JUMP, HCL_CNODE_GET_LOC(cmd)) <= -1) return -1;
|
if (emit_single_param_instruction(hcl, HCL_CODE_JUMP_FORWARD_0, MAX_CODE_JUMP, HCL_CNODE_GET_LOC(cmd)) <= -1) return -1;
|
||||||
|
|
||||||
SWITCH_TOP_CFRAME (hcl, COP_COMPILE_OBJECT_LIST, obj); /* 1 */
|
SWITCH_TOP_CFRAME (hcl, COP_COMPILE_OBJECT_LIST, fun_body); /* 1 */
|
||||||
PUSH_SUBCFRAME (hcl, COP_POST_FUN, fun_name); /* 3*/
|
PUSH_SUBCFRAME (hcl, COP_POST_FUN, fun_name); /* 3*/
|
||||||
cf = GET_SUBCFRAME(hcl);
|
cf = GET_SUBCFRAME(hcl);
|
||||||
cf->u.fun.fun_type = fun_type;
|
cf->u.fun.fun_type = fun_type;
|
||||||
@ -4640,7 +4727,7 @@ static HCL_INLINE int compile_dsymbol (hcl_t* hcl, hcl_cnode_t* obj)
|
|||||||
/* if defined using A::xxx syntax, it's not possible to know the instance position of an instance variable.
|
/* 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 a() {
|
||||||
* fun J::t() {
|
* fun J:t() {
|
||||||
* ## J has nothing to to with X in priciple even if J may point to X when a() is executed.
|
* ## J has nothing to to with X in priciple even if J may point to X when a() is executed.
|
||||||
* ## it's not meaningful to look up the variable `a` in the context of class X.
|
* ## it's not meaningful to look up the variable `a` in the context of class X.
|
||||||
* ## it must be prohibited to access instance variables using the self or super prefix
|
* ## it must be prohibited to access instance variables using the self or super prefix
|
||||||
@ -4659,7 +4746,7 @@ static HCL_INLINE int compile_dsymbol (hcl_t* hcl, hcl_cnode_t* obj)
|
|||||||
}
|
}
|
||||||
else if (hcl_comp_oochars_bcstr(name.ptr, sep - (const hcl_ooch_t*)name.ptr, "super") == 0)
|
else if (hcl_comp_oochars_bcstr(name.ptr, sep - (const hcl_ooch_t*)name.ptr, "super") == 0)
|
||||||
{
|
{
|
||||||
if (fbi->fun_type >> 8) /* if defined using A::xxx syntax */
|
if (fbi->fun_type >> 8) /* if defined using A:xxx syntax */
|
||||||
{
|
{
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(obj), HCL_CNODE_GET_TOK(obj), "not allowed to prefix with super in out-of-class method context");
|
hcl_setsynerrbfmt (hcl, HCL_SYNERR_VARNAME, HCL_CNODE_GET_LOC(obj), HCL_CNODE_GET_TOK(obj), "not allowed to prefix with super in out-of-class method context");
|
||||||
return -1;
|
return -1;
|
||||||
@ -6107,7 +6194,10 @@ static HCL_INLINE int post_fun (hcl_t* hcl)
|
|||||||
{
|
{
|
||||||
/* something wrong - this must not happen because the reader must prevent this
|
/* something wrong - this must not happen because the reader must prevent this
|
||||||
* but if it happens, it is a syntax error */
|
* but if it happens, it is a syntax error */
|
||||||
hcl_setsynerrbfmt(hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(class_name), HCL_CNODE_GET_TOK(class_name), "class name prohibited");
|
hcl_setsynerrbfmt (
|
||||||
|
hcl, HCL_SYNERR_BANNED, HCL_CNODE_GET_LOC(class_name), HCL_NULL,
|
||||||
|
"class name '%.js' prohibited class initialization context",
|
||||||
|
HCL_CNODE_GET_TOKLEN(class_name), HCL_CNODE_GET_TOKPTR(class_name));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,6 +400,16 @@ enum hcl_cnode_type_t
|
|||||||
HCL_CNODE_SELF,
|
HCL_CNODE_SELF,
|
||||||
HCL_CNODE_SUPER,
|
HCL_CNODE_SUPER,
|
||||||
|
|
||||||
|
HCL_CNODE_CONS,
|
||||||
|
HCL_CNODE_ELIST, /* empty list */
|
||||||
|
HCL_CNODE_SHELL, /* pseudo-node to hold another actual node */
|
||||||
|
|
||||||
|
/* If HCL_CNODE_SHELL is not the last item before the horizontal line,
|
||||||
|
* HCL_CNDOE_IS_FOR_DATA(x) must be revised */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/* the cnode types from here don't represent actual data.
|
||||||
|
* these represent syntactical elements of the language only. */
|
||||||
HCL_CNODE_CLASS,
|
HCL_CNODE_CLASS,
|
||||||
HCL_CNODE_FUN,
|
HCL_CNODE_FUN,
|
||||||
HCL_CNODE_DO,
|
HCL_CNODE_DO,
|
||||||
@ -423,10 +433,6 @@ enum hcl_cnode_type_t
|
|||||||
HCL_CNODE_COLONGT, /* :> */
|
HCL_CNODE_COLONGT, /* :> */
|
||||||
HCL_CNODE_COLONLT, /* :< */
|
HCL_CNODE_COLONLT, /* :< */
|
||||||
HCL_CNODE_COLONSTAR, /* :* */
|
HCL_CNODE_COLONSTAR, /* :* */
|
||||||
|
|
||||||
HCL_CNODE_CONS,
|
|
||||||
HCL_CNODE_ELIST, /* empty list */
|
|
||||||
HCL_CNODE_SHELL /* pseudo-node to hold another actual node */
|
|
||||||
};
|
};
|
||||||
typedef enum hcl_cnode_type_t hcl_cnode_type_t;
|
typedef enum hcl_cnode_type_t hcl_cnode_type_t;
|
||||||
|
|
||||||
@ -444,6 +450,7 @@ typedef enum hcl_cnode_flag_t hcl_cnode_flag_t;
|
|||||||
#define HCL_CNODE_GET_TOKLEN(x) ((x)->cn_tok.len)
|
#define HCL_CNODE_GET_TOKLEN(x) ((x)->cn_tok.len)
|
||||||
|
|
||||||
#define HCL_CNODE_IS_TYPED(x, _type) ((x)->cn_type == _type)
|
#define HCL_CNODE_IS_TYPED(x, _type) ((x)->cn_type == _type)
|
||||||
|
#define HCL_CNODE_IS_FOR_DATA(x) ((x)->cn_type <= HCL_CNODE_SHELL)
|
||||||
|
|
||||||
#define HCL_CNODE_IS_ELLIPSIS(x) ((x)->cn_type == HCL_CNODE_ELLIPSIS)
|
#define HCL_CNODE_IS_ELLIPSIS(x) ((x)->cn_type == HCL_CNODE_ELLIPSIS)
|
||||||
#define HCL_CNODE_IS_TRPCOLONS(x) ((x)->cn_type == HCL_CNODE_TRPCOLONS)
|
#define HCL_CNODE_IS_TRPCOLONS(x) ((x)->cn_type == HCL_CNODE_TRPCOLONS)
|
||||||
|
28
lib/read.c
28
lib/read.c
@ -896,7 +896,27 @@ static HCL_INLINE int can_colon_list (hcl_t* hcl)
|
|||||||
if (HCL_CNODE_IS_SYMBOL_SYNCODED(HCL_CNODE_CONS_CAR(rstl->head), HCL_SYNCODE_FUN) ||
|
if (HCL_CNODE_IS_SYMBOL_SYNCODED(HCL_CNODE_CONS_CAR(rstl->head), HCL_SYNCODE_FUN) ||
|
||||||
HCL_CNODE_IS_TYPED(HCL_CNODE_CONS_CAR(rstl->head), HCL_CNODE_FUN))
|
HCL_CNODE_IS_TYPED(HCL_CNODE_CONS_CAR(rstl->head), HCL_CNODE_FUN))
|
||||||
{
|
{
|
||||||
if (rstl->count == 2) return 2;
|
hcl_cnode_t* tmp, * next;
|
||||||
|
next = HCL_CNODE_CONS_CDR(rstl->head);
|
||||||
|
HCL_ASSERT (hcl, next != HCL_NULL);
|
||||||
|
tmp = HCL_CNODE_CONS_CAR(next); /* second item */
|
||||||
|
if (rstl->count == 2)
|
||||||
|
{
|
||||||
|
/* fun class:name() *... */
|
||||||
|
if (HCL_CNODE_IS_SYMBOL_PLAIN(tmp)) return 2;
|
||||||
|
}
|
||||||
|
else if (rstl->count == 3)
|
||||||
|
{
|
||||||
|
/* fun(#c) class:name() ... */
|
||||||
|
if (HCL_CNODE_IS_CONS_CONCODED(tmp, HCL_CONCODE_XLIST) ||
|
||||||
|
HCL_CNODE_IS_ELIST_CONCODED(tmp, HCL_CONCODE_XLIST))
|
||||||
|
{
|
||||||
|
next = HCL_CNODE_CONS_CDR(next);
|
||||||
|
HCL_ASSERT (hcl, next != HCL_NULL);
|
||||||
|
tmp = HCL_CNODE_CONS_CAR(next); /* third item */
|
||||||
|
if (HCL_CNODE_IS_SYMBOL_PLAIN(tmp)) return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0; /* the first key is not colon-delimited. so not allowed to colon-delimit other keys */
|
return 0; /* the first key is not colon-delimited. so not allowed to colon-delimit other keys */
|
||||||
@ -908,11 +928,17 @@ static HCL_INLINE int can_colon_list (hcl_t* hcl)
|
|||||||
cc = (hcl_concode_t)LIST_FLAG_GET_CONCODE(rstl->flagv);
|
cc = (hcl_concode_t)LIST_FLAG_GET_CONCODE(rstl->flagv);
|
||||||
if (cc == HCL_CONCODE_XLIST)
|
if (cc == HCL_CONCODE_XLIST)
|
||||||
{
|
{
|
||||||
|
hcl_cnode_t* tmp;
|
||||||
|
|
||||||
/* method defintion with fun - e.g. fun String:length()
|
/* method defintion with fun - e.g. fun String:length()
|
||||||
* ugly that this reader must know about the meaning of fun */
|
* ugly that this reader must know about the meaning of fun */
|
||||||
if (rstl->count > 1) return 0;
|
if (rstl->count > 1) return 0;
|
||||||
|
|
||||||
/* ugly dual use of a colon sign. switch to MLIST if the first element
|
/* ugly dual use of a colon sign. switch to MLIST if the first element
|
||||||
* is delimited by a colon. e.g. (obj:new 10 20 30) */
|
* is delimited by a colon. e.g. (obj:new 10 20 30) */
|
||||||
|
tmp = HCL_CNODE_CONS_CAR(rstl->head);
|
||||||
|
if (!HCL_CNODE_IS_FOR_DATA(tmp)) return 0;
|
||||||
|
|
||||||
LIST_FLAG_SET_CONCODE(rstl->flagv, HCL_CONCODE_MLIST);
|
LIST_FLAG_SET_CONCODE(rstl->flagv, HCL_CONCODE_MLIST);
|
||||||
rstl->flagv &= ~JSON;
|
rstl->flagv &= ~JSON;
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,11 @@ class B + ##ERROR: syntax error - prohibited binary selector '+'
|
|||||||
J := 11
|
J := 11
|
||||||
class B {
|
class B {
|
||||||
if (== J 10) {
|
if (== J 10) {
|
||||||
fun :*newA() {
|
fun(#ci) newA() {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fun :*newB() {
|
fun(#ci) newB() {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ class B [ x y ] {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class X :: B [ a b ] {
|
class X :: B [ a b ] {
|
||||||
fun :* new(t) {
|
fun(#ci) new(t) {
|
||||||
| a |
|
| a |
|
||||||
set self.a t;
|
set self.a t;
|
||||||
set a 100;
|
set a 100;
|
||||||
@ -67,24 +67,25 @@ class X :: B [ a b ] {
|
|||||||
---
|
---
|
||||||
|
|
||||||
class X {
|
class X {
|
||||||
fun :* xxx() {
|
fun(#ci) xxx() {
|
||||||
return X;
|
return X;
|
||||||
}
|
}
|
||||||
fun :* qqq() {
|
|
||||||
|
fun(#ci) qqq() {
|
||||||
return "hello"
|
return "hello"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String:length() { ##ERROR: syntax error - function name not valid
|
fun String:length() { ##ERROR: syntax error - class name 'String' before :'length' prohibited in class initialization context
|
||||||
return (str.length self)
|
return (core.basicSize self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
class X {
|
class X {
|
||||||
fun :* xxx() {
|
fun(#ci) xxx() {
|
||||||
return X;
|
return X;
|
||||||
}
|
}
|
||||||
fun :* qqq() {
|
fun(#ci) qqq() {
|
||||||
return "hello"
|
return "hello"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,7 +110,7 @@ fun X:xxx() { ##ERROR: exception not handled - "not class"
|
|||||||
## and the clase instantiation method can't specify the size
|
## and the clase instantiation method can't specify the size
|
||||||
## you can't place an item in the arrya at all.
|
## you can't place an item in the arrya at all.
|
||||||
|
|
||||||
fun Array:*boom() {
|
fun(#ci) Array:boom() {
|
||||||
core.basicAtPut self 0 10 ##ERROR: exception not handled - "position(0) out of range - negative or greater than or equal to 0"
|
core.basicAtPut self 0 10 ##ERROR: exception not handled - "position(0) out of range - negative or greater than or equal to 0"
|
||||||
printf "%O" self
|
printf "%O" self
|
||||||
return self
|
return self
|
||||||
@ -119,7 +120,7 @@ Array:boom
|
|||||||
---
|
---
|
||||||
|
|
||||||
class X [ a b c ] {
|
class X [ a b c ] {
|
||||||
fun :* new () {
|
fun(#ci) new () {
|
||||||
self.a := 20
|
self.a := 20
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
@ -186,3 +187,10 @@ F := (class F { ##ERROR: exception not handle - "prohibited redefintion of F"
|
|||||||
##F := 30
|
##F := 30
|
||||||
##class F { ##ERROR: exception not handled - "prohibited redefintion of F"
|
##class F { ##ERROR: exception not handled - "prohibited redefintion of F"
|
||||||
##}
|
##}
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
class a {
|
||||||
|
fun() { ##ERROR: syntax error - unnamed function defined with 'fun' prohibited in class initialziation context
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -146,6 +146,11 @@ fun :* fun1() { ##ERROR: syntax error - invalid function name ':*' for 'fun'
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
fun(#ci) fun1() { ##ERROR: syntax error - unsupported attribute list for plain function 'fun1'
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
(10 + 20 30) ##ERROR: syntax error - redundant operand '30'
|
(10 + 20 30) ##ERROR: syntax error - redundant operand '30'
|
||||||
|
|
||||||
---
|
---
|
||||||
|
19
t/fun-01.hcl
19
t/fun-01.hcl
@ -97,7 +97,7 @@ if (== y 29) {
|
|||||||
## --------------------------------------
|
## --------------------------------------
|
||||||
|
|
||||||
defclass A [ a b c ] {
|
defclass A [ a b c ] {
|
||||||
fun :* newInstance(x y z) {
|
fun(#ci) newInstance(x y z) {
|
||||||
set a x
|
set a x
|
||||||
set b y
|
set b y
|
||||||
set c z
|
set c z
|
||||||
@ -113,8 +113,15 @@ k := (A:newInstance 11 22 33);
|
|||||||
##set k (A:newInstance 11 22 33);
|
##set k (A:newInstance 11 22 33);
|
||||||
|
|
||||||
set v (k:get-a);
|
set v (k:get-a);
|
||||||
if (== v 11) {
|
if (== v 11) { printf "OK - %d\n" v; } else { printf "ERROR - %d, ot 11\n" v; };
|
||||||
printf "OK - %d\n" v;
|
|
||||||
} else {
|
## --------------------------------------
|
||||||
printf "ERROR - %d\n" v;
|
|
||||||
};
|
k := (fun (x) { + x 20 }) ## (+ x 20) would be syntax error, must be { + x 20 }
|
||||||
|
v := (k 10)
|
||||||
|
if (== v 30) { printf "OK - %d\n" v } else { printf "ERROR - %d, not 30\n" v };
|
||||||
|
|
||||||
|
## --------------------------------------
|
||||||
|
fun k(x) (+ x 30) ## (+ x 30) is valid function body
|
||||||
|
v := (k 10)
|
||||||
|
if (== v 40) { printf "OK - %d\n" v } else { printf "ERROR - %d, not 40\n" v };
|
||||||
|
@ -14,7 +14,7 @@ fun Number: ~= (oprnd) { return (~= self oprnd) }
|
|||||||
|
|
||||||
class A [ a b c ] {
|
class A [ a b c ] {
|
||||||
|
|
||||||
fun :*newInstance(x y z) {
|
fun(#ci) newInstance(x y z) {
|
||||||
set a x;
|
set a x;
|
||||||
set b y;
|
set b y;
|
||||||
set c z;
|
set c z;
|
||||||
@ -28,7 +28,7 @@ class A [ a b c ] {
|
|||||||
|
|
||||||
class B :: A [ d e f ] {
|
class B :: A [ d e f ] {
|
||||||
|
|
||||||
fun :*newInstance(x y z) {
|
fun(#ci) newInstance(x y z) {
|
||||||
super:newInstance (* x 2) (* y 2) (* z 2);
|
super:newInstance (* x 2) (* y 2) (* z 2);
|
||||||
set d x;
|
set d x;
|
||||||
set e y;
|
set e y;
|
||||||
@ -36,9 +36,9 @@ class B :: A [ d e f ] {
|
|||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
|
|
||||||
fun :: getSuper() { return super; };
|
fun(#c) getSuper() { return super; };
|
||||||
###fun :: getSuperclass() { return (self:superclass); };
|
###fun(#c) getSuperclass() { return (self:superclass); };
|
||||||
fun :: getSelf() { return self; };
|
fun(#c) getSelf() { return self; };
|
||||||
|
|
||||||
fun sum() {
|
fun sum() {
|
||||||
return (+ (super:get-a) (super:get-b) (super:get-c) self.d self.e self.f);
|
return (+ (super:get-a) (super:get-b) (super:get-c) self.d self.e self.f);
|
||||||
|
@ -12,7 +12,7 @@ fun Number: ~= (oprnd) { return (~= self oprnd) }
|
|||||||
## --------------------------------------------------------------
|
## --------------------------------------------------------------
|
||||||
set t (
|
set t (
|
||||||
class [ x ] {
|
class [ x ] {
|
||||||
fun :* make() { x := 1234; return self; };
|
fun(#ci) make() { x := 1234; return self; };
|
||||||
fun get-x() { return x };
|
fun get-x() { return x };
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -40,7 +40,7 @@ else { printf "OK: value is %d\n" v };
|
|||||||
## --------------------------------------------------------------
|
## --------------------------------------------------------------
|
||||||
|
|
||||||
class X0 [ a b c d ] {
|
class X0 [ a b c d ] {
|
||||||
fun :*new() {
|
fun(#ci) new() {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ else { printf "OK: value is %d\n" v }
|
|||||||
## --------------------------------------------------------------
|
## --------------------------------------------------------------
|
||||||
|
|
||||||
class X1 [ a b c ] {
|
class X1 [ a b c ] {
|
||||||
fun :* new () {
|
fun(#classinst) new () {
|
||||||
self.a := 20
|
self.a := 20
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
@ -108,11 +108,11 @@ class F [ j t ] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class X2 [ a b c ] {
|
class X2 [ a b c ] {
|
||||||
fun :* new () {
|
fun(#classinst) new () {
|
||||||
| j |
|
| j |
|
||||||
self.a := 20
|
self.a := 20
|
||||||
j := (self.a * 2)
|
j := (self.a * 2)
|
||||||
fun F::get_x() { return (j * j) }
|
fun(#class) F:get_x() { return (j * j) }
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,7 +124,7 @@ else { printf "OK: value is %d\n" v }
|
|||||||
|
|
||||||
## --------------------------------------------------------------
|
## --------------------------------------------------------------
|
||||||
class X3 {
|
class X3 {
|
||||||
fun :* new (a b) {
|
fun(#ci) new (a b) {
|
||||||
fun X3:sum() { return (fun(j) { return (j + (a + b)) }) }
|
fun X3:sum() { return (fun(j) { return (j + (a + b)) }) }
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -136,15 +136,15 @@ else { printf "OK: value is %d\n" v }
|
|||||||
|
|
||||||
## --------------------------------------------------------------
|
## --------------------------------------------------------------
|
||||||
class X4 {
|
class X4 {
|
||||||
fun :: t() {
|
fun(#class) t() {
|
||||||
| X5 |
|
| X5 |
|
||||||
class X5 { ## this X5 isn't the local variable X4
|
class X5 { ## this X5 isn't the local variable X4
|
||||||
fun :: t() {
|
fun(#class) t() {
|
||||||
X6 := (class {
|
X6 := (class {
|
||||||
fun :: t() {
|
fun(#class) t() {
|
||||||
| X7 |
|
| X7 |
|
||||||
X7 := (class { ## this X4 is the local variable X4
|
X7 := (class { ## this X4 is the local variable X4
|
||||||
fun :: t() { return 60 }
|
fun(#class) t() { return 60 }
|
||||||
})
|
})
|
||||||
return 40
|
return 40
|
||||||
}
|
}
|
||||||
|
@ -36,12 +36,12 @@
|
|||||||
set X1 999;
|
set X1 999;
|
||||||
set X2 888;
|
set X2 888;
|
||||||
|
|
||||||
fun :: get ( :: x y) {
|
fun(#class) get ( :: x y) {
|
||||||
set x X1;
|
set x X1;
|
||||||
set y X2;
|
set y X2;
|
||||||
};
|
};
|
||||||
|
|
||||||
fun :: get2 (inc :: x y) {
|
fun(#class) get2 (inc :: x y) {
|
||||||
set x (+ X1 inc);
|
set x (+ X1 inc);
|
||||||
set y (+ X2 inc);
|
set y (+ X2 inc);
|
||||||
};
|
};
|
||||||
@ -60,9 +60,9 @@
|
|||||||
else { printf "OK: d=%d\n" d }
|
else { printf "OK: d=%d\n" d }
|
||||||
|
|
||||||
class X [ x, y ] {
|
class X [ x, y ] {
|
||||||
fun ::f(a :: b c) { b := (+ a 10); c := (+ a 20) }
|
fun(#class) f(a :: b c) { b := (+ a 10); c := (+ a 20) }
|
||||||
|
|
||||||
fun :*new(z) {
|
fun(#classinst) new(z) {
|
||||||
## multi-variable assignment with return variables to member variables
|
## multi-variable assignment with return variables to member variables
|
||||||
[self.x, self.y] := (X:f z)
|
[self.x, self.y] := (X:f z)
|
||||||
return self;
|
return self;
|
||||||
@ -83,7 +83,7 @@
|
|||||||
|
|
||||||
|
|
||||||
## create a new binary operator message returning two output values
|
## create a new binary operator message returning two output values
|
||||||
fun Number: // (x :: quo rem) {
|
fun Number:// (x :: quo rem) {
|
||||||
quo := (/ self x)
|
quo := (/ self x)
|
||||||
rem := (- self (* quo x))
|
rem := (- self (* quo x))
|
||||||
}
|
}
|
||||||
|
5
t/run.sh
5
t/run.sh
@ -3,4 +3,9 @@
|
|||||||
## program crashes or exits without an error message.
|
## program crashes or exits without an error message.
|
||||||
echo RUN "[$@]"
|
echo RUN "[$@]"
|
||||||
($@ 2>&1 || echo "ERROR: exited with $?") | grep -E '^ERROR:' && exit 1
|
($@ 2>&1 || echo "ERROR: exited with $?") | grep -E '^ERROR:' && exit 1
|
||||||
|
##[ "x$MEMCHECK" = "xyes" ] && {
|
||||||
|
## [ -x /usr/bin/valgrind ] && {
|
||||||
|
## valgrind --leak-check=full --show-reachable=yes --track-fds=yes --log-file=/tmp/x "$@" 2>&1
|
||||||
|
## }
|
||||||
|
##}
|
||||||
exit 0
|
exit 0
|
||||||
|
@ -58,7 +58,7 @@ x
|
|||||||
|
|
||||||
class T [ j ] {
|
class T [ j ] {
|
||||||
|
|
||||||
fun :* new() {
|
fun(#classinst) new() {
|
||||||
set j 99
|
set j 99
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
defclass A [ a ] {
|
defclass A [ a ] {
|
||||||
fun :* init1() {
|
fun(#ci) init1() {
|
||||||
| b |
|
| b |
|
||||||
set b (+ 1 2);
|
set b (+ 1 2);
|
||||||
set a b;
|
set a b;
|
||||||
@ -15,7 +15,7 @@ defclass A [ a ] {
|
|||||||
printf ">>> %d\n" j;
|
printf ">>> %d\n" j;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun :* init2() {
|
fun(#ci) init2() {
|
||||||
| b |
|
| b |
|
||||||
set b (+ 10 20);
|
set b (+ 10 20);
|
||||||
set a b;
|
set a b;
|
||||||
@ -26,7 +26,7 @@ defclass A [ a ] {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
fun String length() { ##ERROR: syntax error - no argument list
|
fun String length() { ##ERROR: syntax error - 'String' not followed by ( but followed by 'length'
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -1,2 +1,66 @@
|
|||||||
fun self.x() { ##ERROR: syntax error - invalid function name 'self.x' for 'fun'
|
fun self.x() { ##ERROR: syntax error - invalid function name 'self.x' for 'fun'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
fun if() { ##ERROR: syntax error - invalid function name 'if' for 'fun'
|
||||||
|
};
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
fun a if() { ##ERROR: syntax error - 'a' not followed by ( but followed by 'if'
|
||||||
|
};
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
fun a:b if() { ##ERROR: syntax error - 'b' not followed by ( but followed by 'if'
|
||||||
|
};
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
fun x (x :: 20) { ##ERROR: syntax error - invalid return variable '20' for 'fun'
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
fun x (x :: if) { ##ERROR: syntax error - invalid return variable 'if' for 'fun'
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
fun x (x :: self.y) { ##ERROR: syntax error - invalid return variable 'self.y' for 'fun'
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
fun x (x :: z z) { ##ERROR: syntax error - duplicate return variable 'z' for 'fun'
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
fun x (x 20) { ##ERROR: syntax error - invalid argument name '20' for 'fun'
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
fun x (+) { ##ERROR: syntax error - invalid argument name '+' for 'fun'
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
fun x (a while) { ##ERROR: syntax error - invalid argument name 'while' for 'fun'
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
fun x (a b a) { ##ERROR: syntax error - duplicate argument name 'a' for 'fun'
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
fun x (... a) { ##ERROR: syntax error - unexpected token 'a' after '...' for 'fun'
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
fun x (... : a) { ##ERROR: syntax error - : disallowed
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user