Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * syntax.c: |
3 | | * |
4 | | * Copyright (C) 2007-2016 David Lutterkort |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, write to the Free Software |
18 | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | | * |
20 | | * Author: David Lutterkort <dlutter@redhat.com> |
21 | | */ |
22 | | |
23 | | #include <config.h> |
24 | | |
25 | | #include <assert.h> |
26 | | #include <stdarg.h> |
27 | | #include <limits.h> |
28 | | #include <ctype.h> |
29 | | #include <glob.h> |
30 | | #include <argz.h> |
31 | | #include <sys/types.h> |
32 | | #include <sys/stat.h> |
33 | | #include <unistd.h> |
34 | | |
35 | | #include "memory.h" |
36 | | #include "syntax.h" |
37 | | #include "augeas.h" |
38 | | #include "transform.h" |
39 | | #include "errcode.h" |
40 | | |
41 | | /* Extension of source files */ |
42 | | #define AUG_EXT ".aug" |
43 | | |
44 | 0 | #define LNS_TYPE_CHECK(ctx) ((ctx)->aug->flags & AUG_TYPE_CHECK) |
45 | | |
46 | | static const char *const builtin_module = "Builtin"; |
47 | | |
48 | | static const struct type string_type = { .ref = UINT_MAX, .tag = T_STRING }; |
49 | | static const struct type regexp_type = { .ref = UINT_MAX, .tag = T_REGEXP }; |
50 | | static const struct type lens_type = { .ref = UINT_MAX, .tag = T_LENS }; |
51 | | static const struct type tree_type = { .ref = UINT_MAX, .tag = T_TREE }; |
52 | | static const struct type filter_type = { .ref = UINT_MAX, .tag = T_FILTER }; |
53 | | static const struct type transform_type = |
54 | | { .ref = UINT_MAX, .tag = T_TRANSFORM }; |
55 | | static const struct type unit_type = { .ref = UINT_MAX, .tag = T_UNIT }; |
56 | | |
57 | | const struct type *const t_string = &string_type; |
58 | | const struct type *const t_regexp = ®exp_type; |
59 | | const struct type *const t_lens = &lens_type; |
60 | | const struct type *const t_tree = &tree_type; |
61 | | const struct type *const t_filter = &filter_type; |
62 | | const struct type *const t_transform = &transform_type; |
63 | | const struct type *const t_unit = &unit_type; |
64 | | |
65 | | static const char *const type_names[] = { |
66 | | "string", "regexp", "lens", "tree", "filter", |
67 | | "transform", "function", "unit", NULL |
68 | | }; |
69 | | |
70 | | /* The anonymous identifier which we will never bind */ |
71 | | static const char anon_ident[] = "_"; |
72 | | |
73 | | static void print_value(FILE *out, struct value *v); |
74 | | |
75 | | /* The evaluation context with all loaded modules and the bindings for the |
76 | | * module we are working on in LOCAL |
77 | | */ |
78 | | struct ctx { |
79 | | const char *name; /* The module we are working on */ |
80 | | struct augeas *aug; |
81 | | struct binding *local; |
82 | | }; |
83 | | |
84 | 1.52k | static int init_fatal_exn(struct error *error) { |
85 | 1.52k | if (error->exn != NULL) |
86 | 0 | return 0; |
87 | 1.52k | error->exn = make_exn_value(ref(error->info), "Error during evaluation"); |
88 | 1.52k | if (error->exn == NULL) |
89 | 0 | return -1; |
90 | 1.52k | error->exn->exn->seen = 1; |
91 | 1.52k | error->exn->exn->error = 1; |
92 | 1.52k | error->exn->exn->lines = NULL; |
93 | 1.52k | error->exn->exn->nlines = 0; |
94 | 1.52k | error->exn->ref = REF_MAX; |
95 | 1.52k | return 0; |
96 | 1.52k | } |
97 | | |
98 | | static void format_error(struct info *info, aug_errcode_t code, |
99 | 0 | const char *format, va_list ap) { |
100 | 0 | struct error *error = info->error; |
101 | 0 | char *si = NULL, *sf = NULL, *sd = NULL; |
102 | 0 | int r; |
103 | |
|
104 | 0 | error->code = code; |
105 | | /* Only syntax errors are cumulative */ |
106 | 0 | if (code != AUG_ESYNTAX) |
107 | 0 | FREE(error->details); |
108 | |
|
109 | 0 | si = format_info(info); |
110 | 0 | r = vasprintf(&sf, format, ap); |
111 | 0 | if (r < 0) |
112 | 0 | sf = NULL; |
113 | 0 | if (error->details != NULL) { |
114 | 0 | r = xasprintf(&sd, "%s\n%s%s", error->details, |
115 | 0 | (si == NULL) ? "(no location)" : si, |
116 | 0 | (sf == NULL) ? "(no details)" : sf); |
117 | 0 | } else { |
118 | 0 | r = xasprintf(&sd, "%s%s", |
119 | 0 | (si == NULL) ? "(no location)" : si, |
120 | 0 | (sf == NULL) ? "(no details)" : sf); |
121 | 0 | } |
122 | 0 | if (r >= 0) { |
123 | 0 | free(error->details); |
124 | 0 | error->details = sd; |
125 | 0 | } |
126 | 0 | free(si); |
127 | 0 | free(sf); |
128 | 0 | } |
129 | | |
130 | 0 | void syntax_error(struct info *info, const char *format, ...) { |
131 | 0 | struct error *error = info->error; |
132 | 0 | va_list ap; |
133 | |
|
134 | 0 | if (error->code != AUG_NOERROR && error->code != AUG_ESYNTAX) |
135 | 0 | return; |
136 | | |
137 | 0 | va_start(ap, format); |
138 | 0 | format_error(info, AUG_ESYNTAX, format, ap); |
139 | 0 | va_end(ap); |
140 | 0 | } |
141 | | |
142 | 0 | void fatal_error(struct info *info, const char *format, ...) { |
143 | 0 | struct error *error = info->error; |
144 | 0 | va_list ap; |
145 | |
|
146 | 0 | if (error->code == AUG_EINTERNAL) |
147 | 0 | return; |
148 | | |
149 | 0 | va_start(ap, format); |
150 | 0 | format_error(info, AUG_EINTERNAL, format, ap); |
151 | 0 | va_end(ap); |
152 | 0 | } |
153 | | |
154 | 74.6k | static void free_param(struct param *param) { |
155 | 74.6k | if (param == NULL) |
156 | 0 | return; |
157 | 74.6k | assert(param->ref == 0); |
158 | 74.6k | unref(param->info, info); |
159 | 74.6k | unref(param->name, string); |
160 | 74.6k | unref(param->type, type); |
161 | 74.6k | free(param); |
162 | 74.6k | } |
163 | | |
164 | 123k | void free_term(struct term *term) { |
165 | 123k | if (term == NULL) |
166 | 0 | return; |
167 | 123k | assert(term->ref == 0); |
168 | 123k | switch(term->tag) { |
169 | 0 | case A_MODULE: |
170 | 0 | free(term->mname); |
171 | 0 | free(term->autoload); |
172 | 0 | unref(term->decls, term); |
173 | 0 | break; |
174 | 0 | case A_BIND: |
175 | 0 | free(term->bname); |
176 | 0 | unref(term->exp, term); |
177 | 0 | break; |
178 | 0 | case A_COMPOSE: |
179 | 0 | case A_UNION: |
180 | 0 | case A_MINUS: |
181 | 0 | case A_CONCAT: |
182 | 0 | case A_APP: |
183 | 0 | case A_LET: |
184 | 0 | unref(term->left, term); |
185 | 0 | unref(term->right, term); |
186 | 0 | break; |
187 | 48.7k | case A_VALUE: |
188 | 48.7k | unref(term->value, value); |
189 | 48.7k | break; |
190 | 48.7k | case A_IDENT: |
191 | 0 | unref(term->ident, string); |
192 | 0 | break; |
193 | 0 | case A_BRACKET: |
194 | 0 | unref(term->brexp, term); |
195 | 0 | break; |
196 | 74.6k | case A_FUNC: |
197 | 74.6k | unref(term->param, param); |
198 | 74.6k | unref(term->body, term); |
199 | 74.6k | break; |
200 | 74.6k | case A_REP: |
201 | 0 | unref(term->rexp, term); |
202 | 0 | break; |
203 | 0 | case A_TEST: |
204 | 0 | unref(term->test, term); |
205 | 0 | unref(term->result, term); |
206 | 0 | break; |
207 | 0 | default: |
208 | 0 | assert(0); |
209 | 0 | break; |
210 | 123k | } |
211 | 123k | unref(term->next, term); |
212 | 123k | unref(term->info, info); |
213 | 123k | unref(term->type, type); |
214 | 123k | free(term); |
215 | 123k | } |
216 | | |
217 | 123k | static void free_binding(struct binding *binding) { |
218 | 123k | if (binding == NULL) |
219 | 0 | return; |
220 | 123k | assert(binding->ref == 0); |
221 | 123k | unref(binding->next, binding); |
222 | 123k | unref(binding->ident, string); |
223 | 123k | unref(binding->type, type); |
224 | 123k | unref(binding->value, value); |
225 | 123k | free(binding); |
226 | 123k | } |
227 | | |
228 | 3.04k | void free_module(struct module *module) { |
229 | 3.04k | if (module == NULL) |
230 | 0 | return; |
231 | 3.04k | assert(module->ref == 0); |
232 | 3.04k | free(module->name); |
233 | 3.04k | unref(module->next, module); |
234 | 3.04k | unref(module->bindings, binding); |
235 | 3.04k | unref(module->autoload, transform); |
236 | 3.04k | free(module); |
237 | 3.04k | } |
238 | | |
239 | 74.6k | void free_type(struct type *type) { |
240 | 74.6k | if (type == NULL) |
241 | 0 | return; |
242 | 74.6k | assert(type->ref == 0); |
243 | | |
244 | 74.6k | if (type->tag == T_ARROW) { |
245 | 74.6k | unref(type->dom, type); |
246 | 74.6k | unref(type->img, type); |
247 | 74.6k | } |
248 | 74.6k | free(type); |
249 | 74.6k | } |
250 | | |
251 | 1.52k | static void free_exn(struct exn *exn) { |
252 | 1.52k | if (exn == NULL) |
253 | 0 | return; |
254 | | |
255 | 1.52k | unref(exn->info, info); |
256 | 1.52k | free(exn->message); |
257 | 1.52k | for (int i=0; i < exn->nlines; i++) { |
258 | 0 | free(exn->lines[i]); |
259 | 0 | } |
260 | 1.52k | free(exn->lines); |
261 | 1.52k | free(exn); |
262 | 1.52k | } |
263 | | |
264 | 99.0k | void free_value(struct value *v) { |
265 | 99.0k | if (v == NULL) |
266 | 0 | return; |
267 | 99.0k | assert(v->ref == 0); |
268 | | |
269 | 99.0k | switch(v->tag) { |
270 | 0 | case V_STRING: |
271 | 0 | unref(v->string, string); |
272 | 0 | break; |
273 | 0 | case V_REGEXP: |
274 | 0 | unref(v->regexp, regexp); |
275 | 0 | break; |
276 | 0 | case V_LENS: |
277 | 0 | unref(v->lens, lens); |
278 | 0 | break; |
279 | 0 | case V_TREE: |
280 | 0 | free_tree(v->origin); |
281 | 0 | break; |
282 | 0 | case V_FILTER: |
283 | 0 | unref(v->filter, filter); |
284 | 0 | break; |
285 | 0 | case V_TRANSFORM: |
286 | 0 | unref(v->transform, transform); |
287 | 0 | break; |
288 | 48.7k | case V_NATIVE: |
289 | 48.7k | if (v->native) |
290 | 48.7k | unref(v->native->type, type); |
291 | 48.7k | free(v->native); |
292 | 48.7k | break; |
293 | 48.7k | case V_CLOS: |
294 | 48.7k | unref(v->func, term); |
295 | 48.7k | unref(v->bindings, binding); |
296 | 48.7k | break; |
297 | 48.7k | case V_EXN: |
298 | 1.52k | free_exn(v->exn); |
299 | 1.52k | break; |
300 | 0 | case V_UNIT: |
301 | 0 | break; |
302 | 0 | default: |
303 | 0 | assert(0); |
304 | 99.0k | } |
305 | 99.0k | unref(v->info, info); |
306 | 99.0k | free(v); |
307 | 99.0k | } |
308 | | |
309 | | /* |
310 | | * Creation of (some) terms. Others are in parser.y |
311 | | * Reference counted arguments are now owned by the returned object, i.e. |
312 | | * the make_* functions do not increment the count. |
313 | | * Returned objects have a referece count of 1. |
314 | | */ |
315 | 74.6k | struct term *make_term(enum term_tag tag, struct info *info) { |
316 | 74.6k | struct term *term; |
317 | 74.6k | if (make_ref(term) < 0) { |
318 | 0 | unref(info, info); |
319 | 74.6k | } else { |
320 | 74.6k | term->tag = tag; |
321 | 74.6k | term->info = info; |
322 | 74.6k | } |
323 | 74.6k | return term; |
324 | 74.6k | } |
325 | | |
326 | 74.6k | struct term *make_param(char *name, struct type *type, struct info *info) { |
327 | 74.6k | struct term *term = make_term(A_FUNC, info); |
328 | 74.6k | if (term == NULL) |
329 | 0 | goto error; |
330 | 74.6k | make_ref_err(term->param); |
331 | 74.6k | term->param->info = ref(term->info); |
332 | 74.6k | make_ref_err(term->param->name); |
333 | 74.6k | term->param->name->str = name; |
334 | 74.6k | term->param->type = type; |
335 | 74.6k | return term; |
336 | 0 | error: |
337 | 0 | unref(term, term); |
338 | 0 | return NULL; |
339 | 0 | } |
340 | | |
341 | 1.52k | struct value *make_value(enum value_tag tag, struct info *info) { |
342 | 1.52k | struct value *value = NULL; |
343 | 1.52k | if (make_ref(value) < 0) { |
344 | 0 | unref(info, info); |
345 | 1.52k | } else { |
346 | 1.52k | value->tag = tag; |
347 | 1.52k | value->info = info; |
348 | 1.52k | } |
349 | 1.52k | return value; |
350 | 1.52k | } |
351 | | |
352 | 0 | struct value *make_unit(struct info *info) { |
353 | 0 | return make_value(V_UNIT, info); |
354 | 0 | } |
355 | | |
356 | | struct term *make_app_term(struct term *lambda, struct term *arg, |
357 | 0 | struct info *info) { |
358 | 0 | struct term *app = make_term(A_APP, info); |
359 | 0 | if (app == NULL) { |
360 | 0 | unref(lambda, term); |
361 | 0 | unref(arg, term); |
362 | 0 | } else { |
363 | 0 | app->left = lambda; |
364 | 0 | app->right = arg; |
365 | 0 | } |
366 | 0 | return app; |
367 | 0 | } |
368 | | |
369 | 0 | struct term *make_app_ident(char *id, struct term *arg, struct info *info) { |
370 | 0 | struct term *ident = make_term(A_IDENT, ref(info)); |
371 | 0 | ident->ident = make_string(id); |
372 | 0 | if (ident->ident == NULL) { |
373 | 0 | unref(arg, term); |
374 | 0 | unref(info, info); |
375 | 0 | unref(ident, term); |
376 | 0 | return NULL; |
377 | 0 | } |
378 | 0 | return make_app_term(ident, arg, info); |
379 | 0 | } |
380 | | |
381 | 74.6k | struct term *build_func(struct term *params, struct term *exp) { |
382 | 74.6k | assert(params->tag == A_FUNC); |
383 | 74.6k | if (params->next != NULL) |
384 | 25.9k | exp = build_func(params->next, exp); |
385 | | |
386 | 74.6k | params->body = exp; |
387 | 74.6k | params->next = NULL; |
388 | 74.6k | return params; |
389 | 74.6k | } |
390 | | |
391 | | /* Ownership is taken as needed */ |
392 | 48.7k | static struct value *make_closure(struct term *func, struct binding *bnds) { |
393 | 48.7k | struct value *v = NULL; |
394 | 48.7k | if (make_ref(v) == 0) { |
395 | 48.7k | v->tag = V_CLOS; |
396 | 48.7k | v->info = ref(func->info); |
397 | 48.7k | v->func = ref(func); |
398 | 48.7k | v->bindings = ref(bnds); |
399 | 48.7k | } |
400 | 48.7k | return v; |
401 | 48.7k | } |
402 | | |
403 | | struct value *make_exn_value(struct info *info, |
404 | 1.52k | const char *format, ...) { |
405 | 1.52k | va_list ap; |
406 | 1.52k | int r; |
407 | 1.52k | struct value *v; |
408 | 1.52k | char *message; |
409 | | |
410 | 1.52k | va_start(ap, format); |
411 | 1.52k | r = vasprintf(&message, format, ap); |
412 | 1.52k | va_end(ap); |
413 | 1.52k | if (r == -1) |
414 | 0 | return NULL; |
415 | | |
416 | 1.52k | v = make_value(V_EXN, ref(info)); |
417 | 1.52k | if (ALLOC(v->exn) < 0) |
418 | 0 | return info->error->exn; |
419 | 1.52k | v->exn->info = info; |
420 | 1.52k | v->exn->message = message; |
421 | | |
422 | 1.52k | return v; |
423 | 1.52k | } |
424 | | |
425 | 0 | void exn_add_lines(struct value *v, int nlines, ...) { |
426 | 0 | assert(v->tag == V_EXN); |
427 | | |
428 | 0 | va_list ap; |
429 | 0 | if (REALLOC_N(v->exn->lines, v->exn->nlines + nlines) == -1) |
430 | 0 | return; |
431 | 0 | va_start(ap, nlines); |
432 | 0 | for (int i=0; i < nlines; i++) { |
433 | 0 | char *line = va_arg(ap, char *); |
434 | 0 | v->exn->lines[v->exn->nlines + i] = line; |
435 | 0 | } |
436 | 0 | va_end(ap); |
437 | 0 | v->exn->nlines += nlines; |
438 | 0 | } |
439 | | |
440 | 0 | void exn_printf_line(struct value *exn, const char *format, ...) { |
441 | 0 | va_list ap; |
442 | 0 | int r; |
443 | 0 | char *line; |
444 | |
|
445 | 0 | va_start(ap, format); |
446 | 0 | r = vasprintf(&line, format, ap); |
447 | 0 | va_end(ap); |
448 | 0 | if (r >= 0) |
449 | 0 | exn_add_lines(exn, 1, line); |
450 | 0 | } |
451 | | |
452 | | /* |
453 | | * Modules |
454 | | */ |
455 | | static int load_module(struct augeas *aug, const char *name); |
456 | | static char *module_basename(const char *modname); |
457 | | |
458 | 3.04k | struct module *module_create(const char *name) { |
459 | 3.04k | struct module *module; |
460 | 3.04k | make_ref(module); |
461 | 3.04k | module->name = strdup(name); |
462 | 3.04k | return module; |
463 | 3.04k | } |
464 | | |
465 | 0 | static struct module *module_find(struct module *module, const char *name) { |
466 | 0 | list_for_each(e, module) { |
467 | 0 | if (STRCASEEQ(e->name, name)) |
468 | 0 | return e; |
469 | 0 | } |
470 | 0 | return NULL; |
471 | 0 | } |
472 | | |
473 | 0 | static struct binding *bnd_lookup(struct binding *bindings, const char *name) { |
474 | 0 | list_for_each(b, bindings) { |
475 | 0 | if (STREQ(b->ident->str, name)) |
476 | 0 | return b; |
477 | 0 | } |
478 | 0 | return NULL; |
479 | 0 | } |
480 | | |
481 | 0 | static char *modname_of_qname(const char *qname) { |
482 | 0 | char *dot = strchr(qname, '.'); |
483 | 0 | if (dot == NULL) |
484 | 0 | return NULL; |
485 | | |
486 | 0 | return strndup(qname, dot - qname); |
487 | 0 | } |
488 | | |
489 | | static int lookup_internal(struct augeas *aug, const char *ctx_modname, |
490 | 0 | const char *name, struct binding **bnd) { |
491 | 0 | char *modname = modname_of_qname(name); |
492 | |
|
493 | 0 | *bnd = NULL; |
494 | |
|
495 | 0 | if (modname == NULL) { |
496 | 0 | struct module *builtin = |
497 | 0 | module_find(aug->modules, builtin_module); |
498 | 0 | assert(builtin != NULL); |
499 | 0 | *bnd = bnd_lookup(builtin->bindings, name); |
500 | 0 | return 0; |
501 | 0 | } |
502 | | |
503 | 0 | qual_lookup: |
504 | 0 | list_for_each(module, aug->modules) { |
505 | 0 | if (STRCASEEQ(module->name, modname)) { |
506 | 0 | *bnd = bnd_lookup(module->bindings, name + strlen(modname) + 1); |
507 | 0 | free(modname); |
508 | 0 | return 0; |
509 | 0 | } |
510 | 0 | } |
511 | | /* Try to load the module */ |
512 | 0 | if (streqv(modname, ctx_modname)) { |
513 | 0 | free(modname); |
514 | 0 | return 0; |
515 | 0 | } |
516 | 0 | int loaded = load_module(aug, modname) == 0; |
517 | 0 | if (loaded) |
518 | 0 | goto qual_lookup; |
519 | | |
520 | 0 | free(modname); |
521 | 0 | return -1; |
522 | 0 | } |
523 | | |
524 | 0 | struct lens *lens_lookup(struct augeas *aug, const char *qname) { |
525 | 0 | struct binding *bnd = NULL; |
526 | |
|
527 | 0 | if (lookup_internal(aug, NULL, qname, &bnd) < 0) |
528 | 0 | return NULL; |
529 | 0 | if (bnd == NULL || bnd->value->tag != V_LENS) |
530 | 0 | return NULL; |
531 | 0 | return bnd->value->lens; |
532 | 0 | } |
533 | | |
534 | | static struct binding *ctx_lookup_bnd(struct info *info, |
535 | 0 | struct ctx *ctx, const char *name) { |
536 | 0 | struct binding *b = NULL; |
537 | 0 | int nlen = strlen(ctx->name); |
538 | |
|
539 | 0 | if (STREQLEN(ctx->name, name, nlen) && name[nlen] == '.') |
540 | 0 | name += nlen + 1; |
541 | |
|
542 | 0 | b = bnd_lookup(ctx->local, name); |
543 | 0 | if (b != NULL) |
544 | 0 | return b; |
545 | | |
546 | 0 | if (ctx->aug != NULL) { |
547 | 0 | int r; |
548 | 0 | r = lookup_internal(ctx->aug, ctx->name, name, &b); |
549 | 0 | if (r == 0) |
550 | 0 | return b; |
551 | 0 | char *modname = modname_of_qname(name); |
552 | 0 | syntax_error(info, "Could not load module %s for %s", |
553 | 0 | modname, name); |
554 | 0 | free(modname); |
555 | 0 | return NULL; |
556 | 0 | } |
557 | 0 | return NULL; |
558 | 0 | } |
559 | | |
560 | | static struct value *ctx_lookup(struct info *info, |
561 | 0 | struct ctx *ctx, struct string *ident) { |
562 | 0 | struct binding *b = ctx_lookup_bnd(info, ctx, ident->str); |
563 | 0 | return b == NULL ? NULL : b->value; |
564 | 0 | } |
565 | | |
566 | | static struct type *ctx_lookup_type(struct info *info, |
567 | 0 | struct ctx *ctx, struct string *ident) { |
568 | 0 | struct binding *b = ctx_lookup_bnd(info, ctx, ident->str); |
569 | 0 | return b == NULL ? NULL : b->type; |
570 | 0 | } |
571 | | |
572 | | /* Takes ownership as needed */ |
573 | | static struct binding *bind_type(struct binding **bnds, |
574 | 48.7k | const char *name, struct type *type) { |
575 | 48.7k | struct binding *binding; |
576 | | |
577 | 48.7k | if (STREQ(name, anon_ident)) |
578 | 0 | return NULL; |
579 | 48.7k | make_ref(binding); |
580 | 48.7k | make_ref(binding->ident); |
581 | 48.7k | binding->ident->str = strdup(name); |
582 | 48.7k | binding->type = ref(type); |
583 | 48.7k | list_cons(*bnds, binding); |
584 | | |
585 | 48.7k | return binding; |
586 | 48.7k | } |
587 | | |
588 | | /* Takes ownership as needed */ |
589 | | static void bind_param(struct binding **bnds, struct param *param, |
590 | 74.6k | struct value *v) { |
591 | 74.6k | struct binding *b; |
592 | 74.6k | make_ref(b); |
593 | 74.6k | b->ident = ref(param->name); |
594 | 74.6k | b->type = ref(param->type); |
595 | 74.6k | b->value = ref(v); |
596 | 74.6k | ref(*bnds); |
597 | 74.6k | list_cons(*bnds, b); |
598 | 74.6k | } |
599 | | |
600 | 74.6k | static void unbind_param(struct binding **bnds, ATTRIBUTE_UNUSED struct param *param) { |
601 | 74.6k | struct binding *b = *bnds; |
602 | 74.6k | assert(b->ident == param->name); |
603 | 74.6k | assert(b->next != *bnds); |
604 | 74.6k | *bnds = b->next; |
605 | 74.6k | unref(b, binding); |
606 | 74.6k | } |
607 | | |
608 | | /* Takes ownership of VALUE */ |
609 | | static void bind(struct binding **bnds, |
610 | 48.7k | const char *name, struct type *type, struct value *value) { |
611 | 48.7k | struct binding *b = NULL; |
612 | | |
613 | 48.7k | if (STRNEQ(name, anon_ident)) { |
614 | 48.7k | b = bind_type(bnds, name, type); |
615 | 48.7k | b->value = ref(value); |
616 | 48.7k | } |
617 | 48.7k | } |
618 | | |
619 | | /* |
620 | | * Some debug printing |
621 | | */ |
622 | | |
623 | | static char *type_string(struct type *t); |
624 | | |
625 | 0 | static void dump_bindings(struct binding *bnds) { |
626 | 0 | list_for_each(b, bnds) { |
627 | 0 | char *st = type_string(b->type); |
628 | 0 | fprintf(stderr, " %s: %s", b->ident->str, st); |
629 | 0 | fprintf(stderr, " = "); |
630 | 0 | print_value(stderr, b->value); |
631 | 0 | fputc('\n', stderr); |
632 | 0 | free(st); |
633 | 0 | } |
634 | 0 | } |
635 | | |
636 | 0 | static void dump_module(struct module *module) { |
637 | 0 | if (module == NULL) |
638 | 0 | return; |
639 | 0 | fprintf(stderr, "Module %s\n:", module->name); |
640 | 0 | dump_bindings(module->bindings); |
641 | 0 | dump_module(module->next); |
642 | 0 | } |
643 | | |
644 | | ATTRIBUTE_UNUSED |
645 | 0 | static void dump_ctx(struct ctx *ctx) { |
646 | 0 | fprintf(stderr, "Context: %s\n", ctx->name); |
647 | 0 | dump_bindings(ctx->local); |
648 | 0 | if (ctx->aug != NULL) { |
649 | 0 | list_for_each(m, ctx->aug->modules) |
650 | 0 | dump_module(m); |
651 | 0 | } |
652 | 0 | } |
653 | | |
654 | | /* |
655 | | * Values |
656 | | */ |
657 | 0 | void print_tree_braces(FILE *out, int indent, struct tree *tree) { |
658 | 0 | if (tree == NULL) { |
659 | 0 | fprintf(out, "(null tree)\n"); |
660 | 0 | return; |
661 | 0 | } |
662 | 0 | list_for_each(t, tree) { |
663 | 0 | for (int i=0; i < indent; i++) fputc(' ', out); |
664 | 0 | fprintf(out, "{ "); |
665 | 0 | if (t->label != NULL) |
666 | 0 | fprintf(out, "\"%s\"", t->label); |
667 | 0 | if (t->value != NULL) |
668 | 0 | fprintf(out, " = \"%s\"", t->value); |
669 | 0 | if (t->children != NULL) { |
670 | 0 | fputc('\n', out); |
671 | 0 | print_tree_braces(out, indent + 2, t->children); |
672 | 0 | for (int i=0; i < indent; i++) fputc(' ', out); |
673 | 0 | } else { |
674 | 0 | fputc(' ', out); |
675 | 0 | } |
676 | 0 | fprintf(out, "}\n"); |
677 | 0 | } |
678 | 0 | } |
679 | | |
680 | 0 | static void print_value(FILE *out, struct value *v) { |
681 | 0 | if (v == NULL) { |
682 | 0 | fprintf(out, "<null>"); |
683 | 0 | return; |
684 | 0 | } |
685 | | |
686 | 0 | switch(v->tag) { |
687 | 0 | case V_STRING: |
688 | 0 | fprintf(out, "\"%s\"", v->string->str); |
689 | 0 | break; |
690 | 0 | case V_REGEXP: |
691 | 0 | fprintf(out, "/%s/", v->regexp->pattern->str); |
692 | 0 | break; |
693 | 0 | case V_LENS: |
694 | 0 | fprintf(out, "<lens:"); |
695 | 0 | print_info(out, v->lens->info); |
696 | 0 | fprintf(out, ">"); |
697 | 0 | break; |
698 | 0 | case V_TREE: |
699 | 0 | print_tree_braces(out, 0, v->origin); |
700 | 0 | break; |
701 | 0 | case V_FILTER: |
702 | 0 | fprintf(out, "<filter:"); |
703 | 0 | list_for_each(f, v->filter) { |
704 | 0 | fprintf(out, "%c%s%c", f->include ? '+' : '-', f->glob->str, |
705 | 0 | (f->next != NULL) ? ':' : '>'); |
706 | 0 | } |
707 | 0 | break; |
708 | 0 | case V_TRANSFORM: |
709 | 0 | fprintf(out, "<transform:"); |
710 | 0 | print_info(out, v->transform->lens->info); |
711 | 0 | fprintf(out, ">"); |
712 | 0 | break; |
713 | 0 | case V_NATIVE: |
714 | 0 | fprintf(out, "<native:"); |
715 | 0 | print_info(out, v->info); |
716 | 0 | fprintf(out, ">"); |
717 | 0 | break; |
718 | 0 | case V_CLOS: |
719 | 0 | fprintf(out, "<closure:"); |
720 | 0 | print_info(out, v->func->info); |
721 | 0 | fprintf(out, ">"); |
722 | 0 | break; |
723 | 0 | case V_EXN: |
724 | 0 | if (! v->exn->seen) { |
725 | 0 | print_info(out, v->exn->info); |
726 | 0 | fprintf(out, "exception: %s\n", v->exn->message); |
727 | 0 | for (int i=0; i < v->exn->nlines; i++) { |
728 | 0 | fprintf(out, " %s\n", v->exn->lines[i]); |
729 | 0 | } |
730 | 0 | v->exn->seen = 1; |
731 | 0 | } |
732 | 0 | break; |
733 | 0 | case V_UNIT: |
734 | 0 | fprintf(out, "()"); |
735 | 0 | break; |
736 | 0 | default: |
737 | 0 | assert(0); |
738 | 0 | break; |
739 | 0 | } |
740 | 0 | } |
741 | | |
742 | 0 | static int value_equal(struct value *v1, struct value *v2) { |
743 | 0 | if (v1 == NULL && v2 == NULL) |
744 | 0 | return 1; |
745 | 0 | if (v1 == NULL || v2 == NULL) |
746 | 0 | return 0; |
747 | 0 | if (v1->tag != v2->tag) |
748 | 0 | return 0; |
749 | 0 | switch (v1->tag) { |
750 | 0 | case V_STRING: |
751 | 0 | return STREQ(v1->string->str, v2->string->str); |
752 | 0 | break; |
753 | 0 | case V_REGEXP: |
754 | | // FIXME: Should probably build FA's and compare them |
755 | 0 | return STREQ(v1->regexp->pattern->str, v2->regexp->pattern->str); |
756 | 0 | break; |
757 | 0 | case V_LENS: |
758 | 0 | return v1->lens == v2->lens; |
759 | 0 | break; |
760 | 0 | case V_TREE: |
761 | 0 | return tree_equal(v1->origin->children, v2->origin->children); |
762 | 0 | break; |
763 | 0 | case V_FILTER: |
764 | 0 | return v1->filter == v2->filter; |
765 | 0 | break; |
766 | 0 | case V_TRANSFORM: |
767 | 0 | return v1->transform == v2->transform; |
768 | 0 | break; |
769 | 0 | case V_NATIVE: |
770 | 0 | return v1->native == v2->native; |
771 | 0 | break; |
772 | 0 | case V_CLOS: |
773 | 0 | return v1->func == v2->func && v1->bindings == v2->bindings; |
774 | 0 | break; |
775 | 0 | default: |
776 | 0 | assert(0); |
777 | 0 | abort(); |
778 | 0 | break; |
779 | 0 | } |
780 | 0 | } |
781 | | |
782 | | /* |
783 | | * Types |
784 | | */ |
785 | 74.6k | struct type *make_arrow_type(struct type *dom, struct type *img) { |
786 | 74.6k | struct type *type; |
787 | 74.6k | make_ref(type); |
788 | 74.6k | type->tag = T_ARROW; |
789 | 74.6k | type->dom = ref(dom); |
790 | 74.6k | type->img = ref(img); |
791 | 74.6k | return type; |
792 | 74.6k | } |
793 | | |
794 | 123k | struct type *make_base_type(enum type_tag tag) { |
795 | 123k | if (tag == T_STRING) |
796 | 44.1k | return (struct type *) t_string; |
797 | 79.2k | else if (tag == T_REGEXP) |
798 | 13.7k | return (struct type *) t_regexp; |
799 | 65.5k | else if (tag == T_LENS) |
800 | 33.5k | return (struct type *) t_lens; |
801 | 32.0k | else if (tag == T_TREE) |
802 | 21.3k | return (struct type *) t_tree; |
803 | 10.6k | else if (tag == T_FILTER) |
804 | 4.57k | return (struct type *) t_filter; |
805 | 6.09k | else if (tag == T_TRANSFORM) |
806 | 1.52k | return (struct type *) t_transform; |
807 | 4.57k | else if (tag == T_UNIT) |
808 | 4.57k | return (struct type *) t_unit; |
809 | 0 | assert(0); |
810 | 0 | abort(); |
811 | 0 | } |
812 | | |
813 | 0 | static const char *type_name(struct type *t) { |
814 | 0 | for (int i = 0; type_names[i] != NULL; i++) |
815 | 0 | if (i == t->tag) |
816 | 0 | return type_names[i]; |
817 | 0 | assert(0); |
818 | 0 | abort(); |
819 | 0 | } |
820 | | |
821 | 0 | static char *type_string(struct type *t) { |
822 | 0 | if (t->tag == T_ARROW) { |
823 | 0 | char *s = NULL; |
824 | 0 | int r; |
825 | 0 | char *sd = type_string(t->dom); |
826 | 0 | char *si = type_string(t->img); |
827 | 0 | if (t->dom->tag == T_ARROW) |
828 | 0 | r = asprintf(&s, "(%s) -> %s", sd, si); |
829 | 0 | else |
830 | 0 | r = asprintf(&s, "%s -> %s", sd, si); |
831 | 0 | free(sd); |
832 | 0 | free(si); |
833 | 0 | return (r == -1) ? NULL : s; |
834 | 0 | } else { |
835 | 0 | return strdup(type_name(t)); |
836 | 0 | } |
837 | 0 | } |
838 | | |
839 | | /* Decide whether T1 is a subtype of T2. The only subtype relations are |
840 | | * T_STRING <: T_REGEXP and the usual subtyping of functions based on |
841 | | * comparing domains/images |
842 | | * |
843 | | * Return 1 if T1 is a subtype of T2, 0 otherwise |
844 | | */ |
845 | 0 | static int subtype(struct type *t1, struct type *t2) { |
846 | 0 | if (t1 == t2) |
847 | 0 | return 1; |
848 | | /* We only promote T_STRING => T_REGEXP, no automatic conversion |
849 | | of strings/regexps to lenses (yet) */ |
850 | 0 | if (t1->tag == T_STRING) |
851 | 0 | return (t2->tag == T_STRING || t2->tag == T_REGEXP); |
852 | 0 | if (t1->tag == T_ARROW && t2->tag == T_ARROW) { |
853 | 0 | return subtype(t2->dom, t1->dom) |
854 | 0 | && subtype(t1->img, t2->img); |
855 | 0 | } |
856 | 0 | return t1->tag == t2->tag; |
857 | 0 | } |
858 | | |
859 | 0 | static int type_equal(struct type *t1, struct type *t2) { |
860 | 0 | return (t1 == t2) || (subtype(t1, t2) && subtype(t2, t1)); |
861 | 0 | } |
862 | | |
863 | | /* Return a type T with subtype(T, T1) && subtype(T, T2) */ |
864 | | static struct type *type_meet(struct type *t1, struct type *t2); |
865 | | |
866 | | /* Return a type T with subtype(T1, T) && subtype(T2, T) */ |
867 | 0 | static struct type *type_join(struct type *t1, struct type *t2) { |
868 | 0 | if (t1->tag == T_STRING) { |
869 | 0 | if (t2->tag == T_STRING) |
870 | 0 | return ref(t1); |
871 | 0 | else if (t2->tag == T_REGEXP) |
872 | 0 | return ref(t2); |
873 | 0 | } else if (t1->tag == T_REGEXP) { |
874 | 0 | if (t2->tag == T_STRING || t2->tag == T_REGEXP) |
875 | 0 | return ref(t1); |
876 | 0 | } else if (t1->tag == T_ARROW) { |
877 | 0 | if (t2->tag != T_ARROW) |
878 | 0 | return NULL; |
879 | 0 | struct type *dom = type_meet(t1->dom, t2->dom); |
880 | 0 | struct type *img = type_join(t1->img, t2->img); |
881 | 0 | if (dom == NULL || img == NULL) { |
882 | 0 | unref(dom, type); |
883 | 0 | unref(img, type); |
884 | 0 | return NULL; |
885 | 0 | } |
886 | 0 | return make_arrow_type(dom, img); |
887 | 0 | } else if (type_equal(t1, t2)) { |
888 | 0 | return ref(t1); |
889 | 0 | } |
890 | 0 | return NULL; |
891 | 0 | } |
892 | | |
893 | | /* Return a type T with subtype(T, T1) && subtype(T, T2) */ |
894 | 0 | static struct type *type_meet(struct type *t1, struct type *t2) { |
895 | 0 | if (t1->tag == T_STRING) { |
896 | 0 | if (t2->tag == T_STRING || t2->tag == T_REGEXP) |
897 | 0 | return ref(t1); |
898 | 0 | } else if (t1->tag == T_REGEXP) { |
899 | 0 | if (t2->tag == T_STRING || t2->tag == T_REGEXP) |
900 | 0 | return ref(t2); |
901 | 0 | } else if (t1->tag == T_ARROW) { |
902 | 0 | if (t2->tag != T_ARROW) |
903 | 0 | return NULL; |
904 | 0 | struct type *dom = type_join(t1->dom, t2->dom); |
905 | 0 | struct type *img = type_meet(t1->img, t2->img); |
906 | 0 | if (dom == NULL || img == NULL) { |
907 | 0 | unref(dom, type); |
908 | 0 | unref(img, type); |
909 | 0 | return NULL; |
910 | 0 | } |
911 | 0 | return make_arrow_type(dom, img); |
912 | 0 | } else if (type_equal(t1, t2)) { |
913 | 0 | return ref(t1); |
914 | 0 | } |
915 | 0 | return NULL; |
916 | 0 | } |
917 | | |
918 | 0 | static struct type *value_type(struct value *v) { |
919 | 0 | switch(v->tag) { |
920 | 0 | case V_STRING: |
921 | 0 | return make_base_type(T_STRING); |
922 | 0 | case V_REGEXP: |
923 | 0 | return make_base_type(T_REGEXP); |
924 | 0 | case V_LENS: |
925 | 0 | return make_base_type(T_LENS); |
926 | 0 | case V_TREE: |
927 | 0 | return make_base_type(T_TREE); |
928 | 0 | case V_FILTER: |
929 | 0 | return make_base_type(T_FILTER); |
930 | 0 | case V_TRANSFORM: |
931 | 0 | return make_base_type(T_TRANSFORM); |
932 | 0 | case V_UNIT: |
933 | 0 | return make_base_type(T_UNIT); |
934 | 0 | case V_NATIVE: |
935 | 0 | return ref(v->native->type); |
936 | 0 | case V_CLOS: |
937 | 0 | return ref(v->func->type); |
938 | 0 | case V_EXN: /* Fail on exceptions */ |
939 | 0 | default: |
940 | 0 | assert(0); |
941 | 0 | abort(); |
942 | 0 | } |
943 | 0 | } |
944 | | |
945 | | /* Coerce V to the type T. Currently, only T_STRING can be coerced to |
946 | | * T_REGEXP. Returns a value that is owned by the caller. Trying to perform |
947 | | * an impossible coercion is a fatal error. Receives ownership of V. |
948 | | */ |
949 | 0 | static struct value *coerce(struct value *v, struct type *t) { |
950 | 0 | struct type *vt = value_type(v); |
951 | 0 | if (type_equal(vt, t)) { |
952 | 0 | unref(vt, type); |
953 | 0 | return v; |
954 | 0 | } |
955 | 0 | if (vt->tag == T_STRING && t->tag == T_REGEXP) { |
956 | 0 | struct value *rxp = make_value(V_REGEXP, ref(v->info)); |
957 | 0 | rxp->regexp = make_regexp_literal(v->info, v->string->str); |
958 | 0 | if (rxp->regexp == NULL) { |
959 | 0 | report_error(v->info->error, AUG_ENOMEM, NULL); |
960 | 0 | }; |
961 | 0 | unref(v, value); |
962 | 0 | unref(vt, type); |
963 | 0 | return rxp; |
964 | 0 | } |
965 | 0 | return make_exn_value(v->info, "Type %s can not be coerced to %s", |
966 | 0 | type_name(vt), type_name(t)); |
967 | 0 | } |
968 | | |
969 | | /* Return one of the expected types (passed as ...). |
970 | | Does not give ownership of the returned type */ |
971 | | static struct type *expect_types_arr(struct info *info, |
972 | | struct type *act, |
973 | 0 | int ntypes, struct type *allowed[]) { |
974 | 0 | struct type *result = NULL; |
975 | |
|
976 | 0 | for (int i=0; i < ntypes; i++) { |
977 | 0 | if (subtype(act, allowed[i])) { |
978 | 0 | result = allowed[i]; |
979 | 0 | break; |
980 | 0 | } |
981 | 0 | } |
982 | 0 | if (result == NULL) { |
983 | 0 | int len = 0; |
984 | 0 | for (int i=0; i < ntypes; i++) { |
985 | 0 | len += strlen(type_name(allowed[i])); |
986 | 0 | } |
987 | 0 | len += (ntypes - 1) * 4 + 1; |
988 | 0 | char *allowed_names; |
989 | 0 | if (ALLOC_N(allowed_names, len) < 0) |
990 | 0 | return NULL; |
991 | 0 | for (int i=0; i < ntypes; i++) { |
992 | 0 | if (i > 0) |
993 | 0 | strcat(allowed_names, (i == ntypes - 1) ? ", or " : ", "); |
994 | 0 | strcat(allowed_names, type_name(allowed[i])); |
995 | 0 | } |
996 | 0 | char *act_str = type_string(act); |
997 | 0 | syntax_error(info, "type error: expected %s but found %s", |
998 | 0 | allowed_names, act_str); |
999 | 0 | free(act_str); |
1000 | 0 | free(allowed_names); |
1001 | 0 | } |
1002 | 0 | return result; |
1003 | 0 | } |
1004 | | |
1005 | | static struct type *expect_types(struct info *info, |
1006 | 0 | struct type *act, int ntypes, ...) { |
1007 | 0 | va_list ap; |
1008 | 0 | struct type *allowed[ntypes]; |
1009 | |
|
1010 | 0 | va_start(ap, ntypes); |
1011 | 0 | for (int i=0; i < ntypes; i++) |
1012 | 0 | allowed[i] = va_arg(ap, struct type *); |
1013 | 0 | va_end(ap); |
1014 | 0 | return expect_types_arr(info, act, ntypes, allowed); |
1015 | 0 | } |
1016 | | |
1017 | | static struct value *apply(struct term *app, struct ctx *ctx); |
1018 | | |
1019 | | typedef struct value *(*impl0)(struct info *); |
1020 | | typedef struct value *(*impl1)(struct info *, struct value *); |
1021 | | typedef struct value *(*impl2)(struct info *, struct value *, struct value *); |
1022 | | typedef struct value *(*impl3)(struct info *, struct value *, struct value *, |
1023 | | struct value *); |
1024 | | typedef struct value *(*impl4)(struct info *, struct value *, struct value *, |
1025 | | struct value *, struct value *); |
1026 | | typedef struct value *(*impl5)(struct info *, struct value *, struct value *, |
1027 | | struct value *, struct value *, struct value *); |
1028 | | |
1029 | | static struct value *native_call(struct info *info, |
1030 | 0 | struct native *func, struct ctx *ctx) { |
1031 | 0 | struct value *argv[func->argc + 1]; |
1032 | 0 | struct binding *b = ctx->local; |
1033 | |
|
1034 | 0 | for (int i = func->argc - 1; i >= 0; i--) { |
1035 | 0 | argv[i] = b->value; |
1036 | 0 | b = b->next; |
1037 | 0 | } |
1038 | 0 | argv[func->argc] = NULL; |
1039 | |
|
1040 | 0 | return func->impl(info, argv); |
1041 | 0 | } |
1042 | | |
1043 | 0 | static void type_error1(struct info *info, const char *msg, struct type *type) { |
1044 | 0 | char *s = type_string(type); |
1045 | 0 | syntax_error(info, "Type error: "); |
1046 | 0 | syntax_error(info, msg, s); |
1047 | 0 | free(s); |
1048 | 0 | } |
1049 | | |
1050 | | static void type_error2(struct info *info, const char *msg, |
1051 | 0 | struct type *type1, struct type *type2) { |
1052 | 0 | char *s1 = type_string(type1); |
1053 | 0 | char *s2 = type_string(type2); |
1054 | 0 | syntax_error(info, "Type error: "); |
1055 | 0 | syntax_error(info, msg, s1, s2); |
1056 | 0 | free(s1); |
1057 | 0 | free(s2); |
1058 | 0 | } |
1059 | | |
1060 | | static void type_error_binop(struct info *info, const char *opname, |
1061 | 0 | struct type *type1, struct type *type2) { |
1062 | 0 | char *s1 = type_string(type1); |
1063 | 0 | char *s2 = type_string(type2); |
1064 | 0 | syntax_error(info, "Type error: "); |
1065 | 0 | syntax_error(info, "%s of %s and %s is not possible", opname, s1, s2); |
1066 | 0 | free(s1); |
1067 | 0 | free(s2); |
1068 | 0 | } |
1069 | | |
1070 | | static int check_exp(struct term *term, struct ctx *ctx); |
1071 | | |
1072 | | static struct type *require_exp_type(struct term *term, struct ctx *ctx, |
1073 | 0 | int ntypes, struct type *allowed[]) { |
1074 | 0 | int r = 1; |
1075 | |
|
1076 | 0 | if (term->type == NULL) { |
1077 | 0 | r = check_exp(term, ctx); |
1078 | 0 | if (! r) |
1079 | 0 | return NULL; |
1080 | 0 | } |
1081 | | |
1082 | 0 | return expect_types_arr(term->info, term->type, ntypes, allowed); |
1083 | 0 | } |
1084 | | |
1085 | 0 | static int check_compose(struct term *term, struct ctx *ctx) { |
1086 | 0 | struct type *tl = NULL, *tr = NULL; |
1087 | |
|
1088 | 0 | if (! check_exp(term->left, ctx)) |
1089 | 0 | return 0; |
1090 | 0 | tl = term->left->type; |
1091 | |
|
1092 | 0 | if (tl->tag == T_ARROW) { |
1093 | | /* Composition of functions f: a -> b and g: c -> d is defined as |
1094 | | (f . g) x = g (f x) and is type correct if b <: c yielding a |
1095 | | function with type a -> d */ |
1096 | 0 | if (! check_exp(term->right, ctx)) |
1097 | 0 | return 0; |
1098 | 0 | tr = term->right->type; |
1099 | 0 | if (tr->tag != T_ARROW) |
1100 | 0 | goto print_error; |
1101 | 0 | if (! subtype(tl->img, tr->dom)) |
1102 | 0 | goto print_error; |
1103 | 0 | term->type = make_arrow_type(tl->dom, tr->img); |
1104 | 0 | } else if (tl->tag == T_UNIT) { |
1105 | 0 | if (! check_exp(term->right, ctx)) |
1106 | 0 | return 0; |
1107 | 0 | term->type = ref(term->right->type); |
1108 | 0 | } else { |
1109 | 0 | goto print_error; |
1110 | 0 | } |
1111 | 0 | return 1; |
1112 | 0 | print_error: |
1113 | 0 | type_error_binop(term->info, |
1114 | 0 | "composition", term->left->type, term->right->type); |
1115 | 0 | return 0; |
1116 | 0 | } |
1117 | | |
1118 | | static int check_binop(const char *opname, struct term *term, |
1119 | 0 | struct ctx *ctx, int ntypes, ...) { |
1120 | 0 | va_list ap; |
1121 | 0 | struct type *allowed[ntypes]; |
1122 | 0 | struct type *tl = NULL, *tr = NULL; |
1123 | |
|
1124 | 0 | va_start(ap, ntypes); |
1125 | 0 | for (int i=0; i < ntypes; i++) |
1126 | 0 | allowed[i] = va_arg(ap, struct type *); |
1127 | 0 | va_end(ap); |
1128 | |
|
1129 | 0 | tl = require_exp_type(term->left, ctx, ntypes, allowed); |
1130 | 0 | if (tl == NULL) |
1131 | 0 | return 0; |
1132 | | |
1133 | 0 | tr = require_exp_type(term->right, ctx, ntypes, allowed); |
1134 | 0 | if (tr == NULL) |
1135 | 0 | return 0; |
1136 | | |
1137 | 0 | term->type = type_join(tl, tr); |
1138 | 0 | if (term->type == NULL) |
1139 | 0 | goto print_error; |
1140 | 0 | return 1; |
1141 | 0 | print_error: |
1142 | 0 | type_error_binop(term->info, opname, term->left->type, term->right->type); |
1143 | 0 | return 0; |
1144 | 0 | } |
1145 | | |
1146 | 48.7k | static int check_value(struct term *term) { |
1147 | 48.7k | const char *msg; |
1148 | 48.7k | struct value *v = term->value; |
1149 | | |
1150 | 48.7k | if (v->tag == V_REGEXP) { |
1151 | | /* The only literal that needs checking are regular expressions, |
1152 | | where we need to make sure the regexp is syntactically |
1153 | | correct */ |
1154 | 0 | if (regexp_check(v->regexp, &msg) == -1) { |
1155 | 0 | syntax_error(v->info, "Invalid regular expression: %s", msg); |
1156 | 0 | return 0; |
1157 | 0 | } |
1158 | 0 | term->type = make_base_type(T_REGEXP); |
1159 | 48.7k | } else if (v->tag == V_EXN) { |
1160 | | /* Exceptions can't be typed */ |
1161 | 0 | return 0; |
1162 | 48.7k | } else { |
1163 | | /* There are cases where we generate values internally, and |
1164 | | those have their type already set; we don't want to |
1165 | | overwrite that */ |
1166 | 48.7k | if (term->type == NULL) { |
1167 | 0 | term->type = value_type(v); |
1168 | 0 | } |
1169 | 48.7k | } |
1170 | 48.7k | return 1; |
1171 | 48.7k | } |
1172 | | |
1173 | | /* Return 1 if TERM passes, 0 otherwise */ |
1174 | 123k | static int check_exp(struct term *term, struct ctx *ctx) { |
1175 | 123k | int result = 1; |
1176 | 123k | assert(term->type == NULL || term->tag == A_VALUE || term->ref > 1); |
1177 | 123k | if (term->type != NULL && term->tag != A_VALUE) |
1178 | 0 | return 1; |
1179 | | |
1180 | 123k | switch (term->tag) { |
1181 | 0 | case A_UNION: |
1182 | 0 | result = check_binop("union", term, ctx, 2, t_regexp, t_lens); |
1183 | 0 | break; |
1184 | 0 | case A_MINUS: |
1185 | 0 | result = check_binop("minus", term, ctx, 1, t_regexp); |
1186 | 0 | break; |
1187 | 0 | case A_COMPOSE: |
1188 | 0 | result = check_compose(term, ctx); |
1189 | 0 | break; |
1190 | 0 | case A_CONCAT: |
1191 | 0 | result = check_binop("concatenation", term, ctx, |
1192 | 0 | 4, t_string, t_regexp, t_lens, t_filter); |
1193 | 0 | break; |
1194 | 0 | case A_LET: |
1195 | 0 | { |
1196 | 0 | result = check_exp(term->right, ctx); |
1197 | 0 | if (result) { |
1198 | 0 | struct term *func = term->left; |
1199 | 0 | assert(func->tag == A_FUNC); |
1200 | 0 | assert(func->param->type == NULL); |
1201 | 0 | func->param->type = ref(term->right->type); |
1202 | |
|
1203 | 0 | result = check_exp(func, ctx); |
1204 | 0 | if (result) { |
1205 | 0 | term->tag = A_APP; |
1206 | 0 | term->type = ref(func->type->img); |
1207 | 0 | } |
1208 | 0 | } |
1209 | 0 | } |
1210 | 0 | break; |
1211 | 0 | case A_APP: |
1212 | 0 | result = check_exp(term->left, ctx) & check_exp(term->right, ctx); |
1213 | 0 | if (result) { |
1214 | 0 | if (term->left->type->tag != T_ARROW) { |
1215 | 0 | type_error1(term->info, |
1216 | 0 | "expected function in application but found %s", |
1217 | 0 | term->left->type); |
1218 | 0 | result = 0; |
1219 | 0 | }; |
1220 | 0 | } |
1221 | 0 | if (result) { |
1222 | 0 | result = expect_types(term->info, |
1223 | 0 | term->right->type, |
1224 | 0 | 1, term->left->type->dom) != NULL; |
1225 | 0 | if (! result) { |
1226 | 0 | type_error_binop(term->info, "application", |
1227 | 0 | term->left->type, term->right->type); |
1228 | 0 | result = 0; |
1229 | 0 | } |
1230 | 0 | } |
1231 | 0 | if (result) |
1232 | 0 | term->type = ref(term->left->type->img); |
1233 | 0 | break; |
1234 | 48.7k | case A_VALUE: |
1235 | 48.7k | result = check_value(term); |
1236 | 48.7k | break; |
1237 | 0 | case A_IDENT: |
1238 | 0 | { |
1239 | 0 | struct type *t = ctx_lookup_type(term->info, ctx, term->ident); |
1240 | 0 | if (t == NULL) { |
1241 | 0 | syntax_error(term->info, "Undefined variable %s", |
1242 | 0 | term->ident->str); |
1243 | 0 | result = 0; |
1244 | 0 | } else { |
1245 | 0 | term->type = ref(t); |
1246 | 0 | } |
1247 | 0 | } |
1248 | 0 | break; |
1249 | 0 | case A_BRACKET: |
1250 | 0 | result = check_exp(term->brexp, ctx); |
1251 | 0 | if (result) { |
1252 | 0 | term->type = ref(expect_types(term->info, term->brexp->type, |
1253 | 0 | 1, t_lens)); |
1254 | 0 | if (term->type == NULL) { |
1255 | 0 | type_error1(term->info, |
1256 | 0 | "[..] is only defined for lenses, not for %s", |
1257 | 0 | term->brexp->type); |
1258 | 0 | result = 0; |
1259 | 0 | } |
1260 | 0 | } |
1261 | 0 | break; |
1262 | 74.6k | case A_FUNC: |
1263 | 74.6k | { |
1264 | 74.6k | bind_param(&ctx->local, term->param, NULL); |
1265 | 74.6k | result = check_exp(term->body, ctx); |
1266 | 74.6k | if (result) { |
1267 | 74.6k | term->type = |
1268 | 74.6k | make_arrow_type(term->param->type, term->body->type); |
1269 | 74.6k | } |
1270 | 74.6k | unbind_param(&ctx->local, term->param); |
1271 | 74.6k | } |
1272 | 74.6k | break; |
1273 | 0 | case A_REP: |
1274 | 0 | result = check_exp(term->exp, ctx); |
1275 | 0 | if (result) { |
1276 | 0 | term->type = ref(expect_types(term->info, term->exp->type, 2, |
1277 | 0 | t_regexp, t_lens)); |
1278 | 0 | if (term->type == NULL) { |
1279 | 0 | type_error1(term->info, |
1280 | 0 | "Incompatible types: repetition is only defined" |
1281 | 0 | " for regexp and lens, not for %s", |
1282 | 0 | term->exp->type); |
1283 | 0 | result = 0; |
1284 | 0 | } |
1285 | 0 | } |
1286 | 0 | break; |
1287 | 0 | default: |
1288 | 0 | assert(0); |
1289 | 0 | break; |
1290 | 123k | } |
1291 | 123k | assert(!result || term->type != NULL); |
1292 | 123k | return result; |
1293 | 123k | } |
1294 | | |
1295 | 0 | static int check_decl(struct term *term, struct ctx *ctx) { |
1296 | 0 | assert(term->tag == A_BIND || term->tag == A_TEST); |
1297 | | |
1298 | 0 | if (term->tag == A_BIND) { |
1299 | 0 | if (!check_exp(term->exp, ctx)) |
1300 | 0 | return 0; |
1301 | 0 | term->type = ref(term->exp->type); |
1302 | |
|
1303 | 0 | if (bnd_lookup(ctx->local, term->bname) != NULL) { |
1304 | 0 | syntax_error(term->info, |
1305 | 0 | "the name %s is already defined", term->bname); |
1306 | 0 | return 0; |
1307 | 0 | } |
1308 | 0 | bind_type(&ctx->local, term->bname, term->type); |
1309 | 0 | } else if (term->tag == A_TEST) { |
1310 | 0 | if (!check_exp(term->test, ctx)) |
1311 | 0 | return 0; |
1312 | 0 | if (term->result != NULL) { |
1313 | 0 | if (!check_exp(term->result, ctx)) |
1314 | 0 | return 0; |
1315 | 0 | if (! type_equal(term->test->type, term->result->type)) { |
1316 | 0 | type_error2(term->info, |
1317 | 0 | "expected test result of type %s but got %s", |
1318 | 0 | term->result->type, term->test->type); |
1319 | 0 | return 0; |
1320 | 0 | } |
1321 | 0 | } else { |
1322 | 0 | if (expect_types(term->info, term->test->type, 2, |
1323 | 0 | t_string, t_tree) == NULL) |
1324 | 0 | return 0; |
1325 | 0 | } |
1326 | 0 | term->type = ref(term->test->type); |
1327 | 0 | } else { |
1328 | 0 | assert(0); |
1329 | 0 | } |
1330 | 0 | return 1; |
1331 | 0 | } |
1332 | | |
1333 | 0 | static int typecheck(struct term *term, struct augeas *aug) { |
1334 | 0 | int ok = 1; |
1335 | 0 | struct ctx ctx; |
1336 | 0 | char *fname; |
1337 | 0 | const char *basenam; |
1338 | |
|
1339 | 0 | assert(term->tag == A_MODULE); |
1340 | | |
1341 | | /* Check that the module name is consistent with the filename */ |
1342 | 0 | fname = module_basename(term->mname); |
1343 | |
|
1344 | 0 | basenam = strrchr(term->info->filename->str, SEP); |
1345 | 0 | if (basenam == NULL) |
1346 | 0 | basenam = term->info->filename->str; |
1347 | 0 | else |
1348 | 0 | basenam += 1; |
1349 | 0 | if (STRNEQ(fname, basenam)) { |
1350 | 0 | syntax_error(term->info, |
1351 | 0 | "The module %s must be in a file named %s", |
1352 | 0 | term->mname, fname); |
1353 | 0 | free(fname); |
1354 | 0 | return 0; |
1355 | 0 | } |
1356 | 0 | free(fname); |
1357 | |
|
1358 | 0 | ctx.aug = aug; |
1359 | 0 | ctx.local = NULL; |
1360 | 0 | ctx.name = term->mname; |
1361 | 0 | list_for_each(dcl, term->decls) { |
1362 | 0 | ok &= check_decl(dcl, &ctx); |
1363 | 0 | } |
1364 | 0 | unref(ctx.local, binding); |
1365 | 0 | return ok; |
1366 | 0 | } |
1367 | | |
1368 | | static struct value *compile_exp(struct info *, struct term *, struct ctx *); |
1369 | | |
1370 | 0 | static struct value *compile_union(struct term *exp, struct ctx *ctx) { |
1371 | 0 | struct value *v1 = compile_exp(exp->info, exp->left, ctx); |
1372 | 0 | if (EXN(v1)) |
1373 | 0 | return v1; |
1374 | 0 | struct value *v2 = compile_exp(exp->info, exp->right, ctx); |
1375 | 0 | if (EXN(v2)) { |
1376 | 0 | unref(v1, value); |
1377 | 0 | return v2; |
1378 | 0 | } |
1379 | | |
1380 | 0 | struct type *t = exp->type; |
1381 | 0 | struct info *info = exp->info; |
1382 | 0 | struct value *v = NULL; |
1383 | |
|
1384 | 0 | v1 = coerce(v1, t); |
1385 | 0 | if (EXN(v1)) |
1386 | 0 | return v1; |
1387 | 0 | v2 = coerce(v2, t); |
1388 | 0 | if (EXN(v2)) { |
1389 | 0 | unref(v1, value); |
1390 | 0 | return v2; |
1391 | 0 | } |
1392 | | |
1393 | 0 | if (t->tag == T_REGEXP) { |
1394 | 0 | v = make_value(V_REGEXP, ref(info)); |
1395 | 0 | v->regexp = regexp_union(info, v1->regexp, v2->regexp); |
1396 | 0 | } else if (t->tag == T_LENS) { |
1397 | 0 | struct lens *l1 = v1->lens; |
1398 | 0 | struct lens *l2 = v2->lens; |
1399 | 0 | v = lns_make_union(ref(info), ref(l1), ref(l2), LNS_TYPE_CHECK(ctx)); |
1400 | 0 | } else { |
1401 | 0 | fatal_error(info, "Tried to union a %s and a %s to yield a %s", |
1402 | 0 | type_name(exp->left->type), type_name(exp->right->type), |
1403 | 0 | type_name(t)); |
1404 | 0 | } |
1405 | 0 | unref(v1, value); |
1406 | 0 | unref(v2, value); |
1407 | 0 | return v; |
1408 | 0 | } |
1409 | | |
1410 | 0 | static struct value *compile_minus(struct term *exp, struct ctx *ctx) { |
1411 | 0 | struct value *v1 = compile_exp(exp->info, exp->left, ctx); |
1412 | 0 | if (EXN(v1)) |
1413 | 0 | return v1; |
1414 | 0 | struct value *v2 = compile_exp(exp->info, exp->right, ctx); |
1415 | 0 | if (EXN(v2)) { |
1416 | 0 | unref(v1, value); |
1417 | 0 | return v2; |
1418 | 0 | } |
1419 | | |
1420 | 0 | struct type *t = exp->type; |
1421 | 0 | struct info *info = exp->info; |
1422 | 0 | struct value *v; |
1423 | |
|
1424 | 0 | v1 = coerce(v1, t); |
1425 | 0 | v2 = coerce(v2, t); |
1426 | 0 | if (t->tag == T_REGEXP) { |
1427 | 0 | struct regexp *re1 = v1->regexp; |
1428 | 0 | struct regexp *re2 = v2->regexp; |
1429 | 0 | struct regexp *re = regexp_minus(info, re1, re2); |
1430 | 0 | if (re == NULL) { |
1431 | 0 | v = make_exn_value(ref(info), |
1432 | 0 | "Regular expression subtraction 'r1 - r2' failed"); |
1433 | 0 | exn_printf_line(v, "r1: /%s/", re1->pattern->str); |
1434 | 0 | exn_printf_line(v, "r2: /%s/", re2->pattern->str); |
1435 | 0 | } else { |
1436 | 0 | v = make_value(V_REGEXP, ref(info)); |
1437 | 0 | v->regexp = re; |
1438 | 0 | } |
1439 | 0 | } else { |
1440 | 0 | v = NULL; |
1441 | 0 | fatal_error(info, "Tried to subtract a %s and a %s to yield a %s", |
1442 | 0 | type_name(exp->left->type), type_name(exp->right->type), |
1443 | 0 | type_name(t)); |
1444 | 0 | } |
1445 | 0 | unref(v1, value); |
1446 | 0 | unref(v2, value); |
1447 | 0 | return v; |
1448 | 0 | } |
1449 | | |
1450 | 0 | static struct value *compile_compose(struct term *exp, struct ctx *ctx) { |
1451 | 0 | struct info *info = exp->info; |
1452 | 0 | struct value *v; |
1453 | |
|
1454 | 0 | if (exp->left->type->tag == T_ARROW) { |
1455 | | // FIXME: This is really crufty, and should be desugared in the |
1456 | | // parser so that we don't have to do all this manual type |
1457 | | // computation. Should we write function compostion as |
1458 | | // concatenation instead of using a separate syntax ? |
1459 | | |
1460 | | /* Build lambda x: exp->right (exp->left x) as a closure */ |
1461 | 0 | char *var = strdup("@0"); |
1462 | 0 | struct term *func = make_param(var, ref(exp->left->type->dom), |
1463 | 0 | ref(info)); |
1464 | 0 | func->type = make_arrow_type(exp->left->type->dom, |
1465 | 0 | exp->right->type->img); |
1466 | 0 | struct term *ident = make_term(A_IDENT, ref(info)); |
1467 | 0 | ident->ident = ref(func->param->name); |
1468 | 0 | ident->type = ref(func->param->type); |
1469 | 0 | struct term *app = make_app_term(ref(exp->left), ident, ref(info)); |
1470 | 0 | app->type = ref(app->left->type->img); |
1471 | 0 | app = make_app_term(ref(exp->right), app, ref(info)); |
1472 | 0 | app->type = ref(app->right->type->img); |
1473 | |
|
1474 | 0 | build_func(func, app); |
1475 | |
|
1476 | 0 | if (!type_equal(func->type, exp->type)) { |
1477 | 0 | char *f = type_string(func->type); |
1478 | 0 | char *e = type_string(exp->type); |
1479 | 0 | fatal_error(info, |
1480 | 0 | "Composition has type %s but should have type %s", f, e); |
1481 | 0 | free(f); |
1482 | 0 | free(e); |
1483 | 0 | unref(func, term); |
1484 | 0 | return info->error->exn; |
1485 | 0 | } |
1486 | 0 | v = make_closure(func, ctx->local); |
1487 | 0 | unref(func, term); |
1488 | 0 | } else { |
1489 | 0 | v = compile_exp(exp->info, exp->left, ctx); |
1490 | 0 | unref(v, value); |
1491 | 0 | v = compile_exp(exp->info, exp->right, ctx); |
1492 | 0 | } |
1493 | 0 | return v; |
1494 | 0 | } |
1495 | | |
1496 | 0 | static struct value *compile_concat(struct term *exp, struct ctx *ctx) { |
1497 | 0 | struct value *v1 = compile_exp(exp->info, exp->left, ctx); |
1498 | 0 | if (EXN(v1)) |
1499 | 0 | return v1; |
1500 | 0 | struct value *v2 = compile_exp(exp->info, exp->right, ctx); |
1501 | 0 | if (EXN(v2)) { |
1502 | 0 | unref(v1, value); |
1503 | 0 | return v2; |
1504 | 0 | } |
1505 | | |
1506 | 0 | struct type *t = exp->type; |
1507 | 0 | struct info *info = exp->info; |
1508 | 0 | struct value *v; |
1509 | |
|
1510 | 0 | v1 = coerce(v1, t); |
1511 | 0 | v2 = coerce(v2, t); |
1512 | 0 | if (t->tag == T_STRING) { |
1513 | 0 | const char *s1 = v1->string->str; |
1514 | 0 | const char *s2 = v2->string->str; |
1515 | 0 | v = make_value(V_STRING, ref(info)); |
1516 | 0 | make_ref(v->string); |
1517 | 0 | if (ALLOC_N(v->string->str, strlen(s1) + strlen(s2) + 1) < 0) |
1518 | 0 | goto error; |
1519 | 0 | char *s = v->string->str; |
1520 | 0 | strcpy(s, s1); |
1521 | 0 | strcat(s, s2); |
1522 | 0 | } else if (t->tag == T_REGEXP) { |
1523 | 0 | v = make_value(V_REGEXP, ref(info)); |
1524 | 0 | v->regexp = regexp_concat(info, v1->regexp, v2->regexp); |
1525 | 0 | } else if (t->tag == T_FILTER) { |
1526 | 0 | struct filter *f1 = v1->filter; |
1527 | 0 | struct filter *f2 = v2->filter; |
1528 | 0 | v = make_value(V_FILTER, ref(info)); |
1529 | 0 | if (v2->ref == 1 && f2->ref == 1) { |
1530 | 0 | list_append(f2, ref(f1)); |
1531 | 0 | v->filter = ref(f2); |
1532 | 0 | } else if (v1->ref == 1 && f1->ref == 1) { |
1533 | 0 | list_append(f1, ref(f2)); |
1534 | 0 | v->filter = ref(f1); |
1535 | 0 | } else { |
1536 | 0 | struct filter *cf1, *cf2; |
1537 | 0 | cf1 = make_filter(ref(f1->glob), f1->include); |
1538 | 0 | cf2 = make_filter(ref(f2->glob), f2->include); |
1539 | 0 | cf1->next = ref(f1->next); |
1540 | 0 | cf2->next = ref(f2->next); |
1541 | 0 | list_append(cf1, cf2); |
1542 | 0 | v->filter = cf1; |
1543 | 0 | } |
1544 | 0 | } else if (t->tag == T_LENS) { |
1545 | 0 | struct lens *l1 = v1->lens; |
1546 | 0 | struct lens *l2 = v2->lens; |
1547 | 0 | v = lns_make_concat(ref(info), ref(l1), ref(l2), LNS_TYPE_CHECK(ctx)); |
1548 | 0 | } else { |
1549 | 0 | v = NULL; |
1550 | 0 | fatal_error(info, "Tried to concat a %s and a %s to yield a %s", |
1551 | 0 | type_name(exp->left->type), type_name(exp->right->type), |
1552 | 0 | type_name(t)); |
1553 | 0 | } |
1554 | 0 | unref(v1, value); |
1555 | 0 | unref(v2, value); |
1556 | 0 | return v; |
1557 | 0 | error: |
1558 | 0 | return exp->info->error->exn; |
1559 | 0 | } |
1560 | | |
1561 | 0 | static struct value *apply(struct term *app, struct ctx *ctx) { |
1562 | 0 | struct value *f = compile_exp(app->info, app->left, ctx); |
1563 | 0 | struct value *result = NULL; |
1564 | 0 | struct ctx lctx; |
1565 | |
|
1566 | 0 | if (EXN(f)) |
1567 | 0 | return f; |
1568 | | |
1569 | 0 | struct value *arg = compile_exp(app->info, app->right, ctx); |
1570 | 0 | if (EXN(arg)) { |
1571 | 0 | unref(f, value); |
1572 | 0 | return arg; |
1573 | 0 | } |
1574 | | |
1575 | 0 | assert(f->tag == V_CLOS); |
1576 | | |
1577 | 0 | lctx.aug = ctx->aug; |
1578 | 0 | lctx.local = ref(f->bindings); |
1579 | 0 | lctx.name = ctx->name; |
1580 | |
|
1581 | 0 | arg = coerce(arg, f->func->param->type); |
1582 | 0 | if (arg == NULL) |
1583 | 0 | goto done; |
1584 | | |
1585 | 0 | bind_param(&lctx.local, f->func->param, arg); |
1586 | 0 | result = compile_exp(app->info, f->func->body, &lctx); |
1587 | 0 | unref(result->info, info); |
1588 | 0 | result->info = ref(app->info); |
1589 | 0 | unbind_param(&lctx.local, f->func->param); |
1590 | |
|
1591 | 0 | done: |
1592 | 0 | unref(lctx.local, binding); |
1593 | 0 | unref(arg, value); |
1594 | 0 | unref(f, value); |
1595 | 0 | return result; |
1596 | 0 | } |
1597 | | |
1598 | 0 | static struct value *compile_bracket(struct term *exp, struct ctx *ctx) { |
1599 | 0 | struct value *arg = compile_exp(exp->info, exp->brexp, ctx); |
1600 | 0 | if (EXN(arg)) |
1601 | 0 | return arg; |
1602 | 0 | assert(arg->tag == V_LENS); |
1603 | | |
1604 | 0 | struct value *v = lns_make_subtree(ref(exp->info), ref(arg->lens)); |
1605 | 0 | unref(arg, value); |
1606 | | |
1607 | 0 | return v; |
1608 | 0 | } |
1609 | | |
1610 | 0 | static struct value *compile_rep(struct term *rep, struct ctx *ctx) { |
1611 | 0 | struct value *arg = compile_exp(rep->info, rep->rexp, ctx); |
1612 | 0 | struct value *v = NULL; |
1613 | |
|
1614 | 0 | if (EXN(arg)) |
1615 | 0 | return arg; |
1616 | | |
1617 | 0 | arg = coerce(arg, rep->type); |
1618 | 0 | if (rep->type->tag == T_REGEXP) { |
1619 | 0 | int min, max; |
1620 | 0 | if (rep->quant == Q_STAR) { |
1621 | 0 | min = 0; max = -1; |
1622 | 0 | } else if (rep->quant == Q_PLUS) { |
1623 | 0 | min = 1; max = -1; |
1624 | 0 | } else if (rep->quant == Q_MAYBE) { |
1625 | 0 | min = 0; max = 1; |
1626 | 0 | } else { |
1627 | 0 | assert(0); |
1628 | 0 | abort(); |
1629 | 0 | } |
1630 | 0 | v = make_value(V_REGEXP, ref(rep->info)); |
1631 | 0 | v->regexp = regexp_iter(rep->info, arg->regexp, min, max); |
1632 | 0 | } else if (rep->type->tag == T_LENS) { |
1633 | 0 | int c = LNS_TYPE_CHECK(ctx); |
1634 | 0 | if (rep->quant == Q_STAR) { |
1635 | 0 | v = lns_make_star(ref(rep->info), ref(arg->lens), c); |
1636 | 0 | } else if (rep->quant == Q_PLUS) { |
1637 | 0 | v = lns_make_plus(ref(rep->info), ref(arg->lens), c); |
1638 | 0 | } else if (rep->quant == Q_MAYBE) { |
1639 | 0 | v = lns_make_maybe(ref(rep->info), ref(arg->lens), c); |
1640 | 0 | } else { |
1641 | 0 | assert(0); |
1642 | 0 | } |
1643 | 0 | } else { |
1644 | 0 | fatal_error(rep->info, "Tried to repeat a %s to yield a %s", |
1645 | 0 | type_name(rep->rexp->type), type_name(rep->type)); |
1646 | 0 | } |
1647 | 0 | unref(arg, value); |
1648 | 0 | return v; |
1649 | 0 | } |
1650 | | |
1651 | | static struct value *compile_exp(struct info *info, |
1652 | 0 | struct term *exp, struct ctx *ctx) { |
1653 | 0 | struct value *v = NULL; |
1654 | |
|
1655 | 0 | switch (exp->tag) { |
1656 | 0 | case A_COMPOSE: |
1657 | 0 | v = compile_compose(exp, ctx); |
1658 | 0 | break; |
1659 | 0 | case A_UNION: |
1660 | 0 | v = compile_union(exp, ctx); |
1661 | 0 | break; |
1662 | 0 | case A_MINUS: |
1663 | 0 | v = compile_minus(exp, ctx); |
1664 | 0 | break; |
1665 | 0 | case A_CONCAT: |
1666 | 0 | v = compile_concat(exp, ctx); |
1667 | 0 | break; |
1668 | 0 | case A_APP: |
1669 | 0 | v = apply(exp, ctx); |
1670 | 0 | break; |
1671 | 0 | case A_VALUE: |
1672 | 0 | if (exp->value->tag == V_NATIVE) { |
1673 | 0 | v = native_call(info, exp->value->native, ctx); |
1674 | 0 | } else { |
1675 | 0 | v = ref(exp->value); |
1676 | 0 | } |
1677 | 0 | break; |
1678 | 0 | case A_IDENT: |
1679 | 0 | v = ref(ctx_lookup(exp->info, ctx, exp->ident)); |
1680 | 0 | break; |
1681 | 0 | case A_BRACKET: |
1682 | 0 | v = compile_bracket(exp, ctx); |
1683 | 0 | break; |
1684 | 0 | case A_FUNC: |
1685 | 0 | v = make_closure(exp, ctx->local); |
1686 | 0 | break; |
1687 | 0 | case A_REP: |
1688 | 0 | v = compile_rep(exp, ctx); |
1689 | 0 | break; |
1690 | 0 | default: |
1691 | 0 | assert(0); |
1692 | 0 | break; |
1693 | 0 | } |
1694 | | |
1695 | 0 | return v; |
1696 | 0 | } |
1697 | | |
1698 | 0 | static int compile_test(struct term *term, struct ctx *ctx) { |
1699 | 0 | struct value *actual = compile_exp(term->info, term->test, ctx); |
1700 | 0 | struct value *expect = NULL; |
1701 | 0 | int ret = 1; |
1702 | |
|
1703 | 0 | if (term->tr_tag == TR_EXN) { |
1704 | 0 | if (!EXN(actual)) { |
1705 | 0 | print_info(stdout, term->info); |
1706 | 0 | printf("Test run should have produced exception, but produced\n"); |
1707 | 0 | print_value(stdout, actual); |
1708 | 0 | printf("\n"); |
1709 | 0 | ret = 0; |
1710 | 0 | } |
1711 | 0 | } else { |
1712 | 0 | if (EXN(actual)) { |
1713 | 0 | print_info(stdout, term->info); |
1714 | 0 | printf("exception thrown in test\n"); |
1715 | 0 | print_value(stdout, actual); |
1716 | 0 | printf("\n"); |
1717 | 0 | ret = 0; |
1718 | 0 | } else if (term->tr_tag == TR_CHECK) { |
1719 | 0 | expect = compile_exp(term->info, term->result, ctx); |
1720 | 0 | if (EXN(expect)) |
1721 | 0 | goto done; |
1722 | 0 | if (! value_equal(actual, expect)) { |
1723 | 0 | printf("Test failure:"); |
1724 | 0 | print_info(stdout, term->info); |
1725 | 0 | printf("\n"); |
1726 | 0 | printf(" Expected:\n"); |
1727 | 0 | print_value(stdout, expect); |
1728 | 0 | printf("\n"); |
1729 | 0 | printf(" Actual:\n"); |
1730 | 0 | print_value(stdout, actual); |
1731 | 0 | printf("\n"); |
1732 | 0 | ret = 0; |
1733 | 0 | } |
1734 | 0 | } else { |
1735 | 0 | printf("Test result: "); |
1736 | 0 | print_info(stdout, term->info); |
1737 | 0 | printf("\n"); |
1738 | 0 | if (actual->tag == V_TREE) { |
1739 | 0 | print_tree_braces(stdout, 2, actual->origin->children); |
1740 | 0 | } else { |
1741 | 0 | print_value(stdout, actual); |
1742 | 0 | } |
1743 | 0 | printf("\n"); |
1744 | 0 | } |
1745 | 0 | } |
1746 | 0 | done: |
1747 | 0 | reset_error(term->info->error); |
1748 | 0 | unref(actual, value); |
1749 | 0 | unref(expect, value); |
1750 | 0 | return ret; |
1751 | 0 | } |
1752 | | |
1753 | 0 | static int compile_decl(struct term *term, struct ctx *ctx) { |
1754 | 0 | if (term->tag == A_BIND) { |
1755 | 0 | int result; |
1756 | |
|
1757 | 0 | struct value *v = compile_exp(term->info, term->exp, ctx); |
1758 | 0 | bind(&ctx->local, term->bname, term->type, v); |
1759 | |
|
1760 | 0 | if (EXN(v) && !v->exn->seen) { |
1761 | 0 | struct error *error = term->info->error; |
1762 | 0 | struct memstream ms; |
1763 | |
|
1764 | 0 | init_memstream(&ms); |
1765 | |
|
1766 | 0 | syntax_error(term->info, "Failed to compile %s", |
1767 | 0 | term->bname); |
1768 | 0 | fprintf(ms.stream, "%s\n", error->details); |
1769 | 0 | print_value(ms.stream, v); |
1770 | 0 | close_memstream(&ms); |
1771 | |
|
1772 | 0 | v->exn->seen = 1; |
1773 | 0 | free(error->details); |
1774 | 0 | error->details = ms.buf; |
1775 | 0 | } |
1776 | 0 | result = !(EXN(v) || HAS_ERR(ctx->aug)); |
1777 | 0 | unref(v, value); |
1778 | 0 | return result; |
1779 | 0 | } else if (term->tag == A_TEST) { |
1780 | 0 | return compile_test(term, ctx); |
1781 | 0 | } |
1782 | 0 | assert(0); |
1783 | 0 | abort(); |
1784 | 0 | } |
1785 | | |
1786 | 0 | static struct module *compile(struct term *term, struct augeas *aug) { |
1787 | 0 | struct ctx ctx; |
1788 | 0 | struct transform *autoload = NULL; |
1789 | 0 | assert(term->tag == A_MODULE); |
1790 | | |
1791 | 0 | ctx.aug = aug; |
1792 | 0 | ctx.local = NULL; |
1793 | 0 | ctx.name = term->mname; |
1794 | 0 | list_for_each(dcl, term->decls) { |
1795 | 0 | if (!compile_decl(dcl, &ctx)) |
1796 | 0 | goto error; |
1797 | 0 | } |
1798 | | |
1799 | 0 | if (term->autoload != NULL) { |
1800 | 0 | struct binding *bnd = bnd_lookup(ctx.local, term->autoload); |
1801 | 0 | if (bnd == NULL) { |
1802 | 0 | syntax_error(term->info, "Undefined transform in autoload %s", |
1803 | 0 | term->autoload); |
1804 | 0 | goto error; |
1805 | 0 | } |
1806 | 0 | if (expect_types(term->info, bnd->type, 1, t_transform) == NULL) |
1807 | 0 | goto error; |
1808 | 0 | autoload = bnd->value->transform; |
1809 | 0 | } |
1810 | 0 | struct module *module = module_create(term->mname); |
1811 | 0 | module->bindings = ctx.local; |
1812 | 0 | module->autoload = ref(autoload); |
1813 | 0 | return module; |
1814 | 0 | error: |
1815 | 0 | unref(ctx.local, binding); |
1816 | 0 | return NULL; |
1817 | 0 | } |
1818 | | |
1819 | | /* |
1820 | | * Defining native functions |
1821 | | */ |
1822 | | static struct info * |
1823 | 48.7k | make_native_info(struct error *error, const char *fname, int line) { |
1824 | 48.7k | struct info *info; |
1825 | 48.7k | if (make_ref(info) < 0) |
1826 | 0 | goto error; |
1827 | 48.7k | info->first_line = info->last_line = line; |
1828 | 48.7k | info->first_column = info->last_column = 0; |
1829 | 48.7k | info->error = error; |
1830 | 48.7k | if (make_ref(info->filename) < 0) |
1831 | 0 | goto error; |
1832 | 48.7k | info->filename->str = strdup(fname); |
1833 | 48.7k | return info; |
1834 | 0 | error: |
1835 | 0 | unref(info, info); |
1836 | 0 | return NULL; |
1837 | 0 | } |
1838 | | |
1839 | | int define_native_intl(const char *file, int line, |
1840 | | struct error *error, |
1841 | | struct module *module, const char *name, |
1842 | 48.7k | int argc, func_impl impl, ...) { |
1843 | 48.7k | assert(argc > 0); /* We have no unit type */ |
1844 | 48.7k | assert(argc <= 5); |
1845 | 48.7k | va_list ap; |
1846 | 48.7k | enum type_tag tag; |
1847 | 48.7k | struct term *params = NULL, *body = NULL, *func = NULL; |
1848 | 48.7k | struct type *type; |
1849 | 48.7k | struct value *v = NULL; |
1850 | 48.7k | struct info *info = NULL; |
1851 | 48.7k | struct ctx ctx; |
1852 | | |
1853 | 48.7k | info = make_native_info(error, file, line); |
1854 | 48.7k | if (info == NULL) |
1855 | 0 | goto error; |
1856 | | |
1857 | 48.7k | va_start(ap, impl); |
1858 | 123k | for (int i=0; i < argc; i++) { |
1859 | 74.6k | struct term *pterm; |
1860 | 74.6k | char ident[10]; |
1861 | 74.6k | tag = va_arg(ap, enum type_tag); |
1862 | 74.6k | type = make_base_type(tag); |
1863 | 74.6k | snprintf(ident, 10, "@%d", i); |
1864 | 74.6k | pterm = make_param(strdup(ident), type, ref(info)); |
1865 | 74.6k | list_append(params, pterm); |
1866 | 74.6k | } |
1867 | 48.7k | tag = va_arg(ap, enum type_tag); |
1868 | 48.7k | va_end(ap); |
1869 | | |
1870 | 48.7k | type = make_base_type(tag); |
1871 | | |
1872 | 48.7k | make_ref(v); |
1873 | 48.7k | if (v == NULL) |
1874 | 0 | goto error; |
1875 | 48.7k | v->tag = V_NATIVE; |
1876 | 48.7k | v->info = info; |
1877 | 48.7k | info = NULL; |
1878 | | |
1879 | 48.7k | if (ALLOC(v->native) < 0) |
1880 | 0 | goto error; |
1881 | 48.7k | v->native->argc = argc; |
1882 | 48.7k | v->native->type = type; |
1883 | 48.7k | v->native->impl = impl; |
1884 | | |
1885 | 48.7k | make_ref(body); |
1886 | 48.7k | if (body == NULL) |
1887 | 0 | goto error; |
1888 | 48.7k | body->info = ref(info); |
1889 | 48.7k | body->type = ref(type); |
1890 | 48.7k | body->tag = A_VALUE; |
1891 | 48.7k | body->value = v; |
1892 | 48.7k | v = NULL; |
1893 | | |
1894 | 48.7k | func = build_func(params, body); |
1895 | 48.7k | params = NULL; |
1896 | 48.7k | body = NULL; |
1897 | | |
1898 | 48.7k | ctx.aug = NULL; |
1899 | 48.7k | ctx.local = ref(module->bindings); |
1900 | 48.7k | ctx.name = module->name; |
1901 | 48.7k | if (! check_exp(func, &ctx)) { |
1902 | 0 | fatal_error(info, "Typechecking native %s failed", |
1903 | 0 | name); |
1904 | 0 | abort(); |
1905 | 0 | } |
1906 | 48.7k | v = make_closure(func, ctx.local); |
1907 | 48.7k | if (v == NULL) { |
1908 | 0 | unref(module->bindings, binding); |
1909 | 0 | goto error; |
1910 | 0 | } |
1911 | 48.7k | bind(&ctx.local, name, func->type, v); |
1912 | 48.7k | unref(v, value); |
1913 | 48.7k | unref(func, term); |
1914 | 48.7k | unref(module->bindings, binding); |
1915 | | |
1916 | 48.7k | module->bindings = ctx.local; |
1917 | 48.7k | return 0; |
1918 | 0 | error: |
1919 | 0 | list_for_each(p, params) { |
1920 | 0 | unref(p, term); |
1921 | 0 | } |
1922 | 0 | unref(v, value); |
1923 | 0 | unref(body, term); |
1924 | 0 | unref(func, term); |
1925 | 0 | return -1; |
1926 | 0 | } |
1927 | | |
1928 | | |
1929 | | /* Defined in parser.y */ |
1930 | | int augl_parse_file(struct augeas *aug, const char *name, struct term **term); |
1931 | | |
1932 | 0 | static char *module_basename(const char *modname) { |
1933 | 0 | char *fname; |
1934 | |
|
1935 | 0 | if (asprintf(&fname, "%s" AUG_EXT, modname) == -1) |
1936 | 0 | return NULL; |
1937 | 0 | for (int i=0; i < strlen(modname); i++) |
1938 | 0 | fname[i] = tolower(fname[i]); |
1939 | 0 | return fname; |
1940 | 0 | } |
1941 | | |
1942 | 0 | static char *module_filename(struct augeas *aug, const char *modname) { |
1943 | 0 | char *dir = NULL; |
1944 | 0 | char *filename = NULL; |
1945 | 0 | char *name = module_basename(modname); |
1946 | | |
1947 | | /* Module names that contain slashes can fool us into finding and |
1948 | | * loading a module in another directory, but once loaded we won't find |
1949 | | * it under MODNAME so that we will later try and load it over and |
1950 | | * over */ |
1951 | 0 | if (index(modname, '/') != NULL) |
1952 | 0 | goto error; |
1953 | | |
1954 | 0 | while ((dir = argz_next(aug->modpathz, aug->nmodpath, dir)) != NULL) { |
1955 | 0 | int len = strlen(name) + strlen(dir) + 2; |
1956 | 0 | struct stat st; |
1957 | |
|
1958 | 0 | if (REALLOC_N(filename, len) == -1) |
1959 | 0 | goto error; |
1960 | 0 | sprintf(filename, "%s/%s", dir, name); |
1961 | 0 | if (stat(filename, &st) == 0) |
1962 | 0 | goto done; |
1963 | 0 | } |
1964 | 0 | error: |
1965 | 0 | FREE(filename); |
1966 | 0 | done: |
1967 | 0 | free(name); |
1968 | 0 | return filename; |
1969 | 0 | } |
1970 | | |
1971 | | int load_module_file(struct augeas *aug, const char *filename, |
1972 | 0 | const char *name) { |
1973 | 0 | struct term *term = NULL; |
1974 | 0 | int result = -1; |
1975 | |
|
1976 | 0 | if (aug->flags & AUG_TRACE_MODULE_LOADING) |
1977 | 0 | printf("Module %s", filename); |
1978 | 0 | augl_parse_file(aug, filename, &term); |
1979 | 0 | if (aug->flags & AUG_TRACE_MODULE_LOADING) |
1980 | 0 | printf(HAS_ERR(aug) ? " failed\n" : " loaded\n"); |
1981 | 0 | ERR_BAIL(aug); |
1982 | |
|
1983 | 0 | if (! typecheck(term, aug)) |
1984 | 0 | goto error; |
1985 | | |
1986 | 0 | struct module *module = compile(term, aug); |
1987 | 0 | bool bad_module = (module == NULL); |
1988 | 0 | if (bad_module && name != NULL) { |
1989 | | /* Put an empty placeholder on the module list so that |
1990 | | * we don't retry loading this module everytime its mentioned |
1991 | | */ |
1992 | 0 | module = module_create(name); |
1993 | 0 | } |
1994 | 0 | if (module != NULL) { |
1995 | 0 | list_append(aug->modules, module); |
1996 | 0 | list_for_each(bnd, module->bindings) { |
1997 | 0 | if (bnd->value->tag == V_LENS) { |
1998 | 0 | lens_release(bnd->value->lens); |
1999 | 0 | } |
2000 | 0 | } |
2001 | 0 | } |
2002 | 0 | ERR_THROW(bad_module, aug, AUG_ESYNTAX, "Failed to load %s", filename); |
2003 | | |
2004 | 0 | result = 0; |
2005 | 0 | error: |
2006 | | // FIXME: This leads to a bad free of a string used in a del lens |
2007 | | // To reproduce run lenses/tests/test_yum.aug |
2008 | 0 | unref(term, term); |
2009 | 0 | return result; |
2010 | 0 | } |
2011 | | |
2012 | 0 | static int load_module(struct augeas *aug, const char *name) { |
2013 | 0 | char *filename = NULL; |
2014 | |
|
2015 | 0 | if (module_find(aug->modules, name) != NULL) |
2016 | 0 | return 0; |
2017 | | |
2018 | 0 | if ((filename = module_filename(aug, name)) == NULL) |
2019 | 0 | return -1; |
2020 | | |
2021 | 0 | if (load_module_file(aug, filename, name) == -1) |
2022 | 0 | goto error; |
2023 | | |
2024 | 0 | free(filename); |
2025 | 0 | return 0; |
2026 | | |
2027 | 0 | error: |
2028 | 0 | free(filename); |
2029 | 0 | return -1; |
2030 | 0 | } |
2031 | | |
2032 | 1.52k | int interpreter_init(struct augeas *aug) { |
2033 | 1.52k | int r; |
2034 | | |
2035 | 1.52k | r = init_fatal_exn(aug->error); |
2036 | 1.52k | if (r < 0) |
2037 | 0 | return -1; |
2038 | | |
2039 | 1.52k | aug->modules = builtin_init(aug->error); |
2040 | 1.52k | if (aug->flags & AUG_NO_MODL_AUTOLOAD) |
2041 | 0 | return 0; |
2042 | | |
2043 | | // For now, we just load every file on the search path |
2044 | 1.52k | const char *dir = NULL; |
2045 | 1.52k | glob_t globbuf; |
2046 | 1.52k | int gl_flags = GLOB_NOSORT; |
2047 | | |
2048 | 1.52k | MEMZERO(&globbuf, 1); |
2049 | | |
2050 | 4.57k | while ((dir = argz_next(aug->modpathz, aug->nmodpath, dir)) != NULL) { |
2051 | 3.04k | char *globpat; |
2052 | 3.04k | r = asprintf(&globpat, "%s/*.aug", dir); |
2053 | 3.04k | ERR_NOMEM(r < 0, aug); |
2054 | | |
2055 | 3.04k | r = glob(globpat, gl_flags, NULL, &globbuf); |
2056 | 3.04k | if (r != 0 && r != GLOB_NOMATCH) { |
2057 | | /* This really has to be an allocation failure; glob is not |
2058 | | * supposed to return GLOB_ABORTED here */ |
2059 | 0 | aug_errcode_t code = |
2060 | 0 | r == GLOB_NOSPACE ? AUG_ENOMEM : AUG_EINTERNAL; |
2061 | 0 | ERR_REPORT(aug, code, "glob failure for %s", globpat); |
2062 | 0 | free(globpat); |
2063 | 0 | goto error; |
2064 | 0 | } |
2065 | 3.04k | gl_flags |= GLOB_APPEND; |
2066 | 3.04k | free(globpat); |
2067 | 3.04k | } |
2068 | | |
2069 | 1.52k | for (int i=0; i < globbuf.gl_pathc; i++) { |
2070 | 0 | char *name, *p, *q; |
2071 | 0 | int res; |
2072 | 0 | p = strrchr(globbuf.gl_pathv[i], SEP); |
2073 | 0 | if (p == NULL) |
2074 | 0 | p = globbuf.gl_pathv[i]; |
2075 | 0 | else |
2076 | 0 | p += 1; |
2077 | 0 | q = strchr(p, '.'); |
2078 | 0 | name = strndup(p, q - p); |
2079 | 0 | name[0] = toupper(name[0]); |
2080 | 0 | res = load_module(aug, name); |
2081 | 0 | free(name); |
2082 | 0 | if (res == -1) |
2083 | 0 | goto error; |
2084 | 0 | } |
2085 | 1.52k | globfree(&globbuf); |
2086 | 1.52k | return 0; |
2087 | 0 | error: |
2088 | 0 | globfree(&globbuf); |
2089 | 0 | return -1; |
2090 | 1.52k | } |
2091 | | |
2092 | | /* |
2093 | | * Local variables: |
2094 | | * indent-tabs-mode: nil |
2095 | | * c-indent-level: 4 |
2096 | | * c-basic-offset: 4 |
2097 | | * tab-width: 4 |
2098 | | * End: |
2099 | | */ |