Gwion coverage report


Directory: src/
File: src/parse/check_traits.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 0 135 0.0%
Functions: 0 13 0.0%
Branches: 0 112 0.0%

Line Branch Exec Source
1 #include <ctype.h>
2 #include "gwion_util.h"
3 #include "gwion_ast.h"
4 #include "gwion_env.h"
5 #include "vm.h"
6 #include "instr.h"
7 #include "traverse.h"
8 #include "template.h"
9 #include "gwion.h"
10 #include "object.h"
11 #include "operator.h"
12 #include "import.h"
13 #include "parse.h"
14
15 ANN static bool var_match(const Value a, const Value b) {
16 bool error = true;
17 if (isa(a->type, a->type) < 0) {
18 gwerr_basic_from("invalid variable type", NULL, NULL, a->from, 0);
19 error = false;
20 }
21 if (GET_FLAG(a, const) && !GET_FLAG(b, const)) {
22 gwerr_basic_from("variable differs in {/}constness{0}", NULL, NULL, a->from, 0);
23 error = false;
24 }
25 if (GET_FLAG(a, static) && !GET_FLAG(b, static)) {
26 gwerr_basic_from("variable differs in {/}storage{0}", NULL, NULL, a->from, 0);
27 error = false;
28 }
29 if (error) return true;
30 gwerr_secondary_from("from requested variable", b->from);
31 return error;
32 }
33
34 ANN static bool request_var(const Env env, const Type t, const Value request) {
35 const Value value = nspc_lookup_value0(t->nspc, insert_symbol(request->name));
36 if (!value) {
37 gwerr_basic("missing requested variable", NULL, NULL,
38 request->from->filename, request->from->loc, 0);
39 return false;
40 }
41 return var_match(value, request);
42 }
43
44 ANN static bool check_trait_variables(const Env env, const Type t,
45 const Trait trait) {
46 bool error = false;
47 for (m_uint i = 0; i < trait->var->len; i++) {
48 const Value request = *mp_vector_at(trait->var, Value, i);
49 if (!request_var(env, t, request)) error = true;
50 }
51 return error;
52 }
53
54 ANN static bool trait_inherit(const Env env, const Type t, const Func_Def req) {
55 const bool global = type_global(env, t) || !!nspc_lookup_value1(env->curr->parent, req->base->xid);
56 nspc_push_type(env->gwion->mp, env->curr);
57 nspc_add_type(env->curr, insert_symbol("Self"), t);
58 const Func_Def cpy = cpy_func_def(env->gwion->mp, req);
59 if(global) SET_FLAG(cpy->base, global);
60 const m_bool ret = traverse_func_def(env, cpy);
61 nspc_pop_type(env->gwion->mp, env->curr);
62 Section section = MK_SECTION(func, func_def, cpy);
63 if(!env->context->extend)
64 env->context->extend = new_mp_vector(env->gwion->mp, Section, 0);
65 mp_vector_add(env->gwion->mp, &env->context->extend, Section, section);
66 return ret;
67 }
68
69 ANN static bool check_trait_args(const Env env, const Func f, const Func_Base *req, const bool m) {
70 if (mp_vector_len(f->def->base->args) + m != mp_vector_len(req->args)) return false;
71 if(m) {
72 const Arg *r = mp_vector_at(req->args, Arg, 0);
73 if(strcmp(s_name(r->td->xid), "Self"))
74 return false;
75 }
76 for(m_uint i = m; i < req->args->len; i++) {
77 const Arg *r = mp_vector_at(req->args, Arg, i + m);
78 const Type t = known_type(env, r->td);
79 const Arg *arg = mp_vector_at(f->def->base->args, Arg, i);
80 if(arg->type != t) return false;
81 }
82 return true;
83 }
84
85 ANN static bool request_found(const Env env, const Type t,
86 const Func_Def request) {
87 const Value v = nspc_lookup_value0(t->nspc, request->base->xid);
88 if (!v) return false;
89 if (!is_func(env->gwion, v->type)) {
90 gwerr_basic_from("is not a function", NULL, NULL, v->from, 0);
91 return false;
92 }
93 Func f = v->d.func_ref;
94 do {
95 const Func_Base *req = request->base;
96 const Func_Base *fbase = f->def->base;
97 if (!GET_FLAG(fbase, abstract) &&
98 fbase->ret_type == known_type(env, req->td) &&
99 (!req->args || check_trait_args(env, f, req, vflag(f->value_ref, vflag_member))))
100 return true;
101 } while ((f = f->next));
102 return false;
103 }
104
105 ANN static bool ufcs_match(const Env env, const Value v,
106 const Func_Def request, const bool global) {
107 if (!is_func(env->gwion, v->type)) return false; // mayb enot ignore;
108 Func f = v->d.func_ref;
109 do {
110 const Func_Base *req = request->base;
111 const Func_Base *fbase = f->def->base;
112 if (!GET_FLAG(fbase, abstract) &&
113 !vflag(f->value_ref, vflag_member) &&
114 fbase->ret_type == known_type(env, req->td) &&
115 mp_vector_len(fbase->args) == mp_vector_len(req->args) &&
116 (!req->args || check_trait_args(env, f, req, 0))) {
117 if(global && !GET_FLAG(fbase, global))
118 return false;
119 return true;
120 }
121 } while ((f = f->next));
122 return false;
123 }
124
125 ANN static bool trait_ufcs(const Env env, const Type t,
126 const Func_Def request) {
127 const Value v = nspc_lookup_value1(env->curr, request->base->xid);
128 if(v) {
129 const bool global = type_global(env, t) || from_global_nspc(env, v->from->owner);
130 nspc_push_type(env->gwion->mp, env->curr);
131 nspc_add_type(env->curr, insert_symbol("Self"), t);
132 const bool ret = ufcs_match(env, v, request, global);
133 nspc_pop_type(env->gwion->mp, env->curr);
134 if (ret) return true;
135 }
136 return false;
137 }
138
139 ANN static bool request_fun(const Env env, const Type t,
140 const Func_Def request) {
141 if (t->nspc && request_found(env, t, request)) return true;
142 if (trait_ufcs(env, t, request)) return true;
143 if (!GET_FLAG(request->base, abstract))
144 return trait_inherit(env, t, request);
145 const Value parent = nspc_lookup_value1(env->global_nspc, request->base->xid);
146 if(parent) {
147 const Value v = nspc_lookup_value1(env->curr, request->base->xid);
148 if(!env->context->error) {
149 gwerr_basic_from("is missing {+G}global{0}", NULL, NULL, v->from, 0);
150 gwerr_secondary("from requested func", env->name, request->base->pos);
151 env->context->error = true;
152 }
153 } else gwerr_basic("missing requested function", NULL, NULL, env->name,
154 request->base->pos, 0);
155 return false;
156 }
157
158 ANN static bool check_trait_functions(const Env env, const Type t,
159 const Trait trait) {
160 bool error = false;
161 for (m_uint i = 0; i < trait->fun->len; i++) {
162 const Func_Def request = *mp_vector_at(trait->fun, Func_Def, i);
163 if (!request_fun(env, t, request)) error = true;
164 }
165 return error;
166 }
167
168 ANN bool trait_nodup(const ID_List list, const uint32_t i) {
169 const Symbol fst = *mp_vector_at(list, Symbol, i);
170 for(uint32_t j = i + 1; j < list->len; j++) {
171 const Symbol snd = *mp_vector_at(list, Symbol, j);
172 if (fst == snd) return false;
173 }
174 return true;
175 }
176
177 ANN static inline bool trait_error(const Env env) {
178 env_set_error(env, true);
179 return false;
180 }
181
182 ANN bool check_trait_requests(const Env env, const Type t, const ID_List list, const ValueFrom *from) {
183 for(uint32_t i = 0; i < list->len; i++) {
184 const Symbol xid = *mp_vector_at(list, Symbol, i);
185 const Trait trait = nspc_lookup_trait1(env->curr, xid);
186 if (!trait_nodup(list, i)) {
187 gwerr_secondary_from("class has duplicated trait", from);
188 return trait_error(env);
189 }
190 if (trait->var ? check_trait_variables(env, t, trait) : false ||
191 trait->fun ? check_trait_functions(env, t, trait) : false) {
192 gwerr_secondary("in trait", trait->filename, trait->loc);
193 gwerr_secondary("requested here", from->filename, from->loc);
194 return trait_error(env);
195 }
196 }
197 return true;
198 }
199