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 |
|
|
|