2 * builtin.c: builtin primitives
4 * Copyright (C) 2007-2016 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, struct value **argv) {
46 struct value *rxp = argv[0];
47 struct value *dflt = argv[1];
49 assert(rxp->tag == V_REGEXP);
50 assert(dflt->tag == V_STRING);
51 return lns_make_prim(L_DEL, ref(info),
52 ref(rxp->regexp), ref(dflt->string));
55 /* V_REGEXP -> V_LENS */
56 static struct value *lns_store(struct info *info, struct value **argv) {
57 struct value *rxp = argv[0];
59 assert(rxp->tag == V_REGEXP);
60 return lns_make_prim(L_STORE, ref(info), ref(rxp->regexp), NULL);
63 /* V_STRING -> V_LENS */
64 static struct value *lns_value(struct info *info, struct value **argv) {
65 struct value *str = argv[0];
67 assert(str->tag == V_STRING);
68 return lns_make_prim(L_VALUE, ref(info), NULL, ref(str->string));
71 /* V_REGEXP -> V_LENS */
72 static struct value *lns_key(struct info *info, struct value **argv) {
73 struct value *rxp = argv[0];
75 assert(rxp->tag == V_REGEXP);
76 return lns_make_prim(L_KEY, ref(info), ref(rxp->regexp), NULL);
79 /* V_STRING -> V_LENS */
80 static struct value *lns_label(struct info *info, struct value **argv) {
81 struct value *str = argv[0];
83 assert(str->tag == V_STRING);
84 return lns_make_prim(L_LABEL, ref(info), NULL, ref(str->string));
87 /* V_STRING -> V_LENS */
88 static struct value *lns_seq(struct info *info, struct value **argv) {
89 struct value *str = argv[0];
91 assert(str->tag == V_STRING);
92 return lns_make_prim(L_SEQ, ref(info), NULL, ref(str->string));
95 /* V_STRING -> V_LENS */
96 static struct value *lns_counter(struct info *info, struct value **argv) {
97 struct value *str = argv[0];
99 assert(str->tag == V_STRING);
100 return lns_make_prim(L_COUNTER, ref(info), NULL, ref(str->string));
103 /* V_LENS -> V_LENS -> V_LENS -> V_LENS */
104 static struct value *lns_square(struct info *info, struct value **argv) {
105 struct value *l1 = argv[0];
106 struct value *l2 = argv[1];
107 struct value *l3 = argv[2];
109 assert(l1->tag == V_LENS);
110 assert(l2->tag == V_LENS);
111 assert(l3->tag == V_LENS);
112 int check = typecheck_p(info);
114 return lns_make_square(ref(info), ref(l1->lens), ref(l2->lens), ref(l3->lens), check);
117 static void exn_lns_error_detail(struct value *exn, const char *label,
122 char *s = format_info(lens->info);
123 exn_printf_line(exn, "%s: %s", label, s);
127 static struct value *make_exn_lns_error(struct info *info,
128 struct lns_error *err,
133 return info->error->exn;
135 v = make_exn_value(ref(info), "%s", err->message);
136 exn_lns_error_detail(v, "Lens", err->lens);
137 exn_lns_error_detail(v, " Last match", err->last);
138 exn_lns_error_detail(v, " Not matching", err->next);
140 char *pos = format_pos(text, err->pos);
142 calc_line_ofs(text, err->pos, &line, &ofs);
144 "Error encountered at %d:%d (%d characters into string)",
145 (int) line, (int) ofs, err->pos);
147 exn_printf_line(v, "%s", pos);
150 exn_printf_line(v, "Error encountered at path %s", err->path);
156 static void exn_print_tree(struct value *exn, struct tree *tree) {
160 dump_tree(ms.stream, tree);
161 close_memstream(&ms);
162 exn_printf_line(exn, "%s", ms.buf);
166 static struct value *make_pathx_exn(struct info *info, struct pathx *p) {
169 const char *txt, *px_err;
172 px_err = pathx_error(p, &txt, &pos);
173 v = make_exn_value(ref(info), "syntax error in path expression: %s",
176 if (ALLOC_N(msg, strlen(txt) + 4) >= 0) {
177 strncpy(msg, txt, pos);
179 strcat(msg, txt + pos);
180 exn_add_lines(v, 1, msg);
185 static struct value *pathx_parse_glue(struct info *info, struct value *tree,
186 struct value *path, struct pathx **p) {
187 assert(path->tag == V_STRING);
188 assert(tree->tag == V_TREE);
190 if (pathx_parse(tree->origin, info->error, path->string->str, true,
191 NULL, NULL, p) != PATHX_NOERROR) {
192 return make_pathx_exn(info, *p);
198 /* V_LENS -> V_STRING -> V_TREE */
199 static struct value *lens_get(struct info *info, struct value **argv) {
200 struct value *l = argv[0];
201 struct value *str = argv[1];
203 assert(l->tag == V_LENS);
204 assert(str->tag == V_STRING);
205 struct lns_error *err;
207 const char *text = str->string->str;
209 struct tree *tree = lns_get(info, l->lens, text, 0, &err);
210 if (err == NULL && ! HAS_ERR(info)) {
211 v = make_value(V_TREE, ref(info));
212 v->origin = make_tree_origin(tree);
214 struct tree *t = make_tree_origin(tree);
219 v = make_exn_lns_error(info, err, text);
221 exn_printf_line(v, "Tree generated so far:");
222 exn_print_tree(v, tree);
231 /* V_LENS -> V_TREE -> V_STRING -> V_STRING */
232 static struct value *lens_put(struct info *info, struct value **argv) {
233 struct value *l = argv[0];
234 struct value *tree = argv[1];
235 struct value *str = argv[2];
237 assert(l->tag == V_LENS);
238 assert(tree->tag == V_TREE);
239 assert(str->tag == V_STRING);
243 struct lns_error *err;
246 lns_put(info, ms.stream, l->lens, tree->origin->children,
247 str->string->str, 0, &err);
248 close_memstream(&ms);
250 if (err == NULL && ! HAS_ERR(info)) {
251 v = make_value(V_STRING, ref(info));
252 v->string = make_string(ms.buf);
254 v = make_exn_lns_error(info, err, str->string->str);
261 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
262 static struct value *tree_set_glue(struct info *info, struct value **argv) {
263 // FIXME: This only works if TREE is not referenced more than once;
264 // otherwise we'll have some pretty weird semantics, and would really
265 // need to copy TREE first
266 struct value *path = argv[0];
267 struct value *val = argv[1];
268 struct value *tree = argv[2];
270 assert(path->tag == V_STRING);
271 assert(val->tag == V_STRING);
272 assert(tree->tag == V_TREE);
274 struct tree *fake = NULL;
275 struct pathx *p = NULL;
276 struct value *result = NULL;
278 if (tree->origin->children == NULL) {
279 tree->origin->children = make_tree(NULL, NULL, tree->origin, NULL);
280 fake = tree->origin->children;
283 result = pathx_parse_glue(info, tree, path, &p);
287 if (tree_set(p, val->string->str) == NULL) {
288 result = make_exn_value(ref(info),
289 "Tree set of %s to '%s' failed",
290 path->string->str, val->string->str);
294 list_remove(fake, tree->origin->children);
304 /* V_STRING -> V_TREE -> V_TREE */
305 static struct value *tree_clear_glue(struct info *info, struct value **argv) {
306 // FIXME: This only works if TREE is not referenced more than once;
307 // otherwise we'll have some pretty weird semantics, and would really
308 // need to copy TREE first
309 struct value *path = argv[0];
310 struct value *tree = argv[1];
312 assert(path->tag == V_STRING);
313 assert(tree->tag == V_TREE);
315 struct tree *fake = NULL;
316 struct pathx *p = NULL;
317 struct value *result = NULL;
319 if (tree->origin->children == NULL) {
320 tree->origin->children = make_tree(NULL, NULL, tree->origin, NULL);
321 fake = tree->origin->children;
324 result = pathx_parse_glue(info, tree, path, &p);
328 if (tree_set(p, NULL) == NULL) {
329 result = make_exn_value(ref(info),
330 "Tree set of %s to NULL failed",
335 list_remove(fake, tree->origin->children);
345 static struct value *tree_insert_glue(struct info *info, struct value *label,
346 struct value *path, struct value *tree,
348 // FIXME: This only works if TREE is not referenced more than once;
349 // otherwise we'll have some pretty weird semantics, and would really
350 // need to copy TREE first
351 assert(label->tag == V_STRING);
352 assert(path->tag == V_STRING);
353 assert(tree->tag == V_TREE);
356 struct pathx *p = NULL;
357 struct value *result = NULL;
359 result = pathx_parse_glue(info, tree, path, &p);
363 r = tree_insert(p, label->string->str, before);
365 result = make_exn_value(ref(info),
366 "Tree insert of %s at %s failed",
367 label->string->str, path->string->str);
378 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
379 static struct value *tree_insa_glue(struct info *info, struct value **argv) {
380 struct value *label = argv[0];
381 struct value *path = argv[1];
382 struct value *tree = argv[2];
384 return tree_insert_glue(info, label, path, tree, 0);
388 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
389 static struct value *tree_insb_glue(struct info *info, struct value **argv) {
390 struct value *label = argv[0];
391 struct value *path = argv[1];
392 struct value *tree = argv[2];
394 return tree_insert_glue(info, label, path, tree, 1);
397 /* V_STRING -> V_TREE -> V_TREE */
398 static struct value *tree_rm_glue(struct info *info, struct value **argv) {
399 // FIXME: This only works if TREE is not referenced more than once;
400 // otherwise we'll have some pretty weird semantics, and would really
401 // need to copy TREE first
402 struct value *path = argv[0];
403 struct value *tree = argv[1];
405 assert(path->tag == V_STRING);
406 assert(tree->tag == V_TREE);
408 struct pathx *p = NULL;
409 struct value *result = NULL;
411 result = pathx_parse_glue(info, tree, path, &p);
415 if (tree_rm(p) == -1) {
416 result = make_exn_value(ref(info), "Tree rm of %s failed",
426 /* V_STRING -> V_STRING */
427 static struct value *gensym(struct info *info, struct value **argv) {
428 struct value *prefix = argv[0];
430 assert(prefix->tag == V_STRING);
431 static unsigned int count = 0;
436 r = asprintf(&s, "%s%u", prefix->string->str, count);
439 v = make_value(V_STRING, ref(info));
440 v->string = make_string(s);
444 /* V_STRING -> V_FILTER */
445 static struct value *xform_incl(struct info *info, struct value **argv) {
446 struct value *s = argv[0];
448 assert(s->tag == V_STRING);
449 struct value *v = make_value(V_FILTER, ref(info));
450 v->filter = make_filter(ref(s->string), 1);
454 /* V_STRING -> V_FILTER */
455 static struct value *xform_excl(struct info *info, struct value **argv) {
456 struct value *s = argv[0];
458 assert(s->tag == V_STRING);
459 struct value *v = make_value(V_FILTER, ref(info));
460 v->filter = make_filter(ref(s->string), 0);
464 /* V_LENS -> V_FILTER -> V_TRANSFORM */
465 static struct value *xform_transform(struct info *info, struct value **argv) {
466 struct value *l = argv[0];
467 struct value *f = argv[1];
469 assert(l->tag == V_LENS);
470 assert(f->tag == V_FILTER);
471 if (l->lens->value || l->lens->key) {
472 return make_exn_value(ref(info), "Can not build a transform "
473 "from a lens that leaves a %s behind",
474 l->lens->key ? "key" : "value");
476 struct value *v = make_value(V_TRANSFORM, ref(info));
477 v->transform = make_transform(ref(l->lens), ref(f->filter));
481 static struct value *sys_getenv(struct info *info, struct value **argv) {
482 assert(argv[0]->tag == V_STRING);
483 struct value *v = make_value(V_STRING, ref(info));
484 v->string = dup_string(getenv(argv[0]->string->str));
488 static struct value *sys_read_file(struct info *info, struct value **argv) {
489 struct value *n = argv[0];
491 assert(n->tag == V_STRING);
494 str = xread_file(n->string->str);
496 char error_buf[1024];
498 errmsg = xstrerror(errno, error_buf, sizeof(error_buf));
499 struct value *exn = make_exn_value(ref(info),
500 "reading file %s failed:", n->string->str);
501 exn_printf_line(exn, "%s", errmsg);
504 struct value *v = make_value(V_STRING, ref(info));
505 v->string = make_string(str);
509 /* V_LENS -> V_LENS */
510 static struct value *lns_check_rec_glue(struct info *info,
511 struct value **argv) {
512 struct value *l = argv[0];
513 struct value *r = argv[1];
515 assert(l->tag == V_LENS);
516 assert(r->tag == V_LENS);
517 int check = typecheck_p(info);
519 return lns_check_rec(info, l->lens, r->lens, check);
526 /* V_STRING -> V_UNIT */
527 static struct value *pr_string(struct info *info, struct value **argv) {
528 printf("%s", argv[0]->string->str);
529 return make_unit(ref(info));
532 /* V_REGEXP -> V_UNIT */
533 static struct value *pr_regexp(struct info *info, struct value **argv) {
534 print_regexp(stdout, argv[0]->regexp);
535 return make_unit(ref(info));
538 /* V_STRING -> V_UNIT */
539 static struct value *pr_endline(struct info *info, struct value **argv) {
540 printf("%s\n", argv[0]->string->str);
541 return make_unit(ref(info));
544 /* V_TREE -> V_TREE */
545 static struct value *pr_tree(ATTRIBUTE_UNUSED struct info *info,
546 struct value **argv) {
547 print_tree_braces(stdout, 0, argv[0]->origin);
555 static struct value *lns_value_of_type(struct info *info, struct regexp *rx) {
556 struct value *result = make_value(V_REGEXP, ref(info));
558 result->regexp = ref(rx);
560 result->regexp = regexp_make_empty(ref(info));
564 /* V_LENS -> V_REGEXP */
565 static struct value *lns_ctype(struct info *info, struct value **argv) {
566 return lns_value_of_type(info, argv[0]->lens->ctype);
569 /* V_LENS -> V_REGEXP */
570 static struct value *lns_atype(struct info *info, struct value **argv) {
571 return lns_value_of_type(info, argv[0]->lens->atype);
574 /* V_LENS -> V_REGEXP */
575 static struct value *lns_vtype(struct info *info, struct value **argv) {
576 return lns_value_of_type(info, argv[0]->lens->vtype);
579 /* V_LENS -> V_REGEXP */
580 static struct value *lns_ktype(struct info *info, struct value **argv) {
581 return lns_value_of_type(info, argv[0]->lens->ktype);
584 /* V_LENS -> V_STRING */
585 static struct value *lns_fmt_atype(struct info *info, struct value **argv) {
586 struct value *l = argv[0];
588 struct value *result = NULL;
592 r = lns_format_atype(l->lens, &s);
594 return info->error->exn;
595 result = make_value(V_STRING, ref(info));
596 result->string = make_string(s);
600 /* V_REGEXP -> V_STRING -> V_STRING */
601 static struct value *rx_match(struct info *info, struct value **argv) {
602 struct value *rx = argv[0];
603 struct value *s = argv[1];
605 struct value *result = NULL;
606 const char *str = s->string->str;
607 struct re_registers regs;
611 r = regexp_match(rx->regexp, str, strlen(str), 0, ®s);
614 make_exn_value(ref(info), "regexp match failed (internal error)");
621 match = strndup(str + regs.start[0], regs.end[0] - regs.start[0]);
624 result = info->error->exn;
626 result = make_value(V_STRING, ref(info));
627 result->string = make_string(match);
633 struct module *builtin_init(struct error *error) {
634 struct module *modl = module_create("Builtin");
637 #define DEFINE_NATIVE(modl, name, nargs, impl, types ...) \
638 r = define_native(error, modl, name, nargs, impl, ##types); \
639 if (r < 0) goto error;
641 DEFINE_NATIVE(modl, "gensym", 1, gensym, T_STRING, T_STRING);
643 /* Primitive lenses */
644 DEFINE_NATIVE(modl, "del", 2, lns_del, T_REGEXP, T_STRING, T_LENS);
645 DEFINE_NATIVE(modl, "store", 1, lns_store, T_REGEXP, T_LENS);
646 DEFINE_NATIVE(modl, "value", 1, lns_value, T_STRING, T_LENS);
647 DEFINE_NATIVE(modl, "key", 1, lns_key, T_REGEXP, T_LENS);
648 DEFINE_NATIVE(modl, "label", 1, lns_label, T_STRING, T_LENS);
649 DEFINE_NATIVE(modl, "seq", 1, lns_seq, T_STRING, T_LENS);
650 DEFINE_NATIVE(modl, "counter", 1, lns_counter, T_STRING, T_LENS);
651 DEFINE_NATIVE(modl, "square", 3, lns_square, T_LENS, T_LENS, T_LENS, T_LENS);
652 /* Applying lenses (mostly for tests) */
653 DEFINE_NATIVE(modl, "get", 2, lens_get, T_LENS, T_STRING, T_TREE);
654 DEFINE_NATIVE(modl, "put", 3, lens_put, T_LENS, T_TREE, T_STRING,
656 /* Tree manipulation used by the PUT tests */
657 DEFINE_NATIVE(modl, "set", 3, tree_set_glue, T_STRING, T_STRING, T_TREE,
659 DEFINE_NATIVE(modl, "clear", 2, tree_clear_glue, T_STRING, T_TREE,
661 DEFINE_NATIVE(modl, "rm", 2, tree_rm_glue, T_STRING, T_TREE, T_TREE);
662 DEFINE_NATIVE(modl, "insa", 3, tree_insa_glue, T_STRING, T_STRING, T_TREE,
664 DEFINE_NATIVE(modl, "insb", 3, tree_insb_glue, T_STRING, T_STRING, T_TREE,
666 /* Transforms and filters */
667 DEFINE_NATIVE(modl, "incl", 1, xform_incl, T_STRING, T_FILTER);
668 DEFINE_NATIVE(modl, "excl", 1, xform_excl, T_STRING, T_FILTER);
669 DEFINE_NATIVE(modl, "transform", 2, xform_transform, T_LENS, T_FILTER,
671 DEFINE_NATIVE(modl, LNS_CHECK_REC_NAME,
672 2, lns_check_rec_glue, T_LENS, T_LENS, T_LENS);
674 DEFINE_NATIVE(modl, "print_string", 1, pr_string, T_STRING, T_UNIT);
675 DEFINE_NATIVE(modl, "print_regexp", 1, pr_regexp, T_REGEXP, T_UNIT);
676 DEFINE_NATIVE(modl, "print_endline", 1, pr_endline, T_STRING, T_UNIT);
677 DEFINE_NATIVE(modl, "print_tree", 1, pr_tree, T_TREE, T_TREE);
679 /* Lens inspection */
680 DEFINE_NATIVE(modl, "lens_ctype", 1, lns_ctype, T_LENS, T_REGEXP);
681 DEFINE_NATIVE(modl, "lens_atype", 1, lns_atype, T_LENS, T_REGEXP);
682 DEFINE_NATIVE(modl, "lens_vtype", 1, lns_vtype, T_LENS, T_REGEXP);
683 DEFINE_NATIVE(modl, "lens_ktype", 1, lns_ktype, T_LENS, T_REGEXP);
684 DEFINE_NATIVE(modl, "lens_format_atype", 1, lns_fmt_atype,
687 /* Regexp matching */
688 DEFINE_NATIVE(modl, "regexp_match", 2, rx_match, T_REGEXP, T_STRING,
691 /* System functions */
692 struct module *sys = module_create("Sys");
694 DEFINE_NATIVE(sys, "getenv", 1, sys_getenv, T_STRING, T_STRING);
695 DEFINE_NATIVE(sys, "read_file", 1, sys_read_file, T_STRING, T_STRING);
704 * indent-tabs-mode: nil