]> Nishi Git Mirror - gwion.git/commitdiff
:art: Add Union.is()
authorJérémie Astor <fennecdjay@gmail.com>
Mon, 14 Dec 2020 15:28:30 +0000 (16:28 +0100)
committerJérémie Astor <fennecdjay@gmail.com>
Mon, 14 Dec 2020 15:28:30 +0000 (16:28 +0100)
include/opcode.h
opcode.txt
src/lib/object.c
src/lib/union.c
src/parse/check.c
src/parse/scan1.c
src/vm/vm.c

index 4385852b6b2d45a02fd1bc4feef3dc714fa1604a..3a698a5bf4ed9156dda10df842b84de816188769 100644 (file)
@@ -163,6 +163,8 @@ enum {
   eDotMember2,
   eDotMember3,
   eDotMember4,
+  eUnionSet,
+  eUnionCheck,
   eDotStatic,
   eDotStatic2,
   eDotStatic3,
@@ -346,6 +348,8 @@ enum {
 #define  DotMember2          (f_instr)eDotMember2
 #define  DotMember3          (f_instr)eDotMember3
 #define  DotMember4          (f_instr)eDotMember4
+#define  UnionSet            (f_instr)eUnionSet
+#define  UnionCheck          (f_instr)eUnionCheck
 #define  DotStatic           (f_instr)eDotStatic
 #define  DotStatic2          (f_instr)eDotStatic2
 #define  DotStatic3          (f_instr)eDotStatic3
index 18d94e12315c1c8ece230d4dc4481573022a8198..3392b39aaab24850caef84ecec0b781c79acbb0a 100644 (file)
@@ -160,6 +160,8 @@ DotMember
 DotMember2
 DotMember3
 DotMember4
+UnionSet
+UnionCheck
 DotStatic
 DotStatic2
 DotStatic3
index 1a9fec85673351bf99e9b582d0f08bdbf1ca0a1a..c4a02a643c6871ae548b34ae71f3c5b5018b970f 100644 (file)
@@ -66,22 +66,24 @@ ANN void __release(const M_Object o, const VM_Shred shred) {
   MemPool p = shred->info->mp;
   Type t = o->type_ref;
   do {
-    if(!t->nspc || isa(t, shred->info->vm->gwion->type[et_union]) > 0)
+    if(!t->nspc)
       continue;
-    struct scope_iter iter = { t->nspc->info->value, 0, 0 };\
-    Value v;
-    while(scope_iter(&iter, &v) > 0) {
-      if(!GET_FLAG(v, static) && !vflag(v, vflag_union) &&
-          isa(v->type, shred->info->vm->gwion->type[et_object]) > 0)
-        release(*(M_Object*)(o->data + v->from->offset), shred);
-      else if(tflag(v->type, tflag_struct) &&
-            !GET_FLAG(v, static) && !vflag(v, vflag_union) && v->type->info->tuple) {
-        const TupleForm tf = v->type->info->tuple;
-        for(m_uint i = 0; i < vector_size(&tf->types); ++i) {
-          const m_bit *data = o->data + v->from->offset;
-          const Type t = (Type)vector_at(&tf->types, i);
-          if(isa(t, shred->info->vm->gwion->type[et_object]) > 0)
-            release(*(M_Object*)(data + vector_at(&tf->offset, i)), shred);
+    if(isa(t, shred->info->vm->gwion->type[et_union]) > 0) {
+      struct scope_iter iter = { t->nspc->info->value, 0, 0 };\
+      Value v;
+      while(scope_iter(&iter, &v) > 0) {
+        if(!GET_FLAG(v, static) && !vflag(v, vflag_union) &&
+            isa(v->type, shred->info->vm->gwion->type[et_object]) > 0)
+          release(*(M_Object*)(o->data + v->from->offset), shred);
+        else if(tflag(v->type, tflag_struct) &&
+              !GET_FLAG(v, static) && !vflag(v, vflag_union) && v->type->info->tuple) {
+          const TupleForm tf = v->type->info->tuple;
+          for(m_uint i = 0; i < vector_size(&tf->types); ++i) {
+            const m_bit *data = o->data + v->from->offset;
+            const Type t = (Type)vector_at(&tf->types, i);
+            if(isa(t, shred->info->vm->gwion->type[et_object]) > 0)
+              release(*(M_Object*)(data + vector_at(&tf->offset, i)), shred);
+          }
         }
       }
     }
index 1a33a181111248785684630775c2683f0c838be4..fa8e7b42f90f7ba11613639711d6201fdb82b291 100644 (file)
@@ -16,31 +16,30 @@ static GACK(gack_none) {
   INTERP_PRINTF("None")
 }
 
-static INSTR(UnionSet) {
-  const M_Object o = *(M_Object*)REG(-SZ_INT);
-  *(m_uint*)o->data = instr->m_val;
-  memcpy(o->data + SZ_INT, REG(-SZ_INT-instr->m_val2), instr->m_val2);
-  *(m_bit**)REG(-SZ_INT) = o->data + SZ_INT;
-}
+static const f_instr dotmember[]  = { DotMember, DotMember2, DotMember3, DotMember4 };
 
-static INSTR(UnionCheck) {
-  const M_Object o = *(M_Object*)REG(-SZ_INT);
-  if(*(m_uint*)o->data != instr->m_val)
-    Except(shred, _("invalid union access"))
-  POP_REG(shred, SZ_INT - instr->m_val2);
-  memcpy(REG(-instr->m_val2), o->data + SZ_INT, instr->m_val2);
-}
+ANN Instr emit_kind(Emitter emit, const m_uint size, const uint addr, const f_instr func[]);
 
 static OP_EMIT(opem_union_dot) {
   const Exp_Dot *member = (Exp_Dot*)data;
   const Map map = &member->t_base->nspc->info->value->map;
+  CHECK_BO(emit_exp(emit, member->base))
+  if(isa(exp_self(member)->info->type, emit->gwion->type[et_function]) > 0) {
+    const Instr instr = emit_add_instr(emit, RegPushImm);
+    const Func f = (Func)vector_front(&member->t_base->info->parent->nspc->info->vtable);
+    instr->m_val = (m_uint)f->code;
+    return instr;
+  }
   for(m_uint i = 0; i < map_size(map); ++i) {
     if(VKEY(map, i) == (m_uint)member->xid) {
-      CHECK_BO(emit_exp(emit, member->base))
-      const Instr instr = emit_add_instr(emit,
-        !exp_getvar(exp_self(member)) ? UnionCheck : UnionSet);
-      instr->m_val = i + 1;
-      instr->m_val2 = ((Value)VVAL(map, i))->type->size;
+      const Value v = (Value)VVAL(map, i);
+      const uint emit_addr = exp_getvar(exp_self(member));
+      const Instr pre = emit_add_instr(emit,
+        !emit_addr ? UnionCheck : UnionSet);
+      pre->m_val = i + 1;
+      const Instr instr = emit_kind(emit, v->type->size, emit_addr, dotmember);
+      instr->m_val = SZ_INT;
+      instr->m_val2 = v->type->size;
       return instr;
     }
   }
@@ -50,10 +49,37 @@ static OP_EMIT(opem_union_dot) {
 static DTOR(UnionDtor) {
   const m_uint idx = *(m_uint*)o->data;
   if(idx) {
-    const Type t = *(Type*)(o->type_ref->nspc->info->class_data + (idx-1) * SZ_INT);
-    if(isa(t, shred->info->vm->gwion->type[et_compound]) > 0)
-      compound_release(shred, t, (o->data + SZ_INT));
+    const Map map = &o->type_ref->nspc->info->value->map;
+    const Value v = (Value)map_at(map, idx-1);
+    if(isa(v->type, shred->info->vm->gwion->type[et_compound]) > 0)
+      compound_release(shred, v->type, (o->data + SZ_INT));
+  }
+}
+
+static OP_CHECK(opck_union_is) {
+  const Exp e = (Exp)data;
+  const Exp_Call *call = &e->d.exp_call;
+  const Exp exp = call->args;
+  if(exp->exp_type != ae_exp_primary && exp->d.prim.prim_type != ae_prim_id)
+    ERR_N(exp->pos, "Union.is() argument must be of form id");
+  const Type t = call->func->d.exp_dot.t_base;
+  const Value v = find_value(t, exp->d.prim.d.var);
+  if(!v)
+    ERR_N(exp->pos, "'%s' has no member '%s'", t->name, s_name(exp->d.prim.d.var));
+  const Map map = &t->nspc->info->value->map;
+  for(m_uint i = 0; i < map_size(map); ++i) {
+    const Value v = (Value)VVAL(map, i);
+    if(!strcmp(s_name(exp->d.prim.d.var), v->name)) {
+      exp->d.prim.prim_type = ae_prim_num;
+      exp->d.prim.d.num = i+1;
+      return env->gwion->type[et_bool];
+    }
   }
+  return env->gwion->type[et_error];
+}
+
+static MFUN(union_is) {
+  *(m_uint*)RETURN = *(m_uint*)MEM(SZ_INT) == *(m_uint*)o->data;
 }
 
 ANN GWION_IMPORT(union) {
@@ -68,7 +94,15 @@ ANN GWION_IMPORT(union) {
   gwi_class_xtor(gwi, NULL, UnionDtor);
   GWI_BB(gwi_item_ini(gwi, "int", "@index"))
   GWI_BB(gwi_item_end(gwi, ae_flag_none, NULL))
+  GWI_BB(gwi_func_ini(gwi, "bool", "is"))
+  GWI_BB(gwi_func_arg(gwi, "int", "member"))
+  GWI_BB(gwi_func_end(gwi, union_is, ae_flag_none))
   GWI_BB(gwi_class_end(gwi))
+  const Func f = (Func)vector_front(&t_union->nspc->info->vtable);
+  const struct Op_Func opfunc = { .ck=opck_union_is };
+  const struct Op_Import opi = { .rhs=f->value_ref->type,
+       .func=&opfunc, .data=(uintptr_t)f, .pos=gwi->loc, .op=insert_symbol(gwi->gwion->st, "@func_check") };
+  CHECK_BB(add_op(gwi->gwion, &opi))
   gwi->gwion->type[et_union] = t_union;
 
   GWI_BB(gwi_oper_ini(gwi, "@Union", (m_str)OP_ANY_TYPE, NULL))
index 39108371132b420c7cd5b0a13ecd5ea9c05002a0..873240709ac30d124e8216a93c45305040d8426d 100644 (file)
@@ -687,10 +687,11 @@ ANN static Type check_lambda_call(const Env env, const Exp_Call *exp) {
 ANN m_bool func_check(const Env env, const Exp_Call *exp) {
   CHECK_OB(check_exp(env, exp->func))
   const Type t = actual_type(env->gwion, exp->func->info->type);
+  const Exp e = exp_self(exp);
   struct Op_Import opi = { .op=insert_symbol("@func_check"),
-  .rhs=t, .pos=exp_self(exp)->pos, .data=(uintptr_t)exp, .op_type=op_exp };
+  .rhs=t, .pos=exp_self(exp)->pos, .data=(uintptr_t)e, .op_type=op_exp };
   CHECK_NB(op_check(env, &opi)) // doesn't really return NULL
-  return exp_self(exp)->info->type != env->gwion->type[et_error] ?
+  return e->info->type != env->gwion->type[et_error] ?
     GW_OK : GW_ERROR;
 }
 
index a91a7ec449de21267f09bf1862c7594c13807889..0d78487bf1304565d86d96b106bec479f095084c 100644 (file)
@@ -407,9 +407,9 @@ ANN static inline m_bool scan1_union_def_inner_loop(const Env env, Union_Def ude
     DECL_OB(const Type, t, = known_type(env, l->td))
     if(nspc_lookup_value0(env->curr, l->xid))
       ERR_B(l->pos, _("'%s' already declared in union"), s_name(l->xid))
-// check name
-puts(env->curr->name);
     const Value v = new_value(env->gwion->mp, t, s_name(l->xid));
+    if(!tflag(t, tflag_scan1))
+      tuple_contains(env, v);
     v->from->offset = SZ_INT;
     valuefrom(env ,v->from);
     nspc_add_value_front(env->curr, l->xid, v);
index ae258a3e335d8612120d725f6dd1b40bd991b2df..d010c946218b7bbf67fc9beb2ffac78b595a4c6c 100644 (file)
@@ -323,6 +323,7 @@ ANN void vm_run(const VM* vm) { // lgtm [cpp/use-of-goto]
     &&arrayappend, &&autoloop, &&autoloopptr, &&autoloopcount, &&arraytop, &&arrayaccess, &&arrayget, &&arrayaddr, &&arrayvalid,
     &&newobj, &&addref, &&addrefaddr, &&objassign, &&assign, &&remref,
     &&except, &&allocmemberaddr, &&dotmember, &&dotfloat, &&dotother, &&dotaddr,
+    &&unionset, &&unioncheck,
     &&staticint, &&staticfloat, &&staticother,
     &&upvalueint, &&upvaluefloat, &&upvalueother, &&upvalueaddr,
     &&dotfunc, &&dotstaticfunc,
@@ -757,7 +758,7 @@ arrayvalid:
   vector_pop(&shred->gc);
   goto regpush;
 newobj:
-  *(M_Object*)reg = new_object(vm->gwion->mp, shred, (Type)VAL2);
+  *(M_Object*)reg = new_object(vm->gwion->mp, NULL, (Type)VAL2);
   reg += SZ_INT;
   DISPATCH()
 addref:
@@ -823,6 +824,15 @@ PRAGMA_POP()
 dotaddr:
   *(m_bit**)(reg-SZ_INT) = ((*(M_Object*)(reg-SZ_INT))->data + VAL);
   DISPATCH()
+unionset:
+  *(m_uint*)(*(M_Object*)(reg-SZ_INT))->data = VAL;
+  DISPATCH()
+unioncheck:
+  if(*(m_uint*)(*(M_Object*)(reg-SZ_INT))->data != VAL) {
+    exception(shred, "invalid union acces");
+    continue;
+  }
+  DISPATCH()
 staticint:
   *(m_uint*)reg = *(m_uint*)VAL;
   reg += SZ_INT;