enhancing the compiler to handle 'var' in the class scope. unneeded code to be removed asap
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
hyung-hwan 2024-10-19 02:31:54 +09:00
parent 3c88ada3bf
commit f2479c55cd
12 changed files with 225 additions and 55 deletions

View File

@ -241,6 +241,44 @@ static void kill_temporary_variable_at_offset (hcl_t* hcl, hcl_oow_t offset)
hcl->c->tv.s.ptr[offset] = '('; /* HACK!! put a special character which can't form a variable name */
}
static int init_class_level_variable_buffer (hcl_t* hcl, hcl_oocsc_t* dst)
{
hcl_ooch_t* tmp;
tmp = (hcl_ooch_t*)hcl_allocmem(hcl, 1 * HCL_SIZEOF(*dst->ptr));
if (HCL_UNLIKELY(!tmp)) return -1;
dst->ptr = tmp;
dst->len = 0;
dst->capa = 0;
return 0;
}
static void fini_class_level_variable_buffer (hcl_t* hcl, hcl_oocsc_t* dst)
{
if (dst->ptr)
{
hcl_freemem (hcl, dst->ptr);
dst->ptr = HCL_NULL;
dst->len = 0;
dst->capa = 0;
}
}
static int add_class_level_variable (hcl_t* hcl, hcl_oocsc_t* dst, const hcl_oocs_t* name)
{
/* it downcasts hcl_oocsc_t* to hcl_oocs_t*. take extra care to keep their type defintion
* compatible for downcasting in hcl-cmn.h */
if (__find_word_in_string((hcl_oocs_t*)dst, name, 0, HCL_NULL) >= 0)
{
hcl_seterrnum (hcl, HCL_EEXIST);
return -1;
}
return hcl_copy_string_to(hcl, name, (hcl_oocs_t*)dst, &dst->capa, 1, ' ');
}
static int is_in_top_scope (hcl_t* hcl)
{
hcl_funblk_info_t* fbi;
@ -317,10 +355,15 @@ static int find_variable_backward_with_word (hcl_t* hcl, const hcl_oocs_t* name,
#endif
cbi = &hcl->c->clsblk.info[fbi->clsblk_top];
#if 0
if (cbi->ivars_str)
{
haystack.ptr = cbi->ivars_str;
haystack.len = hcl_count_oocstr(cbi->ivars_str);
#else
haystack.ptr = cbi->ivars.ptr;
haystack.len = cbi->ivars.len;
#endif
if (__find_word_in_string(&haystack, name, 1, &index) >= 0)
{
hcl_oow_t fi;
@ -356,12 +399,19 @@ HCL_INFO6 (hcl, "FOUND INST VAR [%.*js]...[%.*js]................ ===> ctx_offse
*/
return 1;
}
#if 0
}
#endif
#if 0
if (cbi->cvars_str)
{
haystack.ptr = cbi->cvars_str;
haystack.len = hcl_count_oocstr(cbi->cvars_str);
#else
haystack.ptr = cbi->cvars.ptr;
haystack.len = cbi->cvars.len;
#endif
if (__find_word_in_string(&haystack, name, 1, &index) >= 0)
{
/* TODO: VAR_CLASS_CM vs VAR_CLASS_IM, need to know if it's an instance method or a class method */
@ -375,7 +425,9 @@ HCL_INFO6 (hcl, "FOUND CLASS VAR [%.*js]...[%.*js]................ ===> ctx_offs
*/
return 1;
}
#if 0
}
#endif
#if 0
}
@ -712,11 +764,11 @@ static int emit_single_param_instruction (hcl_t* hcl, int cmd, hcl_oow_t param_1
hcl_seterrbfmt (hcl, HCL_EINVAL, "unhandled single-parameter instruction %u", (unsigned int)cmd);
return -1;
write_short:
write_short: /* short parameter */
if (emit_byte_instruction(hcl, bc, srcloc) <= -1) return -1;
return 0;
write_long:
write_long: /* long parameter */
if (param_1 > MAX_CODE_PARAM)
{
hcl_seterrbfmt (hcl, HCL_ERANGE, "parameter too large to single-parameter instruction %u", (unsigned int)cmd);
@ -732,7 +784,7 @@ write_long:
#endif
return 0;
write_long2:
write_long2: /* double-long parameter */
if (param_1 > MAX_CODE_PARAM2)
{
hcl_seterrbfmt (hcl, HCL_ERANGE, "parameter too large to single-parameter instruction %u", (unsigned int)cmd);
@ -1071,12 +1123,9 @@ static int push_clsblk (
ci->nivars = nivars;
ci->ncvars = ncvars;
#if 0
XXXXXXXXXXXXXXXXXX
/* TODO: ... */
ci->ivars.
ci->cvars = hcl_
#endif
if (init_class_level_variable_buffer(hcl, &ci->ivars) <= -1) return -1;
if (init_class_level_variable_buffer(hcl, &ci->cvars) <= -1) return -1;
if (nivars > 0)
{
HCL_ASSERT (hcl, ivars_str != HCL_NULL);
@ -1139,6 +1188,9 @@ static void pop_clsblk (hcl_t* hcl)
hcl_freemem (hcl, cbi->ivars_str);
cbi->ivars_str = HCL_NULL;
}
fini_class_level_variable_buffer (hcl, &cbi->ivars);
fini_class_level_variable_buffer (hcl, &cbi->cvars);
hcl->c->clsblk.depth--;
}
@ -2247,7 +2299,6 @@ static int compile_expression_block (hcl_t* hcl, hcl_cnode_t* src, const hcl_bch
cf = GET_SUBCFRAME(hcl);
cf->u.post_do.lvar_start = tvslen;
cf->u.post_do.lvar_end = fbi->tmprlen;
hcl_logbfmt(hcl, HCL_LOG_STDERR, "tvslen=>%d fbi->tmprlen=>%d\n", (int)tvslen, (int)fbi->tmprlen);
return 0;
}
@ -2903,6 +2954,12 @@ static HCL_INLINE int compile_class_p1 (hcl_t* hcl)
if (HCL_UNLIKELY(!tmp)) goto oops;
if (emit_push_literal(hcl, tmp, &cf->u._class.start_loc) <= -1) goto oops;
}
else
{
/* TODO: remove the if part */
/* emit a placeholder instruction to be patched in compile_class_p2() */
if (emit_single_param_instruction(hcl, HCL_CODE_PUSH_LITERAL_0, MAX_CODE_PARAM2, &cf->u._class.start_loc) <= -1) return -1;
}
if (vardcl.ncvars > 0)
{
@ -2923,6 +2980,12 @@ static HCL_INLINE int compile_class_p1 (hcl_t* hcl)
if (HCL_UNLIKELY(!tmp)) goto oops;
if (emit_push_literal(hcl, tmp, &cf->u._class.start_loc) <= -1) goto oops;
}
else
{
/* TODO: remove the if part */
/* emit a placeholder instruction to be patched in compile_class_p2() */
if (emit_single_param_instruction(hcl, HCL_CODE_PUSH_LITERAL_0, MAX_CODE_PARAM2, &cf->u._class.start_loc) <= -1) return -1;
}
if (check_block_expression_as_body(hcl, obj, cf->u._class.cmd_cnode, FOR_CLASS) <= -1) return -1;
@ -2937,6 +3000,9 @@ static HCL_INLINE int compile_class_p1 (hcl_t* hcl)
hcl->c->tv.s.len = saved_tv_slen;
hcl->c->tv.wcount = saved_tv_wcount;
/* the position of the CLASS_ENTER instruction */
hcl->c->clsblk.info[hcl->c->clsblk.depth].class_enter_inst_pos = hcl->code.bc.len;
/* class_enter nsuperclasses, nivars, ncvars */
if (emit_byte_instruction(hcl, HCL_CODE_CLASS_ENTER, &cf->u._class.start_loc) <= -1) goto oops;
if (emit_long_param(hcl, cf->u._class.nsuperclasses) <= -1) goto oops;
@ -2980,7 +3046,60 @@ static HCL_INLINE int compile_class_p2 (hcl_t* hcl)
}
cbi = &hcl->c->clsblk.info[hcl->c->clsblk.depth];
/* TODO: PATCH THE CLASS_ENTER instruction */
if (cbi->class_enter_inst_pos)
{
/* patch the CLASS_ENTER instruction with the final nicvars and ncvars values.
* CLASS_ENTER nsuperclasses(lp)|nivars(lp)|ncvars(lp)|spec/selfspec(b)|index_type(b)
* (lp) = long param, (b) = byte */
hcl_oow_t patch_pos, patch_end;
patch_pos = cbi->class_enter_inst_pos + 1;
patch_pos += HCL_CODE_LONG_PARAM_SIZE; /* skip nsuperclasses */
patch_long_param (hcl, patch_pos, cbi->nivars);
patch_pos += HCL_CODE_LONG_PARAM_SIZE; /* skip nivars */
patch_long_param (hcl, patch_pos, cbi->ncvars);
patch_pos = cbi->class_enter_inst_pos - (HCL_CODE_LONG_PARAM_SIZE * 4 + 1);
if (cbi->nivars > 0)
{
/* patch the PUSH_LITERAL instruction for ivars */
/* TODO: reduce space waste for fixed double-long param */
hcl_oop_t obj;
hcl_oow_t index;
obj = hcl_makestring(hcl, cbi->ivars.ptr, cbi->ivars.len);
if (HCL_UNLIKELY(!obj)) return -1;
if (add_literal(hcl, obj, &index) <= -1) return -1;
patch_double_long_params_with_oow(hcl, patch_pos, index);
}
else
{
/* TODO: reduce space waste for patched NOOP */
patch_end = (--patch_pos) + (HCL_CODE_LONG_PARAM_SIZE * 2) + 1;
for (; patch_pos < patch_end; patch_pos++)
patch_instruction (hcl, patch_pos, HCL_CODE_NOOP);
}
patch_pos = cbi->class_enter_inst_pos - (HCL_CODE_LONG_PARAM_SIZE * 2);
if (cbi->ncvars > 0)
{
/* patch the PUSH_LITERAL instruction for cvars */
/* TODO: reduce space waste for fixed double-long param */
hcl_oop_t obj;
hcl_oow_t index;
obj = hcl_makestring(hcl, cbi->cvars.ptr, cbi->cvars.len);
if (HCL_UNLIKELY(!obj)) return -1;
if (add_literal(hcl, obj, &index) <= -1) return -1;
patch_double_long_params_with_oow(hcl, patch_pos, index);
}
else
{
/* TODO: reduce space waste for patched NOOP */
patch_end = (--patch_pos) + (HCL_CODE_LONG_PARAM_SIZE * 2) + 1;
HCL_ASSERT (hcl, patch_end == cbi->class_enter_inst_pos);
for (;patch_pos < patch_end; patch_pos++)
patch_instruction (hcl, patch_pos, HCL_CODE_NOOP);
}
}
pop_ctlblk (hcl);
pop_clsblk (hcl); /* end of the class block */
@ -3647,7 +3766,7 @@ static int check_var_attr_list (hcl_t* hcl, hcl_cnode_t* attr_list, unsigned int
if (hcl_comp_oochars_bcstr(tokptr, toklen, "class") == 0 ||
hcl_comp_oochars_bcstr(tokptr, toklen, "c") == 0)
{
if (ft != FUN_IM)
if (ft != VAR_INST)
{
conflicting:
hcl_setsynerrbfmt (
@ -3735,27 +3854,24 @@ static int compile_var (hcl_t* hcl, hcl_cnode_t* src)
if (HCL_CNODE_IS_SYMBOL_IDENT(tmp))
{
unsigned int var_type;
unsigned int var_type = VAR_INST;
if (attr_list && check_var_attr_list(hcl, attr_list, &var_type, cmd, cbi->class_name, tmp) <= -1) return -1;
HCL_ASSERT (hcl, var_type == VAR_INST || var_type == VAR_CLASS_I);
while (1)
{
/* TODO: do something here */
hcl_logbfmt(hcl, HCL_LOG_STDERR, "VAR=[%.*js]\n", HCL_CNODE_GET_TOKLEN(tmp), HCL_CNODE_GET_TOKPTR(tmp));
if (var_type == VAR_INST)
{
if (add_class_level_variable(hcl, &cbi->ivars, HCL_CNODE_GET_TOK(tmp)) <= -1) return -1;
cbi->nivars++;
/* TODO: update cbi->nivars_name... */
}
else
{
if (add_class_level_variable(hcl, &cbi->cvars, HCL_CNODE_GET_TOK(tmp)) <= -1) return -1;
cbi->ncvars++;
/* TODO: update cbi->ncvars_name... */
}
next = HCL_CNODE_CONS_CDR(next);
if (!next) break;
tmp = HCL_CNODE_CONS_CAR(next);
@ -3773,6 +3889,12 @@ hcl_logbfmt(hcl, HCL_LOG_STDERR, "VAR=[%.*js]\n", HCL_CNODE_GET_TOKLEN(tmp), HCL
return -1;
}
/* if there is assignment with expression, we can arragne to compile RHS. in that case
* the explicit PUSH_NIL here isn't needed */
/* TODO: hack for POP_STACKPOP generated in compile_object_list().
* remove generating this instruction after having fixed the problem in that function */
if (emit_byte_instruction(hcl, HCL_CODE_PUSH_NIL, HCL_CNODE_GET_LOC(cmd)) <= -1) return -1;
POP_CFRAME (hcl);
return 0;
}
@ -5609,7 +5731,7 @@ static int compile_object_r (hcl_t* hcl)
HCL_ASSERT (hcl, cf->opcode == COP_COMPILE_OBJECT_R);
HCL_ASSERT (hcl, cf->operand != HCL_NULL);
oprnd = cf->operand;
oprnd = cf->operand;
if (HCL_CNODE_IS_CONS(oprnd))
{
hcl_concode_t cc;
@ -5752,9 +5874,8 @@ static int compile_object_list (hcl_t* hcl)
{
/* emit POP_STACKTOP before evaluating the second objects
* and onwards. this goes above COP_COMPILE_OBJECT.*/
/* TODO: if the previous operators is known to divert execution flow, it may skip this.
* for instance, some 'RETURN' or 'JUMP' operators */
* for instance, some 'RETURN' or 'JUMP' operators or class-level variable declaration with 'var' */
PUSH_CFRAME (hcl, COP_EMIT_POP_STACKTOP, oprnd);
}
}

View File

@ -4032,7 +4032,7 @@ static int execute (hcl_t* hcl)
push superclass (only if nsuperclassses > 0)
push ivars_string
push cvars_string
class_enter indexed_type nsuperclasses nivars ncvars
class_enter nsuperclasses nivars ncvars spec/selfspec, indexed_tye
*/
hcl_oop_t superclass, ivars_str, cvars_str, class_name, v;
hcl_ooi_t expected_spec, expected_selfspec;
@ -4050,14 +4050,14 @@ static int execute (hcl_t* hcl)
if (b3 > 0)
{
HCL_STACK_POP_TO (hcl, cvars_str);
HCL_ASSERT (hcl, HCL_IS_STRING(hcl, cvars_str));
// HCL_ASSERT (hcl, HCL_IS_STRING(hcl, cvars_str));
}
else cvars_str = hcl->_nil;
if (b2 > 0)
{
HCL_STACK_POP_TO (hcl, ivars_str);
HCL_ASSERT (hcl, HCL_IS_STRING(hcl, ivars_str));
// HCL_ASSERT (hcl, HCL_IS_STRING(hcl, ivars_str));
}
else ivars_str = hcl->_nil;

View File

@ -1141,7 +1141,7 @@ void hcl_gc (hcl_t* hcl, int full)
if (!full && hcl->gci.lazy_sweep)
{
/* set the lazy sweeping pointer to the head of the allocated blocks.
* hawk_allocbytes() updates hcl->gci.ls.prev if it is called while
* hcl_allocbytes() updates hcl->gci.ls.prev if it is called while
* hcl->gci.ls.curr stays at hcl->gci.b */
hcl->gci.ls.prev = HCL_NULL;
hcl->gci.ls.curr = hcl->gci.b;

View File

@ -473,12 +473,33 @@ struct hcl_bcs_t
};
typedef struct hcl_bcs_t hcl_bcs_t;
struct hcl_ucsc_t
{
/* the first two fields 'ptr' and 'len' must match those in hcl_ucs_t
* for easy downcasting to it. */
hcl_uch_t* ptr;
hcl_oow_t len; /* length */
hcl_oow_t capa; /* capacity */
};
typedef struct hcl_ucsc_t hcl_ucsc_t;
struct hcl_bcsc_t
{
/* the first two fields 'ptr' and 'len' must match those in hcl_bcs_t
* for easy downcasting to it. */
hcl_bch_t* ptr;
hcl_oow_t len; /* length */
hcl_oow_t capa; /* capacity */
};
typedef struct hcl_bcsc_t hcl_bcsc_t;
#if defined(HCL_ENABLE_WIDE_CHAR)
typedef hcl_uch_t hcl_ooch_t;
typedef hcl_uchu_t hcl_oochu_t;
typedef hcl_uci_t hcl_ooci_t;
typedef hcl_ucu_t hcl_oocu_t;
typedef hcl_ucs_t hcl_oocs_t;
typedef hcl_ucsc_t hcl_oocsc_t;
# define HCL_OOCH_IS_UCH
# define HCL_SIZEOF_OOCH_T HCL_SIZEOF_UCH_T
#else
@ -487,6 +508,7 @@ typedef struct hcl_bcs_t hcl_bcs_t;
typedef hcl_bci_t hcl_ooci_t;
typedef hcl_bcu_t hcl_oocu_t;
typedef hcl_bcs_t hcl_oocs_t;
typedef hcl_bcsc_t hcl_oocsc_t;
# define HCL_OOCH_IS_BCH
# define HCL_SIZEOF_OOCH_T HCL_SIZEOF_BCH_T
#endif

View File

@ -741,6 +741,9 @@ struct hcl_clsblk_info_t
{
hcl_cnode_t* class_name;
hcl_oocsc_t ivars;
hcl_oocsc_t cvars;
hcl_oow_t nivars;
hcl_oow_t ncvars;
hcl_ooch_t* ivars_str;
@ -749,6 +752,7 @@ struct hcl_clsblk_info_t
hcl_ooi_t funblk_base;
hcl_ooi_t class_start_inst_pos; /* the position of the first instruction in the class body after CLASS_ENTER */
hcl_ooi_t class_enter_inst_pos; /* the position of the CLASS_ENTER instruction */
};
typedef struct hcl_clsblk_info_t hcl_clsblk_info_t;

View File

@ -91,7 +91,7 @@ enum hcl_errnum_t
HCL_EEXCEPT, /**< runtime error - exception not handled */
HCL_ESTKOVRFLW, /**< runtime error - stack overflow */
HCL_ESTKUNDFLW, /**< runtime error - stack overflow */
HCL_EUNDEFVAR /**< runtime error - undefined variable access */
HCL_EUNDEFVAR /**< runtime error - undefined variable access */
};
typedef enum hcl_errnum_t hcl_errnum_t;

View File

@ -15,13 +15,15 @@ class B + ##ERROR: syntax error - prohibited binary selector '+'
---
class A [ a ] {
| j | ##ERROR: syntax error - variable declaration disallowed in class init scope
class A {
var a
| j | ##ERROR: syntax error - variable declaration disallowed
}
---
class 10 [ a ] { ##ERROR: syntax error - invalid class name '10' for 'class'
class 10 { ##ERROR: syntax error - invalid class name '10' for 'class'
var a
}
---
@ -31,7 +33,8 @@ class class { ##ERROR: syntax error - invalid class name 'class' for 'class'
---
class super.a [ a ] { ##ERROR: syntax error - invalid class name 'super.a' for 'class'
class super.a { ##ERROR: syntax error - invalid class name 'super.a' for 'class'
var a
}
---
@ -70,18 +73,20 @@ t1 := (B:newA) ##ERROR: exception not handled - "unable to send newA to B - 'new
---
class B [ x ] {
class B {
var x
if (x > 0) { ##ERROR: syntax error - prohibited access to instance variable - x
}
}
---
class B [ x y ] {
class B {
var x y
};
class X: B [ a b ] {
class X: B {
var a b
fun(#ci) new(t) {
| a |
set self.a t;
@ -156,7 +161,8 @@ Array:boom
---
class X [ a b c ] {
class X {
var a b c
fun(#ci) new () {
self.a := 20
return self
@ -176,10 +182,12 @@ printf "%d\n" ((X:new):get_a)
---
class F [ a b c ] {
class F {
var a b c
}
class X [ a b c ] {
class X {
var a b c
fun oh() {
fun F:get_a() {
return super.a ##ERROR: syntax error - not allowed to prefix with super
@ -233,7 +241,8 @@ class a {
---
class X10 [ x ] {
class X10 {
var x
fun(#ci) make() { x := 1234; return self; };
fun get-x() { return x };
}

View File

@ -96,7 +96,8 @@ if (== y 29) {
## --------------------------------------
class A [ a b c ] {
class A {
var a b c
fun(#ci) newInstance(x y z) {
set a x
set b y

View File

@ -12,7 +12,8 @@ fun Number: <= (oprnd) { return (<= self oprnd) }
fun Number: == (oprnd) { return (== self oprnd) }
fun Number: ~= (oprnd) { return (~= self oprnd) }
class A [ a b c ] {
class A {
var a b c
fun(#ci) newInstance(x y z) {
set a x;
@ -26,7 +27,8 @@ class A [ a b c ] {
fun get-c() { return self.c; };
};
class B: A [ d e f ] {
class B: A {
var d e f
fun(#ci) newInstance(x y z) {
super:newInstance (* x 2) (* y 2) (* z 2);

View File

@ -11,7 +11,8 @@ fun Number: ~= (oprnd) { return (~= self oprnd) }
## --------------------------------------------------------------
set t (
class [ x ] {
class {
var x
fun(#ci) make() { x := 1234; return self; };
fun get-x() { return x };
}
@ -40,16 +41,18 @@ else { printf "OK: value is %d\n" v };
## --------------------------------------------------------------
class X0 [ a b c d ] {
fun(#ci) new() {
return self;
}
class X0 {
var a b c d
fun(#ci) new() {
return self;
}
fun x() {
fun x() {
a := 20 ; self.b:=(a + 10); c := (b + 20)
printf "%d %d %d\n" self.a self.b self.c
return (+ self.a self.b self.c)
}
}
fun y() {
self.d := (fun(k) {
return (k + 1)
@ -67,7 +70,8 @@ else { printf "OK: value is %d\n" v }
## --------------------------------------------------------------
class X1 [ a b c ] {
class X1 {
var a b c
fun(#classinst) new () {
self.a := 20
return self
@ -105,10 +109,12 @@ else { printf "OK: value is %d\n" v }
## --------------------------------------------------------------
class F [ j t ] {
class F {
var j t
}
class X2 [ a b c ] {
class X2 {
var a b c
fun(#classinst) new () {
| j |
self.a := 20
@ -178,7 +184,8 @@ if (nqv? v 50) { printf "ERROR: v is not 50 - %d\n" v } \
else { printf "OK: value is %d\n" v }
## --------------------------------------------------------------
class X10 [ x ] {
class X10 {
var x
fun(#ci) make() { x := 1234; return self; };
fun get-x() { return x };
}

View File

@ -31,7 +31,8 @@
## test return variables in message sends
class B [ [X1 X2] ] {
class B {
var(#class) X1 X2
set X1 999;
set X2 888;
@ -59,7 +60,9 @@
if (~= d 788) { printf "ERROR: d must be 788\n" } \
else { printf "OK: d=%d\n" d }
class X [ x, y ] {
class X {
var x y
fun(#class) f(a :: b c) { b := (+ a 10); c := (+ a 20) }
fun(#classinst) new(z) {

View File

@ -56,7 +56,8 @@ fun x () {
x
class T [ j ] {
class T {
var j
fun(#classinst) new() {
set j 99