Gwion coverage report


Directory: src/
File: src/lib/ref.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 84 133 63.2%
Functions: 9 13 69.2%
Branches: 13 36 36.1%

Line Branch Exec Source
1 #include <stdlib.h>
2 #include <string.h>
3 #include "gwion_util.h"
4 #include "gwion_ast.h"
5 #include "gwion_env.h"
6 #include "vm.h"
7 #include "gwion.h"
8 #include "instr.h"
9 #include "object.h"
10 #include "operator.h"
11 #include "import.h"
12 #include "emit.h"
13 #include "traverse.h"
14 #include "template.h"
15 #include "parse.h"
16 #include "specialid.h"
17 #include "gwi.h"
18 #include "tmpl_info.h"
19
20 11 ANN Type ref_type(const Gwion gwion, const Type t, const loc_t loc) {
21 11 const m_str name = type2str(gwion, t, loc);
22 11 char c[7 + strlen(name)];
23 11 sprintf(c, "Ref:[%s]", name);
24 11 return str2type(gwion, c, loc);
25 }
26
27 1 static m_bool ref_access(const Env env, const Exp e) {
28 1 const m_str access = exp_access(e);
29
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!access) return GW_OK;
30 env_err(env, e->pos, _("operand is %s"), access);
31 return GW_ERROR;
32 }
33
34 1 static OP_CHECK(opck_ref_implicit_similar) {
35 1 const struct Implicit *imp = (struct Implicit *)data;
36
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 CHECK_BN(ref_access(env, imp->e));
37 1 exp_setvar(imp->e, 1);
38 1 return imp->t;
39 }
40
41 static inline Type ref_base(Type t) {
42 do if(!tflag(t->info->parent, tflag_ref))
43 return t;
44 while((t = t->info->parent));
45 return NULL;
46 }
47
48 1 static OP_EMIT(opem_ref_implicit_similar) {
49 1 const struct Implicit *imp = (struct Implicit *)data;
50
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if(!tflag(imp->t, tflag_contract)) return GW_OK;
51 const Env env = emit->env;
52 const Type base = ref_base(imp->t);
53 struct Op_Import opi = {.op = insert_symbol("@implicit"),
54 .lhs = base,
55 .rhs = imp->t,
56 .data = (m_uint)imp};
57 CHECK_BB(op_emit(emit, &opi));
58 emit_regmove(emit, -imp->e->type->size);
59 exp_setvar(imp->e, true);
60 imp->e->cast_to = NULL;
61 return emit_exp(emit, imp->e);
62 }
63
64 static OP_CHECK(opck_implicit_ref) {
65 const struct Implicit *imp = (struct Implicit *)data;
66 CHECK_BN(ref_access(env, imp->e));
67 exp_setvar(imp->e, 1);
68 imp->e->cast_to = imp->t;
69 return imp->t;
70 }
71
72 static OP_CHECK(opck_ref_contract_similar) {
73 const struct Implicit *imp = (struct Implicit *)data;
74 CHECK_BN(ref_access(env, imp->e));
75 const Type base = (Type)vector_front(&imp->t->info->tuple->contains);
76 struct Op_Import opi = {.op = insert_symbol("@implicit"),
77 .lhs = imp->e->type,
78 .rhs = base,
79 .data = (m_uint)imp};
80 return op_check(env, &opi);
81 }
82
83 static OP_EMIT(opem_ref_contract_similar) {
84 const struct Implicit *imp = (struct Implicit *)data;
85 const Env env = emit->env;
86 const Type base = (Type)vector_front(&imp->t->info->tuple->contains);
87 struct Exp_ cast = {.type=base, .d={.exp_cast={.exp=imp->e}}};
88 struct Op_Import opi = {.op = insert_symbol("$"),
89 .lhs = imp->e->type,
90 .rhs = base,
91 .data = (m_uint)&cast};
92 CHECK_BB(op_emit(emit, &opi));
93 emit_regmove(emit, -imp->e->type->size);
94 exp_setvar(imp->e, true);
95 imp->e->cast_to = NULL;
96 return emit_exp(emit, imp->e);
97 }
98
99 644 ANN static void base2ref(Env env, const Type lhs, const Type rhs) {
100 644 struct Op_Func opfunc = {.ck = opck_similar_cast};
101 644 struct Op_Import opi = {.op = insert_symbol("$"),
102 .lhs = lhs,
103 .ret = rhs,
104 .rhs = rhs,
105 .func = &opfunc,
106 .data = eNoOp};
107 644 add_op(env->gwion, &opi);
108 644 opfunc.ck = opck_ref_implicit_similar;
109 644 opfunc.em = opem_ref_implicit_similar;
110 644 opi.op = insert_symbol("@implicit");
111 644 add_op(env->gwion, &opi);
112
113
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 644 times.
644 if(tflag(lhs, tflag_contract)) {
114 opi.lhs = lhs->info->base_type;
115 opfunc.ck = opck_ref_contract_similar;
116 opfunc.em = opem_ref_contract_similar;
117 opi.op = insert_symbol("@implicit");
118 add_op(env->gwion, &opi);
119 }
120
121 644 }
122
123 644 ANN static void ref2base(Env env, const Type lhs, const Type rhs) {
124 644 struct Op_Import opi = {.op = insert_symbol("$"),
125 .lhs = lhs,
126 .ret = rhs,
127 .rhs = rhs,
128 /*.func=&opfunc,*/ .data = eNoOp};
129 644 add_op(env->gwion, &opi);
130 644 opi.op = insert_symbol("@implicit");
131 644 add_op(env->gwion, &opi);
132 644 }
133
134 644 ANN static void ref2ref(Env env, const Type lhs, const Type rhs) {
135 644 struct Op_Func opfunc = {.ck = opck_implicit_ref };
136 644 struct Op_Import opi = {.op = insert_symbol("$"),
137 .lhs = lhs,
138 .ret = rhs,
139 .rhs = rhs,
140 .func=&opfunc, .data = eNoOp};
141 644 add_op(env->gwion, &opi);
142 644 opi.op = insert_symbol("@implicit");
143 644 add_op(env->gwion, &opi);
144 644 }
145
146 653 static OP_CHECK(opck_ref_scan) {
147 653 struct TemplateScan *ts = (struct TemplateScan *)data;
148 653 struct tmpl_info info = {
149 653 .base = ts->t, .td = ts->td, .list = ts->t->info->cdef->base.tmpl->list};
150 653 const Type exists = tmpl_exists(env, &info);
151
3/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 644 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
653 if (exists) return exists != env->gwion->type[et_error] ? exists : NULL;
152 644 const Type base = known_type(env, *mp_vector_at(ts->td->types, Type_Decl*, 0));
153 644 const Type t = new_type(env->gwion->mp, s_name(info.name), base);
154 644 t->size = SZ_INT;
155 644 SET_FLAG(t, abstract | ae_flag_final);
156 644 set_tflag(t, tflag_infer);
157 644 set_tflag(t, tflag_noret);
158 644 set_tflag(t, tflag_scan0);
159 644 set_tflag(t, tflag_scan1);
160 644 set_tflag(t, tflag_scan2);
161 644 set_tflag(t, tflag_check);
162 644 set_tflag(t, tflag_emit);
163 644 set_tflag(t, tflag_ref);
164 644 const m_uint scope = env_push(env, base->info->value->from->owner_class,
165 644 base->info->value->from->owner);
166 644 mk_class(env, t, (loc_t) {});
167 644 base2ref(env, base, t);
168 644 ref2base(env, t, base);
169 644 ref2ref(env, t, t);
170 644 env_pop(env, scope);
171 644 t->info->tuple = new_tupleform(env->gwion->mp, base);
172 644 type_addref(base);
173 644 vector_add(&t->info->tuple->contains, (vtype)base);
174 644 nspc_add_type_front(t->info->value->from->owner, info.name, t);
175 644 return t;
176 }
177
178 638 GWION_IMPORT(ref) {
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
638 gwidoc(gwi, "Ref: take a reference from a variable.");
180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
638 gwinote(gwi, "used just as the variable it reference.");
181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
638 gwinote(gwi, "can only be used as argument.");
182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
638 gwinote(gwi, "and cannot be returned.");
183 638 const Type t_foreach = gwi_struct_ini(gwi, "Ref:[A]");
184 638 set_tflag(t_foreach, tflag_infer);
185
186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
638 gwinote(gwi, "a pointer to the referenced variable.");
187 638 t_foreach->nspc->offset += SZ_INT;
188
189 638 GWI_BB(gwi_struct_end(gwi))
190
191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
638 gwidoc(gwi, "internal `Ref` type creation.");
192 638 GWI_BB(gwi_oper_ini(gwi, "Ref", NULL, NULL))
193 638 GWI_BB(gwi_oper_add(gwi, opck_ref_scan))
194 638 GWI_BB(gwi_oper_end(gwi, "class", NULL))
195 638 return GW_OK;
196 }
197