From 37b652ead601a03999098cb1137cfb99923549f6 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 15 Sep 2025 01:41:43 +0900 Subject: [PATCH] changed the syntax for clarity - attribute list to use a tuple, class variable list to use a normal parenthesized list --- lib/comp.c | 158 +++++++++++++++++++---------------------------- lib/read.c | 2 - t/class-5001.err | 56 +++++++++++------ t/fun-01.hak | 2 +- t/insta-01.hak | 10 +-- t/insta-02.hak | 22 +++---- t/retvar-01.hak | 8 +-- t/var-01.hak | 2 +- t/var-5001.err | 20 +++--- t/var-5004.err | 8 +-- 10 files changed, 140 insertions(+), 148 deletions(-) diff --git a/lib/comp.c b/lib/comp.c index ab8ac7a..6bb8b5c 100644 --- a/lib/comp.c +++ b/lib/comp.c @@ -1514,7 +1514,7 @@ static int collect_vardcl_for_class (hak_t* hak, hak_cnode_t* obj, hak_cnode_t** tv_slen_saved = hak->c->tv.s.len; dcl = HAK_CNODE_CONS_CAR(obj); - HAK_ASSERT(hak, HAK_CNODE_IS_CONS_CONCODED(dcl, HAK_CONCODE_TUPLE)); + HAK_ASSERT(hak, HAK_CNODE_IS_CONS_CONCODED(dcl, HAK_CONCODE_XLIST)); do { @@ -1524,7 +1524,7 @@ static int collect_vardcl_for_class (hak_t* hak, hak_cnode_t* obj, hak_cnode_t** var = HAK_CNODE_CONS_CAR(dcl); - if (HAK_CNODE_IS_CONS_CONCODED(var, HAK_CONCODE_TUPLE)) /* [ ... ] */ + if (HAK_CNODE_IS_CONS_CONCODED(var, HAK_CONCODE_XLIST)) /* ( ... ) */ { if (enclosed) { @@ -1539,10 +1539,10 @@ static int collect_vardcl_for_class (hak_t* hak, hak_cnode_t* obj, hak_cnode_t** dcl = var; continue; /* start over */ } - else if (HAK_CNODE_IS_ELIST_CONCODED(var, HAK_CONCODE_TUPLE)) + else if (HAK_CNODE_IS_ELIST_CONCODED(var, HAK_CONCODE_XLIST)) { - /* no variables inside [] */ - if (enclosed) goto synerr_varname; /* [] inside [] */ + /* no variables inside () */ + if (enclosed) goto synerr_varname; /* () inside () */ goto next; } @@ -2652,10 +2652,10 @@ static int check_class_attr_list (hak_t* hak, hak_cnode_t* attr_list, unsigned i ct = HAK_OBJ_TYPE_OOP; HAK_ASSERT(hak, attr_list != HAK_NULL); - HAK_ASSERT(hak, HAK_CNODE_IS_CONS_CONCODED(attr_list, HAK_CONCODE_XLIST) || - HAK_CNODE_IS_ELIST_CONCODED(attr_list, HAK_CONCODE_XLIST)); + HAK_ASSERT(hak, HAK_CNODE_IS_CONS_CONCODED(attr_list, HAK_CONCODE_TUPLE) || + HAK_CNODE_IS_ELIST_CONCODED(attr_list, HAK_CONCODE_TUPLE)); - if (HAK_CNODE_IS_ELIST_CONCODED(attr_list, HAK_CONCODE_XLIST)) + if (HAK_CNODE_IS_ELIST_CONCODED(attr_list, HAK_CONCODE_TUPLE)) { /* don't allow empty attribute list */ if (class_name) @@ -2676,7 +2676,7 @@ static int check_class_attr_list (hak_t* hak, hak_cnode_t* attr_list, unsigned i return -1; } - if (HAK_CNODE_IS_CONS_CONCODED(attr_list, HAK_CONCODE_XLIST)) + if (HAK_CNODE_IS_CONS_CONCODED(attr_list, HAK_CONCODE_TUPLE)) { hak_cnode_t* c; const hak_ooch_t* tokptr; @@ -2759,30 +2759,23 @@ static int check_class_attr_list (hak_t* hak, hak_cnode_t* attr_list, unsigned i } /* - (class A - [ x y ] ## instance variables - :: | x y z | ## class variables <--- how to initialize the class variables??? - - ## everything inside class after the variable declarations are normal expressions. - ## however, the resolution of some variables will fall under the enclosing class. - (set x 20) - (printf "normal statement ....\n"); - - (fun new (a b c) -(printf "%O\n" self) ; self is A - (set obj super.new) - (obj.init a b c) - ;(obj.x 10) - ;(obj.y 20) - (return obj) - ) - ) - - (class B :: A ; A is a parent class - | p q | - .... - ) + class[#attr1 #attr2] Name: SuperclassName (ivar1 ivar2 (cvar1) ivar3) { + cvar1 := 20 + fun[#ci] new(a b c) { + self.ivar1 := a + ivar2 := b + ivar3 := (self.cvar1 * 2) + } + } + class Name(ivar1 ivar2 (cvar1) ivar3) { + cvar1 := 20 + fun[#ci] new(a b c) { + self.ivar1 := a + ivar2 := b + ivar3 := (self.cvar1 * 2) + } + } */ static int compile_class (hak_t* hak, hak_cnode_t* src) @@ -2807,9 +2800,10 @@ static int compile_class (hak_t* hak, hak_cnode_t* src) { HAK_ASSERT(hak, HAK_CNODE_IS_CONS(obj)); + /* class[#b] .... */ tmp = HAK_CNODE_CONS_CAR(obj); - if (HAK_CNODE_IS_ELIST_CONCODED(tmp, HAK_CONCODE_XLIST) || - HAK_CNODE_IS_CONS_CONCODED(tmp, HAK_CONCODE_XLIST)) + if (HAK_CNODE_IS_ELIST_CONCODED(tmp, HAK_CONCODE_TUPLE) || + HAK_CNODE_IS_CONS_CONCODED(tmp, HAK_CONCODE_TUPLE)) { attr_list = tmp; obj = HAK_CNODE_CONS_CDR(obj); @@ -2984,13 +2978,13 @@ static HAK_INLINE int compile_class_p1 (hak_t* hak) if (obj && HAK_CNODE_IS_CONS(obj)) { /* class-level variables - instance variables and class variable - * - class X [ a b c [d e] x ] { ... } + * - class X ( a b c (d e) x ) { ... } * - a b c are instance variables. * - d e, enclsoed in another [], are class variables. * */ hak_cnode_t* tmp; tmp = HAK_CNODE_CONS_CAR(obj); - if (HAK_CNODE_IS_CONS_CONCODED(tmp, HAK_CONCODE_TUPLE)) + if (HAK_CNODE_IS_CONS_CONCODED(tmp, HAK_CONCODE_XLIST)) { if (collect_vardcl_for_class(hak, obj, &obj, &vardcl) <= -1) return -1; } @@ -3150,10 +3144,10 @@ static int check_fun_attr_list (hak_t* hak, hak_cnode_t* attr_list, unsigned int ft = FUN_IM; HAK_ASSERT(hak, attr_list != HAK_NULL); - HAK_ASSERT(hak, HAK_CNODE_IS_CONS_CONCODED(attr_list, HAK_CONCODE_XLIST) || - HAK_CNODE_IS_ELIST_CONCODED(attr_list, HAK_CONCODE_XLIST)); + HAK_ASSERT(hak, HAK_CNODE_IS_CONS_CONCODED(attr_list, HAK_CONCODE_TUPLE) || + HAK_CNODE_IS_ELIST_CONCODED(attr_list, HAK_CONCODE_TUPLE)); - if (HAK_CNODE_IS_ELIST_CONCODED(attr_list, HAK_CONCODE_XLIST)) + if (HAK_CNODE_IS_ELIST_CONCODED(attr_list, HAK_CONCODE_TUPLE)) { /* don't allow empty attribute list */ if (class_name && fun_name) @@ -3183,7 +3177,7 @@ static int check_fun_attr_list (hak_t* hak, hak_cnode_t* attr_list, unsigned int return -1; } - if (HAK_CNODE_IS_CONS_CONCODED(attr_list, HAK_CONCODE_XLIST)) + if (HAK_CNODE_IS_CONS_CONCODED(attr_list, HAK_CONCODE_TUPLE)) { hak_cnode_t* c, * a; const hak_ooch_t* tokptr; @@ -3279,12 +3273,28 @@ static int compile_fun (hak_t* hak, hak_cnode_t* src) /* fun (arg..) * fun name(arg..) - * fun(#attr..) name(arg..) ## valid as class method, not valid as plain function - * fun(#attr..) (arg..) ## not valid. not attribute list for unnamed functions - * fun(#attr..) class:name(arg..) + * fun[#attr..] name(arg..) ## valid as class method, not valid as plain function + * fun[#attr..] (arg..) ## not valid. no attribute list for unnamed functions + * fun[#attr..] class:name(arg..) */ tmp = HAK_CNODE_CONS_CAR(next); + if (HAK_CNODE_IS_CONS_CONCODED(tmp, HAK_CONCODE_TUPLE) || + HAK_CNODE_IS_ELIST_CONCODED(tmp, HAK_CONCODE_TUPLE)) + { + attr_list = tmp; + next = HAK_CNODE_CONS_CDR(next); + if (!next) + { + hak_setsynerrbfmt( + hak, HAK_SYNERR_FUN, HAK_CNODE_GET_LOC(fun_name), HAK_NULL, + "no function name or arguments after attribute list for '%.*js'", + HAK_CNODE_GET_TOKLEN(cmd), HAK_CNODE_GET_TOKPTR(cmd)); + return -1; + } + tmp = HAK_CNODE_CONS_CAR(next); + } + if (HAK_CNODE_IS_SYMBOL(tmp)) { /* 'fun' followed by name */ @@ -3365,72 +3375,32 @@ static int compile_fun (hak_t* hak, hak_cnode_t* src) { /* 'fun' followed by attribute or argument list */ arg_list = tmp; - if (fun_name) + /* argument list + * fun class:name() + * fun name () + * fun () + * ^ */ + next = HAK_CNODE_CONS_CDR(next); /* point past argument list */ + if (!next) { - /* argument list for sure - * fun class:name() - * fun name () - * ^ */ - next = HAK_CNODE_CONS_CDR(next); /* point past argument list */ - if (!next) + if (fun_name) { hak_setsynerrbfmt( hak, HAK_SYNERR_FUN, HAK_CNODE_GET_LOC(cmd), HAK_NULL, "no function body after argument list of function '%.*js' for '%.*js'", HAK_CNODE_GET_TOKLEN(fun_name), HAK_CNODE_GET_TOKPTR(fun_name), HAK_CNODE_GET_TOKLEN(cmd), HAK_CNODE_GET_TOKPTR(cmd)); - return -1; } - fun_body = next; - } - else - { - /* not clear if it is attribute list or argument list */ - next = HAK_CNODE_CONS_CDR(next); /* point past attribute/argument list */ - if (!next) + else { - /* 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? */ hak_setsynerrbfmt( hak, HAK_SYNERR_FUN, HAK_CNODE_GET_LOC(cmd), HAK_NULL, "unnamed function not followed by function body for '%.*js'", HAK_CNODE_GET_TOKLEN(cmd), HAK_CNODE_GET_TOKPTR(cmd)); - return -1; - } - - tmp = HAK_CNODE_CONS_CAR(next); - if (HAK_CNODE_IS_SYMBOL(tmp)) - { - /* it is attribute list for sure. fun(#attr..) name */ - attr_list = arg_list; - arg_list = HAK_NULL; - goto fun_got_name; - } - else if (HAK_CNODE_IS_CONS_CONCODED(tmp, HAK_CONCODE_XLIST) || - HAK_CNODE_IS_ELIST_CONCODED(tmp, HAK_CONCODE_XLIST)) - { - /* fun(#attr..) (arg..) .. */ - attr_list = arg_list; - arg_list = tmp; - - next = HAK_CNODE_CONS_CDR(next); /* point past argument list */ - if (!next) - { - hak_setsynerrbfmt( - hak, HAK_SYNERR_FUN, HAK_CNODE_GET_LOC(cmd), HAK_NULL, - "no function body after attribute list and argument list of unnamed function for '%.*js'", - HAK_CNODE_GET_TOKLEN(cmd), HAK_CNODE_GET_TOKPTR(cmd)); - return -1; - } - fun_body = next; - } - else - { - /* fun(arg..) .. */ - fun_body = next; } + return -1; } + fun_body = next; if (src->cn_llvl >= 2 && is_in_class_init_scope_but_not_at_llvl(hak, src->cn_llvl - 2)) { diff --git a/lib/read.c b/lib/read.c index 282ef3c..fec93e5 100644 --- a/lib/read.c +++ b/lib/read.c @@ -1553,7 +1553,6 @@ static int feed_process_token (hak_t* hak) int oldflagv; frd->expect_vlist_item = 0; frd->obj = leave_list(hak, &frd->list_loc, &frd->flagv, &oldflagv); - if (HAK_LIKELY(frd->obj)) frd->obj->cn_llvl = frd->level; frd->level--; frd->flagv |= AT_BEGINNING; list_loc = &frd->list_loc; @@ -1787,7 +1786,6 @@ static int feed_process_token (hak_t* hak) #endif frd->obj = leave_list(hak, &frd->list_loc, &frd->flagv, &oldflagv); - if (HAK_LIKELY(frd->obj)) frd->obj->cn_llvl = frd->level; /* list level */ frd->level--; frd->flagv |= AT_BEGINNING; /* the current one is over. move on the beginning for the next expression */ list_loc = &frd->list_loc; diff --git a/t/class-5001.err b/t/class-5001.err index c09da1e..3e116dc 100644 --- a/t/class-5001.err +++ b/t/class-5001.err @@ -58,16 +58,36 @@ class a: #(1 2) { ##ERROR: syntax error - no valid superclass name after ':' for J := 11 class B { if (== J 10) { - fun(#ci) newA() { + fun[#ci] newA() { ##ERROR: syntax error - function 'newA' defined with 'fun' prohibited in class initialziation context return self } } else { - fun(#ci) newB() { + fun[#ci] newB() { return self } } } +##t2 := (B:newB) +##t1 := (B:newA) ##error: exception not handled - "unable to send newA to B - 'newA' not found in B" + +--- + +class B { + +} + +J := 11 +if (== J 10) { + fun[#ci] B:newA() { + return self + } +} else { + fun[#ci] B:newB() { + return self + } +} + t2 := (B:newB) t1 := (B:newA) ##ERROR: exception not handled - "unable to send newA to B - 'newA' not found in B" @@ -87,7 +107,7 @@ class B { class X: B { var a b - fun(#ci) new(t) { + fun[#ci] new(t) { | a | set self.a t; set a 100; @@ -109,11 +129,11 @@ class X: B { --- class X { - fun(#ci) xxx() { + fun[#ci] xxx() { return X; } - fun(#ci) qqq() { + fun[#ci] qqq() { return "hello" } @@ -124,10 +144,10 @@ class X { --- class X { - fun(#ci) xxx() { + fun[#ci] xxx() { return X; } - fun(#ci) qqq() { + fun[#ci] qqq() { return "hello" } } @@ -152,7 +172,7 @@ fun X:xxx() { ##ERROR: exception not handled - "not class" ## and the clase instantiation method can't specify the size ## you can't place an item in the arrya at all. -fun(#ci) 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" printf "%O" self return self @@ -163,7 +183,7 @@ Array:boom class X { var a b c - fun(#ci) new () { + fun[#ci] new () { self.a := 20 return self } @@ -243,7 +263,7 @@ class a { class X10 { var x - fun(#ci) make() { x := 1234; return self; }; + fun[#ci] make() { x := 1234; return self; }; fun get-x() { return x }; } @@ -260,44 +280,44 @@ class String { ##ERROR: exception not handled - "incompatible redefintion of Str --- -class() { ##ERROR: syntax error - empty attribute list on unnamed class for 'class' +class[] { ##ERROR: syntax error - empty attribute list on unnamed class for 'class' } --- -class() Kuduro { ##ERROR: syntax error - empty attribute list on 'Kuduro' for 'class' +class[] Kuduro { ##ERROR: syntax error - empty attribute list on 'Kuduro' for 'class' } --- -class(#byte #limited #char) Kuduro { ##ERROR: syntax error - conflicting or duplicate class attribute name '#char' +class[#byte #limited #char] Kuduro { ##ERROR: syntax error - conflicting or duplicate class attribute name '#char' } --- -class(#byte #limited #final #limited) Kuduro { ##ERROR: syntax error - conflicting or duplicate class attribute name '#limited' +class[#byte #limited #final #limited] Kuduro { ##ERROR: syntax error - conflicting or duplicate class attribute name '#limited' } --- -class(#byte #bytes) Kuduro { ##ERROR: syntax error - unrecognized class attribute name '#bytes' +class[#byte #bytes] Kuduro { ##ERROR: syntax error - unrecognized class attribute name '#bytes' } --- -class Kuduro [a b c] { +class Kuduro (a b c) { var d e var a ##ERROR: syntax error - duplicate instance variable name 'a' } --- -class Kuduro [a [b] c] { +class Kuduro (a (b) c) { var d e var b ##ERROR: syntax error - duplicate instance variable name 'b' } --- -class Kuduro [a [b] c] { +class Kuduro (a (b) c) { var d e var(#class) b ##ERROR: syntax error - duplicate class variable name 'b' } diff --git a/t/fun-01.hak b/t/fun-01.hak index 31538f4..0a16686 100644 --- a/t/fun-01.hak +++ b/t/fun-01.hak @@ -98,7 +98,7 @@ if (== y 29) { class A { var a b c - fun(#ci) newInstance(x y z) { + fun[#ci] newInstance(x y z) { set a x set b y set c z diff --git a/t/insta-01.hak b/t/insta-01.hak index fe49175..93e0a17 100644 --- a/t/insta-01.hak +++ b/t/insta-01.hak @@ -15,7 +15,7 @@ fun Number: ~= (oprnd) { return (~= self oprnd) } class A { var a b c - fun(#ci) newInstance(x y z) { + fun[#ci] newInstance(x y z) { set a x; set b y; set c z; @@ -30,7 +30,7 @@ class A { class B: A { var d e f - fun(#ci) newInstance(x y z) { + fun[#ci] newInstance(x y z) { super:newInstance (* x 2) (* y 2) (* z 2); set d x; set e y; @@ -38,9 +38,9 @@ class B: A { return self; }; - fun(#c) getSuper() { return super; }; - ###fun(#c) getSuperclass() { return (self:superclass); }; - fun(#c) getSelf() { return self; }; + fun[#c] getSuper() { return super; }; + ###fun[#c] getSuperclass() { return (self:superclass); }; + fun[#c] getSelf() { return self; }; fun sum() { return (+ (super:get-a) (super:get-b) (super:get-c) self.d self.e self.f); diff --git a/t/insta-02.hak b/t/insta-02.hak index 1bbabf3..9e8c916 100644 --- a/t/insta-02.hak +++ b/t/insta-02.hak @@ -13,7 +13,7 @@ fun Number: ~= (oprnd) { return (~= self oprnd) } set t ( class { var x - fun(#ci) make() { x := 1234; return self; }; + fun[#ci] make() { x := 1234; return self; }; fun get-x() { return x }; } ); @@ -43,7 +43,7 @@ else { printf "OK: value is %d\n" v }; class X0 { var a b c d - fun(#ci) new() { + fun[#ci] new() { return self; } @@ -72,7 +72,7 @@ else { printf "OK: value is %d\n" v } class X1 { var a b c - fun(#classinst) new () { + fun[#classinst] new () { self.a := 20 return self } @@ -115,11 +115,11 @@ class F { class X2 { var a b c - fun(#classinst) new () { + fun[#classinst] new () { | j | self.a := 20 j := (self.a * 2) - fun(#class) F:get_x() { return (j * j) } + fun[#class] F:get_x() { return (j * j) } return self } } @@ -131,7 +131,7 @@ else { printf "OK: value is %d\n" v } ## -------------------------------------------------------------- class X3 { - fun(#ci) new (a b) { + fun[#ci] new (a b) { fun X3:sum() { return (fun(j) { return (j + (a + b)) }) } return self; } @@ -143,15 +143,15 @@ else { printf "OK: value is %d\n" v } ## -------------------------------------------------------------- class X4 { - fun(#class) t() { + fun[#class] t() { | X5 | class X5 { ## this X5 isn't the local variable X4 - fun(#class) t() { + fun[#class] t() { X6 := (class { - fun(#class) t() { + fun[#class] t() { | X7 | X7 := (class { ## this X4 is the local variable X4 - fun(#class) t() { return 60 } + fun[#class] t() { return 60 } }) return 40 } @@ -186,7 +186,7 @@ else { printf "OK: value is %d\n" v } ## -------------------------------------------------------------- class X10 { var x - fun(#ci) make() { x := 1234; return self; }; + fun[#ci] make() { x := 1234; return self; }; fun get-x() { return x }; } diff --git a/t/retvar-01.hak b/t/retvar-01.hak index 25881ea..483d255 100644 --- a/t/retvar-01.hak +++ b/t/retvar-01.hak @@ -37,12 +37,12 @@ set X1 999; set X2 888; - fun(#class) get ( :: x y) { + fun[#class] get ( :: x y) { set x X1; set y X2; }; - fun(#class) get2 (inc :: x y) { + fun[#class] get2 (inc :: x y) { set x (+ X1 inc); set y (+ X2 inc); }; @@ -63,9 +63,9 @@ class X { var x y - fun(#class) f(a :: b c) { b := (+ a 10); c := (+ a 20) } + fun[#class] f(a :: b c) { b := (+ a 10); c := (+ a 20) } - fun(#classinst) new(z) { + fun[#classinst] new(z) { ## multi-variable assignment with return variables to member variables [self.x, self.y] := (X:f z) return self; diff --git a/t/var-01.hak b/t/var-01.hak index 4f1c85e..5dc6c85 100644 --- a/t/var-01.hak +++ b/t/var-01.hak @@ -59,7 +59,7 @@ x class T { var j - fun(#classinst) new() { + fun[#classinst] new() { set j 99 return self } diff --git a/t/var-5001.err b/t/var-5001.err index d8ecab0..3e28def 100644 --- a/t/var-5001.err +++ b/t/var-5001.err @@ -1,5 +1,5 @@ -class A [ a ] { - fun(#ci) init1() { +class A ( a ) { + fun[#ci] init1() { | b | set b (+ 1 2); set a b; @@ -15,7 +15,7 @@ class A [ a ] { printf ">>> %d\n" j; } - fun(#ci) init2() { + fun[#ci] init2() { | b | set b (+ 10 20); set a b; @@ -31,24 +31,28 @@ fun String length() { ##ERROR: syntax error - 'String' not followed by ( but fol --- -class A [ 10 ] { ##ERROR: syntax error - not variable name '10' +class A ( 10 ) { ##ERROR: syntax error - not variable name '10' } --- -class A [ a := 20 ] { ##ERROR: syntax error - := disallowed +class A ( a := 20 ) { ##ERROR: syntax error - block expression expected as 'class' body } --- -class A [ [ [a] ] ] { ##ERROR: syntax error - not variable name + +class A ( ( (a) ) ) { ##ERROR: syntax error - not variable name } --- -class A [ a + ] { ##ERROR: syntax error - not variable name '+' + +## TODO: improve the reader to be aware that it's in the class definition context +## while reading '(a + )' and to flag + as an invalid variable name... +class A ( a + ) { ##ERROR: syntax error - no operand after binary selector '+' } --- -class A [ + ] { ##ERROR: syntax error - not variable name '+' +class A ( + ) { ##ERROR: syntax error - not variable name '+' } --- diff --git a/t/var-5004.err b/t/var-5004.err index 9caf046..1ac72e0 100644 --- a/t/var-5004.err +++ b/t/var-5004.err @@ -79,22 +79,22 @@ fun fun fun1() { ##ERROR: syntax error - invalid function name 'fun' for 'fun' --- -fun(#ci) fun1() { ##ERROR: syntax error - attribute list prohibited on plain function 'fun1' +fun[#ci] fun1() { ##ERROR: syntax error - attribute list prohibited on plain function 'fun1' } --- -fun() () { ##ERROR: syntax error - attribute list prohibited on unnamed function for 'fun' +fun[] () { ##ERROR: syntax error - attribute list prohibited on unnamed function for 'fun' } --- -fun() X:y() { ##ERROR: syntax error - empty attribute list on 'X:y' for 'fun' +fun[] X:y() { ##ERROR: syntax error - empty attribute list on 'X:y' for 'fun' } --- class X { - fun() y() { ##ERROR: syntax error - empty attribute list on 'y' for 'fun' + fun[] y() { ##ERROR: syntax error - empty attribute list on 'y' for 'fun' } }