Gwion coverage report


Directory: src/
File: src/parse/partial.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 144 156 92.3%
Functions: 16 16 100.0%
Branches: 66 96 68.8%

Line Branch Exec Source
1 #include "gwion_util.h"
2 #include "gwion_ast.h"
3 #include "gwion_env.h"
4 #include "vm.h"
5 #include "instr.h"
6 #include "emit.h"
7 #include "gwion.h"
8 #include "object.h"
9 #include "operator.h"
10 #include "import.h"
11 #include "gwi.h"
12 #include "traverse.h"
13 #include "parse.h"
14 #include "partial.h"
15
16 6 ANN static Arg_List partial_arg_list(const Env env, const Arg_List base, const Exp e) {
17 6 Arg_List args = new_mp_vector(env->gwion->mp, Arg, 0);
18 6 Exp next = e;
19 6 uint32_t i = 0;
20
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6 times.
17 while(next) {
21
3/4
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
11 if(is_hole(env, next) || is_typed_hole(env, next)) {
22 char c[256];
23 7 sprintf(c, "@%u", args->len);
24 7 const Arg *src = mp_vector_at(base, Arg, i);
25
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 Type_Decl *td = src->td ? cpy_type_decl(env->gwion->mp, src->td) : NULL;
26 7 Arg arg = { .td = td, .var_decl = { .xid = insert_symbol(c) }};
27
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 mp_vector_add(env->gwion->mp, &args, Arg, arg);
28 }
29 11 i++;
30 11 next = next->next;
31 }
32 6 return args;
33 }
34
35 6 ANN static inline Symbol partial_name(const Env env, const pos_t pos) {
36 6 char c[7 + 1 + num_digit(pos.line) + num_digit(pos.column) + 2];
37 6 sprintf(c, "partial:%u:%u", pos.line, pos.column);
38 6 return insert_symbol(c);
39 }
40
41 6 ANN2(1, 2) static inline Func_Base *partial_base(const Env env, const Func_Base *base, Exp earg, const loc_t loc) {
42
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 Arg_List args = earg ? partial_arg_list(env, base->args, earg) : NULL;
43
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 Func_Base *fb = new_func_base(env->gwion->mp, base->td ? cpy_type_decl(env->gwion->mp, base->td) : NULL, partial_name(env, loc.first), args, ae_flag_none, loc);
44 6 return fb;
45 }
46
47 11 ANN static Exp partial_exp(const Env env, Arg_List args, Exp e, const uint i) {
48
3/4
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
11 if(is_hole(env, e) || is_typed_hole(env, e)) {
49 char c[256];
50 7 sprintf(c, "@%u", i);
51 7 const Exp exp = new_prim_id(env->gwion->mp, insert_symbol(c), e->pos);
52 7 exp->type = known_type(env, mp_vector_at(args, Arg, i)->td);
53 7 exp->d.prim.value = new_value(env, exp->type, c, e->pos);
54 7 valid_value(env, insert_symbol(c), exp->d.prim.value);
55 7 return exp;
56 }
57 4 const Exp next = e->next;
58 4 e->next = NULL;
59 4 const Exp exp = cpy_exp(env->gwion->mp, e);
60 4 exp->type = e->type;
61 4 e->next = next;
62 4 return exp;
63 }
64
65 6 ANN2(1) static Exp partial_call(const Env env, Arg_List args, Exp e) {
66 6 Exp base = NULL, arg;
67 6 uint32_t i = 0;
68
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6 times.
17 while(e) {
69 11 const Exp exp = partial_exp(env, args, e, i++);
70
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
11 if(base) arg = arg->next = exp;
71 6 else arg = base = exp;
72 11 e = e->next;
73 }
74 6 return base;
75 }
76
77
78 19 ANN Func find_match(const Env env, Func func, const Exp exp, const bool implicit,
79 const bool specific) {
80 do {
81 19 Exp e = exp;
82 19 uint32_t i = 0;
83 19 Arg_List args = func->def->base->args;
84 19 uint32_t len = mp_vector_len(args);
85
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 9 times.
45 while(e) {
86
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 27 times.
36 if (i >= len) break;
87 27 const Arg *arg = mp_vector_at(args, Arg, i++);
88
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 22 times.
27 if(!is_hole(env, e)) {
89
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 if(!is_typed_hole(env, e)) {
90 5 const Exp next = e->next;
91 5 e->next = NULL;
92 5 const Type ret = check_exp(env, e);
93 5 e->next = next;
94
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 CHECK_OO(ret);
95 } else
96 CHECK_OO((e->type = known_type(env, e->d.exp_cast.td)));
97
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
5 if (!func_match_inner(env, e, arg->type, implicit, specific)) break;
98 }
99 26 e = e->next;
100 }
101
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 1 times.
19 if (!e && len == i) return func;
102
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9 times.
11 } while ((func = func->next));
103 9 return NULL;
104 }
105
106 10 ANN Func find_match_actual(const Env env, const Func up, const Exp args) {
107
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 3 times.
13 return find_match(env, up, args, false, true) ?:
108
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
5 find_match(env, up, args, true, true) ?:
109
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
4 find_match(env, up, args, false, true) ?:
110 2 find_match(env, up, args, true, false) ?:
111 NULL;
112 }
113
114 ANN static Func partial_match(const Env env, const Func up, const Exp args, const loc_t loc);
115
116 10 ANN static void print_arg(Arg_List args) {
117
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 10 times.
25 for(uint32_t i = 0; i < args->len; i++) {
118 15 Arg *arg = mp_vector_at(args, Arg, i);
119
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 gw_err("{G}%s{0} {/}%s{0}", arg->type ? arg->type->name : NULL,
120 arg->var_decl.xid ? s_name(arg->var_decl.xid) : "");
121
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 10 times.
15 if(i < args->len - 1) gw_err(", ");
122 }
123 10 }
124
125 12 ANN void print_signature(const Func f) {
126 12 gw_err(" {-}(%s){0} ", f->name);
127 12 const Arg_List args = f->def->base->args;
128
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
12 if (args)
129 10 print_arg(args);
130 else
131 2 gw_err("{G}void{0}");
132 12 gw_err("\n");
133 12 }
134
135 1 ANN void ambiguity(const Env env, Func f, const Exp args, const loc_t loc) {
136 1 print_signature(f);
137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 while(f->next) {
138 const Func next = partial_match(env, f->next, args, loc);
139 if(next) print_signature(next);
140 f = f->next;
141 }
142 1 }
143
144 10 ANN static Func partial_match(const Env env, const Func up, const Exp args, const loc_t loc) {
145 10 const Func f = find_match_actual(env, up, args);
146
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 if(f) {
147 8 const Type t = f->value_ref->from->owner_class;
148
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if(f->next) {
149 2 const Func next = partial_match(env, f->next, args, loc);
150
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if(next) {
151 1 const Type tnext = next->value_ref->from->owner_class;
152
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if(!t || !tnext || isa(t, tnext) < 0) {
153 1 gwerr_basic(_("can't resolve ambiguity"), _("in this partial application"), _("use typed holes: _ $ type"), env->name, loc, 0);
154 1 gw_err(_("\nthose functions could match:\n"));
155 1 print_signature(f);
156 1 ambiguity(env, next, args, loc);
157 1 env_set_error(env, true);
158 1 return NULL;
159 }
160 }
161 }
162 7 return f;
163 }
164 2 return NULL;
165 }
166
167 6 ANN static Stmt_List partial_code(const Env env, Arg_List args, const Exp efun, const Exp earg) {
168 6 const Exp arg = partial_call(env, args, earg);
169 6 const Exp exp = new_exp_call(env->gwion->mp, efun, arg, efun->pos);
170 6 Stmt_List code = new_mp_vector(env->gwion->mp, struct Stmt_, 1);
171 6 mp_vector_set(code, struct Stmt_, 0, ((struct Stmt_) {
172 .stmt_type = ae_stmt_return,
173 .d = { .stmt_exp = { .val = exp }}
174 }));
175 // stmt->stmt_type = ae_stmt_return;
176 // stmt->d.stmt_exp.val = exp;
177 6 return code;
178 // return new_stmt_code(env->gwion->mp, slist, efun->pos);
179 }
180
181 2 ANN static uint32_t count_args_exp(Exp args) {
182 2 uint32_t i = 0;
183 4 do i++;
184
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 while ((args = args->next));
185 2 return i;
186 }
187
188 2 ANN static uint32_t count_args_func(Func f, const uint32_t i) {
189 2 uint32_t max = 0;
190 do {
191 3 const uint32_t len = mp_vector_len(f->def->base->args);
192
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if(len > i && len > max) max = len;
193
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } while ((f = f->next));
194 2 return max;
195 }
196
197 2 ANN static Exp expand(const Env env, const Func func, const Exp e, const loc_t loc) {
198 2 const uint32_t i = count_args_exp(e);
199 2 const uint32_t max = count_args_func(func, i);
200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(max > i) {
201 Exp args = e;
202 if(args) {
203 while(args->next) args = args->next;
204 args->next = new_prim_id(env->gwion->mp, insert_symbol("_"), loc);
205 return e;
206 } else return new_prim_id(env->gwion->mp, insert_symbol("_"), loc);
207 }
208 2 return NULL;
209 }
210
211 9 ANN Type partial_type(const Env env, Exp_Call *const call) {
212 9 const Func base = call->func->type->info->func;
213
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if(!base) ERR_O(call->func->pos, _("can't do partial application on a literal lambda"));
214 8 const Func f = partial_match(env, base, call->args, call->func->pos);
215
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if(!f) {
216 2 const Exp e = expand(env, call->func->type->info->func, call->args, call->func->pos);
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(e) {
218 call->args = e;
219 return partial_type(env, call);
220 }
221 2 ERR_O(call->func->pos, _("no match found for partial application"));
222 }
223 6 nspc_push_value(env->gwion->mp, env->curr);
224 6 Func_Base *const fbase = partial_base(env, f->def->base, call->args, call->func->pos);
225 6 const Stmt_List code = partial_code(env, f->def->base->args, call->func, call->args);
226 6 const Exp exp = exp_self(call);
227 6 exp->d.exp_lambda.def = new_func_def(env->gwion->mp, fbase, code);
228 6 exp->exp_type = ae_exp_lambda;
229 6 const m_bool ret = traverse_func_def(env, exp->d.exp_lambda.def);
230 6 nspc_pop_value(env->gwion->mp, env->curr);
231
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 return ret > 0 ? exp->d.exp_lambda.def->base->func->value_ref->type : NULL;
232 }
233