2 * builtin.c: builtin primitives
4 * Copyright (C) 2007-2015 David Lutterkort
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.
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.
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
20 * Author: David Lutterkort <dlutter@redhat.com>
31 #include "transform.h"
34 #define UNIMPL_BODY(name) \
36 FIXME(#name " called"); \
44 /* V_REGEXP -> V_STRING -> V_LENS */
45 static struct value *lns_del(struct info *info,
46 struct value *rxp, struct value *dflt) {
47 assert(rxp->tag == V_REGEXP);
48 assert(dflt->tag == V_STRING);
49 return lns_make_prim(L_DEL, ref(info),
50 ref(rxp->regexp), ref(dflt->string));
53 /* V_REGEXP -> V_LENS */
54 static struct value *lns_store(struct info *info, struct value *rxp) {
55 assert(rxp->tag == V_REGEXP);
56 return lns_make_prim(L_STORE, ref(info), ref(rxp->regexp), NULL);
59 /* V_STRING -> V_LENS */
60 static struct value *lns_value(struct info *info, struct value *str) {
61 assert(str->tag == V_STRING);
62 return lns_make_prim(L_VALUE, ref(info), NULL, ref(str->string));
65 /* V_REGEXP -> V_LENS */
66 static struct value *lns_key(struct info *info, struct value *rxp) {
67 assert(rxp->tag == V_REGEXP);
68 return lns_make_prim(L_KEY, ref(info), ref(rxp->regexp), NULL);
71 /* V_STRING -> V_LENS */
72 static struct value *lns_label(struct info *info, struct value *str) {
73 assert(str->tag == V_STRING);
74 return lns_make_prim(L_LABEL, ref(info), NULL, ref(str->string));
77 /* V_STRING -> V_LENS */
78 static struct value *lns_seq(struct info *info, struct value *str) {
79 assert(str->tag == V_STRING);
80 return lns_make_prim(L_SEQ, ref(info), NULL, ref(str->string));
83 /* V_STRING -> V_LENS */
84 static struct value *lns_counter(struct info *info, struct value *str) {
85 assert(str->tag == V_STRING);
86 return lns_make_prim(L_COUNTER, ref(info), NULL, ref(str->string));
89 /* V_LENS -> V_LENS -> V_LENS -> V_LENS */
90 static struct value *lns_square(struct info *info, struct value *l1,
91 struct value *l2, struct value *l3) {
92 assert(l1->tag == V_LENS);
93 assert(l2->tag == V_LENS);
94 assert(l3->tag == V_LENS);
95 int check = info->error->aug->flags & AUG_TYPE_CHECK;
97 return lns_make_square(ref(info), ref(l1->lens), ref(l2->lens), ref(l3->lens), check);
100 static void exn_lns_error_detail(struct value *exn, const char *label,
105 char *s = format_info(lens->info);
106 exn_printf_line(exn, "%s: %s", label, s);
110 static struct value *make_exn_lns_error(struct info *info,
111 struct lns_error *err,
116 return info->error->exn;
118 v = make_exn_value(ref(info), "%s", err->message);
119 exn_lns_error_detail(v, "Lens", err->lens);
120 exn_lns_error_detail(v, " Last match", err->last);
121 exn_lns_error_detail(v, " Not matching", err->next);
123 char *pos = format_pos(text, err->pos);
125 calc_line_ofs(text, err->pos, &line, &ofs);
127 "Error encountered at %d:%d (%d characters into string)",
128 (int) line, (int) ofs, err->pos);
130 exn_printf_line(v, "%s", pos);
133 exn_printf_line(v, "Error encountered at path %s", err->path);
139 static void exn_print_tree(struct value *exn, struct tree *tree) {
143 dump_tree(ms.stream, tree);
144 close_memstream(&ms);
145 exn_printf_line(exn, "%s", ms.buf);
149 static struct value *make_pathx_exn(struct info *info, struct pathx *p) {
155 msg = strdup(pathx_error(p, &txt, &pos));
159 v = make_exn_value(ref(info), "syntax error in path expression: %s", msg);
160 if (ALLOC_N(msg, strlen(txt) + 4) >= 0) {
161 strncpy(msg, txt, pos);
163 strcat(msg, txt + pos);
164 exn_add_lines(v, 1, msg);
169 static struct value *pathx_parse_glue(struct info *info, struct value *tree,
170 struct value *path, struct pathx **p) {
171 assert(path->tag == V_STRING);
172 assert(tree->tag == V_TREE);
174 if (pathx_parse(tree->origin, info->error, path->string->str, true,
175 NULL, NULL, p) != PATHX_NOERROR) {
176 return make_pathx_exn(ref(info), *p);
182 /* V_LENS -> V_STRING -> V_TREE */
183 static struct value *lens_get(struct info *info, struct value *l,
185 assert(l->tag == V_LENS);
186 assert(str->tag == V_STRING);
187 struct lns_error *err;
189 const char *text = str->string->str;
191 struct tree *tree = lns_get(info, l->lens, text, &err);
192 if (err == NULL && ! HAS_ERR(info)) {
193 v = make_value(V_TREE, ref(info));
194 v->origin = make_tree_origin(tree);
196 struct tree *t = make_tree_origin(tree);
201 v = make_exn_lns_error(info, err, text);
203 exn_printf_line(v, "Tree generated so far:");
204 exn_print_tree(v, tree);
213 /* V_LENS -> V_TREE -> V_STRING -> V_STRING */
214 static struct value *lens_put(struct info *info, struct value *l,
215 struct value *tree, struct value *str) {
216 assert(l->tag == V_LENS);
217 assert(tree->tag == V_TREE);
218 assert(str->tag == V_STRING);
222 struct lns_error *err;
225 lns_put(ms.stream, l->lens, tree->origin->children,
226 str->string->str, &err);
227 close_memstream(&ms);
229 if (err == NULL && ! HAS_ERR(info)) {
230 v = make_value(V_STRING, ref(info));
231 v->string = make_string(ms.buf);
233 v = make_exn_lns_error(info, err, str->string->str);
240 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
241 static struct value *tree_set_glue(struct info *info, struct value *path,
242 struct value *val, struct value *tree) {
243 // FIXME: This only works if TREE is not referenced more than once;
244 // otherwise we'll have some pretty weird semantics, and would really
245 // need to copy TREE first
246 assert(path->tag == V_STRING);
247 assert(val->tag == V_STRING);
248 assert(tree->tag == V_TREE);
250 struct tree *fake = NULL;
251 struct pathx *p = NULL;
252 struct value *result = NULL;
254 if (tree->origin->children == NULL) {
255 tree->origin->children = make_tree(NULL, NULL, tree->origin, NULL);
256 fake = tree->origin->children;
259 result = pathx_parse_glue(info, tree, path, &p);
263 if (tree_set(p, val->string->str) == NULL) {
264 result = make_exn_value(ref(info),
265 "Tree set of %s to '%s' failed",
266 path->string->str, val->string->str);
270 list_remove(fake, tree->origin->children);
280 /* V_STRING -> V_TREE -> V_TREE */
281 static struct value *tree_clear_glue(struct info *info, struct value *path,
282 struct value *tree) {
283 // FIXME: This only works if TREE is not referenced more than once;
284 // otherwise we'll have some pretty weird semantics, and would really
285 // need to copy TREE first
286 assert(path->tag == V_STRING);
287 assert(tree->tag == V_TREE);
289 struct tree *fake = NULL;
290 struct pathx *p = NULL;
291 struct value *result = NULL;
293 if (tree->origin->children == NULL) {
294 tree->origin->children = make_tree(NULL, NULL, tree->origin, NULL);
295 fake = tree->origin->children;
298 result = pathx_parse_glue(info, tree, path, &p);
302 if (tree_set(p, NULL) == NULL) {
303 result = make_exn_value(ref(info),
304 "Tree set of %s to NULL failed",
309 list_remove(fake, tree->origin->children);
319 static struct value *tree_insert_glue(struct info *info, struct value *label,
320 struct value *path, struct value *tree,
322 // FIXME: This only works if TREE is not referenced more than once;
323 // otherwise we'll have some pretty weird semantics, and would really
324 // need to copy TREE first
325 assert(label->tag == V_STRING);
326 assert(path->tag == V_STRING);
327 assert(tree->tag == V_TREE);
330 struct pathx *p = NULL;
331 struct value *result = NULL;
333 result = pathx_parse_glue(info, tree, path, &p);
337 r = tree_insert(p, label->string->str, before);
339 result = make_exn_value(ref(info),
340 "Tree insert of %s at %s failed",
341 label->string->str, path->string->str);
352 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
353 static struct value *tree_insa_glue(struct info *info, struct value *label,
354 struct value *path, struct value *tree) {
355 return tree_insert_glue(info, label, path, tree, 0);
359 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
360 static struct value *tree_insb_glue(struct info *info, struct value *label,
361 struct value *path, struct value *tree) {
362 return tree_insert_glue(info, label, path, tree, 1);
365 /* V_STRING -> V_TREE -> V_TREE */
366 static struct value *tree_rm_glue(struct info *info,
368 struct value *tree) {
369 // FIXME: This only works if TREE is not referenced more than once;
370 // otherwise we'll have some pretty weird semantics, and would really
371 // need to copy TREE first
372 assert(path->tag == V_STRING);
373 assert(tree->tag == V_TREE);
375 struct pathx *p = NULL;
376 struct value *result = NULL;
378 result = pathx_parse_glue(info, tree, path, &p);
382 if (tree_rm(p) == -1) {
383 result = make_exn_value(ref(info), "Tree rm of %s failed",
393 /* V_STRING -> V_STRING */
394 static struct value *gensym(struct info *info, struct value *prefix) {
395 assert(prefix->tag == V_STRING);
396 static unsigned int count = 0;
401 r = asprintf(&s, "%s%u", prefix->string->str, count);
404 v = make_value(V_STRING, ref(info));
405 v->string = make_string(s);
409 /* V_STRING -> V_FILTER */
410 static struct value *xform_incl(struct info *info, struct value *s) {
411 assert(s->tag == V_STRING);
412 struct value *v = make_value(V_FILTER, ref(info));
413 v->filter = make_filter(ref(s->string), 1);
417 /* V_STRING -> V_FILTER */
418 static struct value *xform_excl(struct info *info, struct value *s) {
419 assert(s->tag == V_STRING);
420 struct value *v = make_value(V_FILTER, ref(info));
421 v->filter = make_filter(ref(s->string), 0);
425 /* V_LENS -> V_FILTER -> V_TRANSFORM */
426 static struct value *xform_transform(struct info *info, struct value *l,
428 assert(l->tag == V_LENS);
429 assert(f->tag == V_FILTER);
430 if (l->lens->value || l->lens->key) {
431 return make_exn_value(ref(info), "Can not build a transform "
432 "from a lens that leaves a %s behind",
433 l->lens->key ? "key" : "value");
435 struct value *v = make_value(V_TRANSFORM, ref(info));
436 v->transform = make_transform(ref(l->lens), ref(f->filter));
440 static struct value *sys_getenv(struct info *info, struct value *n) {
441 assert(n->tag == V_STRING);
442 struct value *v = make_value(V_STRING, ref(info));
443 v->string = dup_string(getenv(n->string->str));
447 static struct value *sys_read_file(struct info *info, struct value *n) {
448 assert(n->tag == V_STRING);
451 str = xread_file(n->string->str);
453 char error_buf[1024];
455 errmsg = xstrerror(errno, error_buf, sizeof(error_buf));
456 struct value *exn = make_exn_value(ref(info),
457 "reading file %s failed:", n->string->str);
458 exn_printf_line(exn, "%s", errmsg);
461 struct value *v = make_value(V_STRING, ref(info));
462 v->string = make_string(str);
466 /* V_LENS -> V_LENS */
467 static struct value *lns_check_rec_glue(struct info *info,
468 struct value *l, struct value *r) {
469 assert(l->tag == V_LENS);
470 assert(r->tag == V_LENS);
471 int check = info->error->aug->flags & AUG_TYPE_CHECK;
473 return lns_check_rec(info, l->lens, r->lens, check);
480 /* V_STRING -> V_UNIT */
481 static struct value *pr_string(struct info *info, struct value *s) {
482 printf("%s", s->string->str);
483 return make_unit(ref(info));
486 /* V_REGEXP -> V_UNIT */
487 static struct value *pr_regexp(struct info *info, struct value *r) {
488 print_regexp(stdout, r->regexp);
489 return make_unit(ref(info));
492 /* V_STRING -> V_UNIT */
493 static struct value *pr_endline(struct info *info, struct value *s) {
494 printf("%s\n", s->string->str);
495 return make_unit(ref(info));
498 /* V_TREE -> V_TREE */
499 static struct value *pr_tree(ATTRIBUTE_UNUSED struct info *info,
501 print_tree_braces(stdout, 0, t->origin);
509 static struct value *lns_value_of_type(struct info *info, struct regexp *rx) {
510 struct value *result = make_value(V_REGEXP, ref(info));
512 result->regexp = ref(rx);
514 result->regexp = regexp_make_empty(ref(info));
518 /* V_LENS -> V_REGEXP */
519 static struct value *lns_ctype(struct info *info, struct value *l) {
520 return lns_value_of_type(info, l->lens->ctype);
523 /* V_LENS -> V_REGEXP */
524 static struct value *lns_atype(struct info *info, struct value *l) {
525 return lns_value_of_type(info, l->lens->atype);
528 /* V_LENS -> V_REGEXP */
529 static struct value *lns_vtype(struct info *info, struct value *l) {
530 return lns_value_of_type(info, l->lens->vtype);
533 /* V_LENS -> V_REGEXP */
534 static struct value *lns_ktype(struct info *info, struct value *l) {
535 return lns_value_of_type(info, l->lens->ktype);
538 /* V_LENS -> V_STRING */
539 static struct value *lns_fmt_atype(struct info *info, struct value *l) {
540 struct value *result = NULL;
544 r = lns_format_atype(l->lens, &s);
546 return info->error->exn;
547 result = make_value(V_STRING, ref(info));
548 result->string = make_string(s);
552 /* V_REGEXP -> V_STRING -> V_STRING */
553 static struct value *rx_match(struct info *info,
554 struct value *rx, struct value *s) {
555 struct value *result = NULL;
556 const char *str = s->string->str;
557 struct re_registers regs;
561 r = regexp_match(rx->regexp, str, strlen(str), 0, ®s);
564 make_exn_value(ref(info), "regexp match failed (internal error)");
571 match = strndup(str + regs.start[0], regs.end[0] - regs.start[0]);
574 result = info->error->exn;
576 result = make_value(V_STRING, ref(info));
577 result->string = make_string(match);
583 struct module *builtin_init(struct error *error) {
584 struct module *modl = module_create("Builtin");
587 #define DEFINE_NATIVE(modl, name, nargs, impl, types ...) \
588 r = define_native(error, modl, name, nargs, impl, ##types); \
589 if (r < 0) goto error;
591 DEFINE_NATIVE(modl, "gensym", 1, gensym, T_STRING, T_STRING);
593 /* Primitive lenses */
594 DEFINE_NATIVE(modl, "del", 2, lns_del, T_REGEXP, T_STRING, T_LENS);
595 DEFINE_NATIVE(modl, "store", 1, lns_store, T_REGEXP, T_LENS);
596 DEFINE_NATIVE(modl, "value", 1, lns_value, T_STRING, T_LENS);
597 DEFINE_NATIVE(modl, "key", 1, lns_key, T_REGEXP, T_LENS);
598 DEFINE_NATIVE(modl, "label", 1, lns_label, T_STRING, T_LENS);
599 DEFINE_NATIVE(modl, "seq", 1, lns_seq, T_STRING, T_LENS);
600 DEFINE_NATIVE(modl, "counter", 1, lns_counter, T_STRING, T_LENS);
601 DEFINE_NATIVE(modl, "square", 3, lns_square, T_LENS, T_LENS, T_LENS, T_LENS);
602 /* Applying lenses (mostly for tests) */
603 DEFINE_NATIVE(modl, "get", 2, lens_get, T_LENS, T_STRING, T_TREE);
604 DEFINE_NATIVE(modl, "put", 3, lens_put, T_LENS, T_TREE, T_STRING,
606 /* Tree manipulation used by the PUT tests */
607 DEFINE_NATIVE(modl, "set", 3, tree_set_glue, T_STRING, T_STRING, T_TREE,
609 DEFINE_NATIVE(modl, "clear", 2, tree_clear_glue, T_STRING, T_TREE,
611 DEFINE_NATIVE(modl, "rm", 2, tree_rm_glue, T_STRING, T_TREE, T_TREE);
612 DEFINE_NATIVE(modl, "insa", 3, tree_insa_glue, T_STRING, T_STRING, T_TREE,
614 DEFINE_NATIVE(modl, "insb", 3, tree_insb_glue, T_STRING, T_STRING, T_TREE,
616 /* Transforms and filters */
617 DEFINE_NATIVE(modl, "incl", 1, xform_incl, T_STRING, T_FILTER);
618 DEFINE_NATIVE(modl, "excl", 1, xform_excl, T_STRING, T_FILTER);
619 DEFINE_NATIVE(modl, "transform", 2, xform_transform, T_LENS, T_FILTER,
621 DEFINE_NATIVE(modl, LNS_CHECK_REC_NAME,
622 2, lns_check_rec_glue, T_LENS, T_LENS, T_LENS);
624 DEFINE_NATIVE(modl, "print_string", 1, pr_string, T_STRING, T_UNIT);
625 DEFINE_NATIVE(modl, "print_regexp", 1, pr_regexp, T_REGEXP, T_UNIT);
626 DEFINE_NATIVE(modl, "print_endline", 1, pr_endline, T_STRING, T_UNIT);
627 DEFINE_NATIVE(modl, "print_tree", 1, pr_tree, T_TREE, T_TREE);
629 /* Lens inspection */
630 DEFINE_NATIVE(modl, "lens_ctype", 1, lns_ctype, T_LENS, T_REGEXP);
631 DEFINE_NATIVE(modl, "lens_atype", 1, lns_atype, T_LENS, T_REGEXP);
632 DEFINE_NATIVE(modl, "lens_vtype", 1, lns_vtype, T_LENS, T_REGEXP);
633 DEFINE_NATIVE(modl, "lens_ktype", 1, lns_ktype, T_LENS, T_REGEXP);
634 DEFINE_NATIVE(modl, "lens_format_atype", 1, lns_fmt_atype,
637 /* Regexp matching */
638 DEFINE_NATIVE(modl, "regexp_match", 2, rx_match, T_REGEXP, T_STRING,
641 /* System functions */
642 struct module *sys = module_create("Sys");
644 DEFINE_NATIVE(sys, "getenv", 1, sys_getenv, T_STRING, T_STRING);
645 DEFINE_NATIVE(sys, "read_file", 1, sys_read_file, T_STRING, T_STRING);
654 * indent-tabs-mode: nil