]> Nishi Git Mirror - gwion.git/commitdiff
:art: Improve ctors
authorfennecdjay <fennecdjay@gmail.com>
Sun, 23 Oct 2022 22:35:00 +0000 (00:35 +0200)
committerfennecdjay <fennecdjay@gmail.com>
Sun, 23 Oct 2022 22:35:00 +0000 (00:35 +0200)
include/emit.h
include/parse.h
src/emit/emit.c
src/env/value.c
src/lib/deep_equal.c
src/lib/object_op.c
src/parse/check.c
src/parse/scan1.c
src/vm/vm.c

index 942f67d4205bb7df379e78c4f7a5e4067893d5d7..32fdd69205073c8f87f389d432a7838a98c0264c 100644 (file)
@@ -95,16 +95,6 @@ ANN static inline Instr emit_compound_addref(const Emitter emit, const Type t,
                                  : emit_struct_addref(emit, t, size, emit_var);
 }
 
-ANN static inline bool is_static_call(const Emitter emit, const Exp e) {
-  if (e->exp_type != ae_exp_dot) return true;
-  const Exp_Dot *member = &e->d.exp_dot;
-  return GET_FLAG(e->type, final) ||
-         GET_FLAG(member->base->type, final) ||
-         is_class(emit->gwion, member->base->type) ||
-//         GET_FLAG(e->type->info->func, static) ||
-         member->base->exp_type == ae_exp_cast;
-}
-
 ANN Instr emit_kind(Emitter, const m_uint size, const bool addr,
                     const f_instr func[]);
 ANN Instr emit_regpushimm(Emitter, const m_uint, const bool);
index bc2964aa16d444ded95d42d89f9462a5449871d6..1041c2652494341ed7b31ee6fcaf33a6a97a123a 100644 (file)
@@ -123,4 +123,14 @@ ANN static inline bool not_upvalue(const Env env, const Value v) {
 }
 
 ANN m_bool abstract_array(const Env env, const Array_Sub array);
+
+ANN static inline bool is_static_call(const Gwion gwion, const Exp e) {
+  if (e->exp_type != ae_exp_dot) return true;
+  const Exp_Dot *member = &e->d.exp_dot;
+  if(unlikely(!strcmp(s_name(member->xid), "new"))) return true;
+  return GET_FLAG(e->type, final) ||
+         GET_FLAG(member->base->type, final) ||
+         is_class(gwion, member->base->type) ||
+         member->base->exp_type == ae_exp_cast;
+}
 #endif
index f0f8883eda11e20ed67f64ef6b6165814c2c4629..a3d78adee9fec711eb7e7ed6d16baf93b8c82f43 100644 (file)
@@ -1358,7 +1358,7 @@ ANN static m_bool _emit_exp_call(const Emitter emit, const Exp_Call *exp_call) {
     CHECK_BB(emit_func_args(emit, exp_call));
   if (is_func(emit->gwion, t)) // is_callable needs type
     CHECK_BB(emit_exp_call1(emit, t->info->func,
-                            is_static_call(emit, exp_call->func)));
+                            is_static_call(emit->gwion, exp_call->func)));
   else {
     struct Op_Import opi = {.op   = insert_symbol("@ctor"),
                             .rhs  = t,
@@ -1659,8 +1659,7 @@ ANN static void call_finish(const Emitter emit, const Func f,
   const m_uint offset = emit_code_offset(emit);
   if (f != emit->env->func || !is_static || strcmp(s_name(f->def->base->xid), "new"))
     regseti(emit, offset);
-  const bool _is_static = !strcmp(s_name(f->def->base->xid), "new") ? true : is_static;
-  const Instr instr   = emit_call(emit, f, _is_static);
+  const Instr instr   = emit_call(emit, f, is_static);
   instr->m_val        = f->def->base->ret_type->size;
   instr->m_val2       = offset;
 }
index ef8f41659184a8d6fa9ac68e50669daea844c8de..0c06360d5bf3e13b9c1d44aca2855626d5d35338 100644 (file)
@@ -4,7 +4,6 @@
 #include "vm.h"
 #include "gwion.h"
 
-#define MAX(a, b) (a >= b ? a : b)
 ANN void free_value(Value a, Gwion gwion) {
   const Type t = a->type;
   if (t->size > SZ_INT && !vflag(a, vflag_func) && a->d.ptr)
index 5857500e9fa6fcf4857c25647b7418acc31cc35f..343c702a6899216367f27cc40ae426c2e4dc966c 100644 (file)
@@ -212,10 +212,6 @@ ANN static bool deep_emit(const Emitter emit, struct DeepEmits *ds) {
     struct Exp_ rexp = MK_DOT(emit, ds->rhs->tmp, rhs);
     struct Exp_ temp = MK_BIN(lexp, rexp, ds->bin);
     temp.type=emit->gwion->type[et_bool];
-    if(tflag(lexp.type, tflag_struct))
-      exp_setvar(&lexp, true);
-    if(tflag(rexp.type, tflag_struct))
-      exp_setvar(&rexp, true);
     if(emit_exp(emit, &temp) < 0) return false;
     vector_add(&ds->acc, (m_uint)emit_add_instr(emit, BranchEqInt));
   }
index bb9b219fbc528b86aceeca379ca1829b48bdf22c..a42dad6bc4cbdc32122cfe519af51282f982c151 100644 (file)
@@ -1,3 +1,4 @@
+
 #include "gwion_util.h"
 #include "gwion_ast.h"
 #include "gwion_env.h"
@@ -147,17 +148,13 @@ ANN static void emit_member_func(const Emitter emit, const Exp_Dot *member) {
       instr->m_val = (m_uint)f;
       return;
     }
-  } else if (is_static_call(emit, exp_self(member))) {
+  } else if (is_static_call(emit->gwion, exp_self(member))) {
     if (member->is_call && f == emit->env->func && strcmp(s_name(f->def->base->xid), "new")) return;
     const Instr func_i = emit_add_instr(emit, f->code ? RegPushImm : SetFunc);
     func_i->m_val      = (m_uint)f->code ?: (m_uint)f;
     return;
   } else {
     if (tflag(member->base->type, tflag_struct)) {
-      if (!GET_FLAG(f->def->base, static)) {
-        exp_setvar(member->base, 1);
-        emit_exp(emit, member->base);
-      }
       const Instr func_i = emit_add_instr(emit, f->code ? RegPushImm : SetFunc);
       func_i->m_val      = (m_uint)f->code ?: (m_uint)f;
       return;
@@ -229,12 +226,6 @@ OP_CHECK(opck_object_dot) {
           _("keyword 'this' must be associated with object instance..."));
   const Value value = get_value(env, member, the_base);
   if (!value) {
-/*
-    if(env->class_def != the_base && tflag(the_base, tflag_cdef) && !tflag(the_base, tflag_check))
-      CHECK_BN(ensure_traverse(env, the_base));
-      return check_exp(env, exp_self(member));
-    }
-*/
     const Value v = nspc_lookup_value1(env->curr, member->xid);
     if(v) {
       if (member->is_call) {
@@ -242,14 +233,19 @@ OP_CHECK(opck_object_dot) {
           return v->type;
         if (is_class(env->gwion, v->type)) {
            DECL_OO(const Type, parent, = class_type(env, member, v->type));
-          // allow only direct parent or smth?
-          // mark the function as ctor_ok
           if (isa(the_base, parent) > 0 && parent->nspc) {
             const Symbol sym = insert_symbol(env->gwion->st, "new");
+            if(!env->func || env->func->def->base->xid != sym)
+              ERR_N(exp_self(member)->pos, "calling a parent constructor is only allowed in `new` definition");
+            // is this
+            if(member->base->exp_type != ae_exp_primary ||
+               member->base->d.prim.prim_type != ae_prim_id ||
+               strcmp(s_name(member->base->d.prim.d.var), "this"))
+              ERR_N(exp_self(member)->pos, "calling a parent constructor is only allowed with `this`");
+            SET_FLAG(env->func, const); // mark the function as ctor_ok
             const Value ret = nspc_lookup_value1(parent->nspc, sym);
             member->xid = sym;
-            if(ret)
-              return ret->type;
+            if(ret) return ret->type;
           }
         }
       } else if(is_class(env->gwion, v->type) && the_base == v->type->info->base_type)
@@ -275,7 +271,6 @@ OP_CHECK(opck_object_dot) {
     ERR_N(exp_self(member)->pos,
           _("cannot access member '%s.%s' without object instance..."),
           the_base->name, str);
-// if current function is a constructor
   if (GET_FLAG(value, const)) exp_setmeta(exp_self(member), 1);
   exp_self(member)->acquire = 1;
   return value->type;
@@ -288,7 +283,6 @@ ANN static Type member_type(const Gwion gwion, const Type base) {
 
 OP_EMIT(opem_object_dot) {
   const Exp_Dot *member = (Exp_Dot *)data;
-//  const Type     t_base = actual_type(emit->gwion, member->base->type);
   const Type     t_base = member_type(emit->gwion, member->base->type);
   const Value    value  = find_value(t_base, member->xid);
   if(!tflag(t_base, tflag_emit) /*&& emit->env->class_def != t_base*/) {
@@ -299,23 +293,24 @@ OP_EMIT(opem_object_dot) {
     instr->m_val      = (m_uint)value->type;
     return GW_OK;
   }
+  if (tflag(t_base, tflag_struct) && !GET_FLAG(value, static)) {
+    exp_setvar(member->base, true);
+    CHECK_BB(emit_exp(emit, member->base));
+  }
   if (!is_class(emit->gwion, member->base->type) &&
       (vflag(value, vflag_member) ||
        (is_func(emit->gwion, exp_self(member)->type)))) {
-    if (!tflag(t_base, tflag_struct) && vflag(value, vflag_member))
+    if (!tflag(t_base, tflag_struct))
       CHECK_BB(emit_exp(emit, member->base));
   }
-  if (is_func(emit->gwion, exp_self(member)->type) && // is_func
+  if (is_func(emit->gwion, exp_self(member)->type) &&
       !fflag(exp_self(member)->type->info->func, fflag_fptr))
     emit_member_func(emit, member);
   else if (vflag(value, vflag_member)) {
     if (!tflag(t_base, tflag_struct))
       emit_member(emit, value, exp_getvar(exp_self(member)));
-    else {
-      exp_setvar(member->base, 1);
-      CHECK_BB(emit_exp(emit, member->base));
+    else
       emit_struct_data(emit, value, exp_getvar(exp_self(member)));
-    }
   } else if (GET_FLAG(value, static))
     emit_dot_static_import_data(emit, value, exp_getvar(exp_self(member)));
   else { // member type
@@ -387,14 +382,7 @@ ANN Type scan_class(const Env env, const Type t, const Type_Decl *td) {
   CHECK_BO(envset_pushv(&es, t->info->value));
   const bool local = !owner && !tmpl_global(env, td->types) && from_global_nspc(env, env->curr);
   if(local && env->context) env_push(env, NULL, env->context->nspc);
-  // these context and env command may fit better somewhere else
-//  const m_str env_filename = env->name;
-//  const m_str ctx_filename = env->context->name;
-//  env->name = t->info->value->from->filename;
-//  env->context->name = t->info->value->from->ctx->name;
   const Type ret = _scan_class(env, &info);
-//  env->name = env_filename;
-//  env->context->name = ctx_filename;
   if(local && env->context)env_pop(env, es.scope);
   envset_pop(&es, owner);
   return ret;
index 68756d4fb4f3ddf02ac450660789ba0e2eca949e..1fea7125ec60dfb4863d4797178ee449698010d7 100644 (file)
@@ -952,10 +952,24 @@ ANN Type _check_exp_call1(const Env env, Exp_Call *const exp) {
   return NULL;
 }
 
+ANN static Type check_static(const Env env, const Exp e) {
+  const Type t = e->type;
+  if(unlikely(!is_func(env->gwion, t))             ||
+     !t->info->func                                ||
+     !GET_FLAG(t->info->func->def->base, abstract) ||
+     !is_static_call(env->gwion, e)) return t;
+  env_err(env, e->pos, "making a static call to an abstract function");
+  env->context->error = false;
+  gwerr_secondary_from("declared here", t->info->value->from);
+  env->context->error = true;
+  return NULL;
+}
+
 ANN Type check_exp_call1(const Env env, Exp_Call *const exp) {
   DECL_BO(const m_bool, ret, = func_check(env, exp));
   if (!ret) return exp_self(exp)->type;
   const Type t = exp->func->type;
+  CHECK_OO(check_static(env, exp->func));
   const Type _ret = _check_exp_call1(env, exp);
   if(_ret) return _ret;
   if(isa(exp->func->type, env->gwion->type[et_closure]) > 0) {
@@ -1856,11 +1870,31 @@ ANN m_bool _check_func_def(const Env env, const Func_Def f) {
   return ret;
 }
 
+ANN m_bool check_new(const Env env, const Func_Def fdef) {
+  if(!fdef->builtin && !GET_FLAG(fdef->base->func, const) &&
+    GET_FLAG(env->class_def->info->parent, abstract)) {
+    // we can probably do simpler, but this may require fixing new@ index
+    const Value v = nspc_lookup_value0(env->class_def->info->parent->nspc, fdef->base->xid);
+    if(v) {
+      Func f = v->d.func_ref;
+      while(f) {
+        if(compat_func(fdef, f->def)) break;
+        f = f->next;
+      }
+      if(f && GET_FLAG(f, abstract)) ERR_B(fdef->base->pos, "What what?");
+    }
+  }
+  return GW_OK;
+}
+
 ANN m_bool check_func_def(const Env env, const Func_Def fdef) {
   const uint16_t depth = env->scope->depth;
   env->scope->depth = 0;
   const m_bool ret = _check_func_def(env, fdef);
   env->scope->depth = depth;
+  // we need to find matching parent and see if abstract
+  if(!strcmp(s_name(fdef->base->xid), "new"))
+    CHECK_BB(check_new(env, fdef));
   return ret;
 }
 
index 0129144f54ca42b4b29b959fc005a55c98bf9264..1a5f3208093f03d4b04a9b76901be9763d314bdd 100644 (file)
@@ -724,6 +724,7 @@ ANN static m_bool scan1_parent(const Env env, const Class_Def cdef) {
       !(tflag(cdef->base.type, tflag_cdef) || tflag(cdef->base.type, tflag_udef)))
     ERR_B(pos, _("cannot extend primitive type '%s'"), parent->name)
   if (type_ref(parent)) ERR_B(pos, _("can't use ref type in class extend"))
+  if (GET_FLAG(parent, abstract)) SET_FLAG(cdef->base.type, abstract);
   return GW_OK;
 }
 
index 949254063ee11e47ac2e34d40d01dc2011ffeee1..5f44ab9ed222f90e0ac786c2178443d078b553fc 100644 (file)
@@ -1195,7 +1195,7 @@ vm_prepare(const VM *vm, m_bit *prepare_code) { // lgtm [cpp/use-of-goto]
       reg += VAL2;
       DISPATCH()
     dotfunc:
-      *(VM_Code *)(reg + (m_uint)VAL2) =
+      *(VM_Code *)(reg + IVAL2) =
           ((Func)(*(M_Object *)(reg - SZ_INT))->type_ref->nspc->vtable.ptr[OFFSET + VAL])->code;
       DISPATCH()
     gacktype : {
@@ -1207,9 +1207,8 @@ vm_prepare(const VM *vm, m_bit *prepare_code) { // lgtm [cpp/use-of-goto]
       m_str str = *(m_str *)(reg - SZ_INT);
       if (!VAL) {
         gw_out("%s\n", str);
-fflush(stdout);
-}
-      else
+        fflush(stdout);
+      } else
         *(M_Object *)(reg - SZ_INT) = new_string(vm->gwion, str);
       if (str) mp_free2(vm->gwion->mp, strlen(str), str);
       DISPATCH();