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,
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) {
152 const char *txt, *px_err;
155 px_err = pathx_error(p, &txt, &pos);
156 v = make_exn_value(ref(info), "syntax error in path expression: %s",
159 if (ALLOC_N(msg, strlen(txt) + 4) >= 0) {
160 strncpy(msg, txt, pos);
162 strcat(msg, txt + pos);
163 exn_add_lines(v, 1, msg);
168 static struct value *pathx_parse_glue(struct info *info, struct value *tree,
169 struct value *path, struct pathx **p) {
170 assert(path->tag == V_STRING);
171 assert(tree->tag == V_TREE);
173 if (pathx_parse(tree->origin, info->error, path->string->str, true,
174 NULL, NULL, p) != PATHX_NOERROR) {
175 return make_pathx_exn(info, *p);
181 /* V_LENS -> V_STRING -> V_TREE */
182 static struct value *lens_get(struct info *info, struct value *l,
184 assert(l->tag == V_LENS);
185 assert(str->tag == V_STRING);
186 struct lns_error *err;
188 const char *text = str->string->str;
190 struct tree *tree = lns_get(info, l->lens, text, &err);
191 if (err == NULL && ! HAS_ERR(info)) {
192 v = make_value(V_TREE, ref(info));
193 v->origin = make_tree_origin(tree);
195 struct tree *t = make_tree_origin(tree);
200 v = make_exn_lns_error(info, err, text);
202 exn_printf_line(v, "Tree generated so far:");
203 exn_print_tree(v, tree);
212 /* V_LENS -> V_TREE -> V_STRING -> V_STRING */
213 static struct value *lens_put(struct info *info, struct value *l,
214 struct value *tree, struct value *str) {
215 assert(l->tag == V_LENS);
216 assert(tree->tag == V_TREE);
217 assert(str->tag == V_STRING);
221 struct lns_error *err;
224 lns_put(ms.stream, l->lens, tree->origin->children,
225 str->string->str, &err);
226 close_memstream(&ms);
228 if (err == NULL && ! HAS_ERR(info)) {
229 v = make_value(V_STRING, ref(info));
230 v->string = make_string(ms.buf);
232 v = make_exn_lns_error(info, err, str->string->str);
239 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
240 static struct value *tree_set_glue(struct info *info, struct value *path,
241 struct value *val, struct value *tree) {
242 // FIXME: This only works if TREE is not referenced more than once;
243 // otherwise we'll have some pretty weird semantics, and would really
244 // need to copy TREE first
245 assert(path->tag == V_STRING);
246 assert(val->tag == V_STRING);
247 assert(tree->tag == V_TREE);
249 struct tree *fake = NULL;
250 struct pathx *p = NULL;
251 struct value *result = NULL;
253 if (tree->origin->children == NULL) {
254 tree->origin->children = make_tree(NULL, NULL, tree->origin, NULL);
255 fake = tree->origin->children;
258 result = pathx_parse_glue(info, tree, path, &p);
262 if (tree_set(p, val->string->str) == NULL) {
263 result = make_exn_value(ref(info),
264 "Tree set of %s to '%s' failed",
265 path->string->str, val->string->str);
269 list_remove(fake, tree->origin->children);
279 /* V_STRING -> V_TREE -> V_TREE */
280 static struct value *tree_clear_glue(struct info *info, struct value *path,
281 struct value *tree) {
282 // FIXME: This only works if TREE is not referenced more than once;
283 // otherwise we'll have some pretty weird semantics, and would really
284 // need to copy TREE first
285 assert(path->tag == V_STRING);
286 assert(tree->tag == V_TREE);
288 struct tree *fake = NULL;
289 struct pathx *p = NULL;
290 struct value *result = NULL;
292 if (tree->origin->children == NULL) {
293 tree->origin->children = make_tree(NULL, NULL, tree->origin, NULL);
294 fake = tree->origin->children;
297 result = pathx_parse_glue(info, tree, path, &p);
301 if (tree_set(p, NULL) == NULL) {
302 result = make_exn_value(ref(info),
303 "Tree set of %s to NULL failed",
308 list_remove(fake, tree->origin->children);
318 static struct value *tree_insert_glue(struct info *info, struct value *label,
319 struct value *path, struct value *tree,
321 // FIXME: This only works if TREE is not referenced more than once;
322 // otherwise we'll have some pretty weird semantics, and would really
323 // need to copy TREE first
324 assert(label->tag == V_STRING);
325 assert(path->tag == V_STRING);
326 assert(tree->tag == V_TREE);
329 struct pathx *p = NULL;
330 struct value *result = NULL;
332 result = pathx_parse_glue(info, tree, path, &p);
336 r = tree_insert(p, label->string->str, before);
338 result = make_exn_value(ref(info),
339 "Tree insert of %s at %s failed",
340 label->string->str, path->string->str);
351 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
352 static struct value *tree_insa_glue(struct info *info, struct value *label,
353 struct value *path, struct value *tree) {
354 return tree_insert_glue(info, label, path, tree, 0);
358 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
359 static struct value *tree_insb_glue(struct info *info, struct value *label,
360 struct value *path, struct value *tree) {
361 return tree_insert_glue(info, label, path, tree, 1);
364 /* V_STRING -> V_TREE -> V_TREE */
365 static struct value *tree_rm_glue(struct info *info,
367 struct value *tree) {
368 // FIXME: This only works if TREE is not referenced more than once;
369 // otherwise we'll have some pretty weird semantics, and would really
370 // need to copy TREE first
371 assert(path->tag == V_STRING);
372 assert(tree->tag == V_TREE);
374 struct pathx *p = NULL;
375 struct value *result = NULL;
377 result = pathx_parse_glue(info, tree, path, &p);
381 if (tree_rm(p) == -1) {
382 result = make_exn_value(ref(info), "Tree rm of %s failed",
392 /* V_STRING -> V_STRING */
393 static struct value *gensym(struct info *info, struct value *prefix) {
394 assert(prefix->tag == V_STRING);
395 static unsigned int count = 0;
400 r = asprintf(&s, "%s%u", prefix->string->str, count);
403 v = make_value(V_STRING, ref(info));
404 v->string = make_string(s);
408 /* V_STRING -> V_FILTER */
409 static struct value *xform_incl(struct info *info, struct value *s) {
410 assert(s->tag == V_STRING);
411 struct value *v = make_value(V_FILTER, ref(info));
412 v->filter = make_filter(ref(s->string), 1);
416 /* V_STRING -> V_FILTER */
417 static struct value *xform_excl(struct info *info, struct value *s) {
418 assert(s->tag == V_STRING);
419 struct value *v = make_value(V_FILTER, ref(info));
420 v->filter = make_filter(ref(s->string), 0);
424 /* V_LENS -> V_FILTER -> V_TRANSFORM */
425 static struct value *xform_transform(struct info *info, struct value *l,
427 assert(l->tag == V_LENS);
428 assert(f->tag == V_FILTER);
429 if (l->lens->value || l->lens->key) {
430 return make_exn_value(ref(info), "Can not build a transform "
431 "from a lens that leaves a %s behind",
432 l->lens->key ? "key" : "value");
434 struct value *v = make_value(V_TRANSFORM, ref(info));
435 v->transform = make_transform(ref(l->lens), ref(f->filter));
439 static struct value *sys_getenv(struct info *info, struct value *n) {
440 assert(n->tag == V_STRING);
441 struct value *v = make_value(V_STRING, ref(info));
442 v->string = dup_string(getenv(n->string->str));
446 static struct value *sys_read_file(struct info *info, struct value *n) {
447 assert(n->tag == V_STRING);
450 str = xread_file(n->string->str);
452 char error_buf[1024];
454 errmsg = xstrerror(errno, error_buf, sizeof(error_buf));
455 struct value *exn = make_exn_value(ref(info),
456 "reading file %s failed:", n->string->str);
457 exn_printf_line(exn, "%s", errmsg);
460 struct value *v = make_value(V_STRING, ref(info));
461 v->string = make_string(str);
465 /* V_LENS -> V_LENS */
466 static struct value *lns_check_rec_glue(struct info *info,
467 struct value *l, struct value *r) {
468 assert(l->tag == V_LENS);
469 assert(r->tag == V_LENS);
470 int check = info->error->aug->flags & AUG_TYPE_CHECK;
472 return lns_check_rec(info, l->lens, r->lens, check);
479 /* V_STRING -> V_UNIT */
480 static struct value *pr_string(struct info *info, struct value *s) {
481 printf("%s", s->string->str);
482 return make_unit(ref(info));
485 /* V_REGEXP -> V_UNIT */
486 static struct value *pr_regexp(struct info *info, struct value *r) {
487 print_regexp(stdout, r->regexp);
488 return make_unit(ref(info));
491 /* V_STRING -> V_UNIT */
492 static struct value *pr_endline(struct info *info, struct value *s) {
493 printf("%s\n", s->string->str);
494 return make_unit(ref(info));
497 /* V_TREE -> V_TREE */
498 static struct value *pr_tree(ATTRIBUTE_UNUSED struct info *info,
500 print_tree_braces(stdout, 0, t->origin);
508 static struct value *lns_value_of_type(struct info *info, struct regexp *rx) {
509 struct value *result = make_value(V_REGEXP, ref(info));
511 result->regexp = ref(rx);
513 result->regexp = regexp_make_empty(ref(info));
517 /* V_LENS -> V_REGEXP */
518 static struct value *lns_ctype(struct info *info, struct value *l) {
519 return lns_value_of_type(info, l->lens->ctype);
522 /* V_LENS -> V_REGEXP */
523 static struct value *lns_atype(struct info *info, struct value *l) {
524 return lns_value_of_type(info, l->lens->atype);
527 /* V_LENS -> V_REGEXP */
528 static struct value *lns_vtype(struct info *info, struct value *l) {
529 return lns_value_of_type(info, l->lens->vtype);
532 /* V_LENS -> V_REGEXP */
533 static struct value *lns_ktype(struct info *info, struct value *l) {
534 return lns_value_of_type(info, l->lens->ktype);
537 /* V_LENS -> V_STRING */
538 static struct value *lns_fmt_atype(struct info *info, struct value *l) {
539 struct value *result = NULL;
543 r = lns_format_atype(l->lens, &s);
545 return info->error->exn;
546 result = make_value(V_STRING, ref(info));
547 result->string = make_string(s);
551 /* V_REGEXP -> V_STRING -> V_STRING */
552 static struct value *rx_match(struct info *info,
553 struct value *rx, struct value *s) {
554 struct value *result = NULL;
555 const char *str = s->string->str;
556 struct re_registers regs;
560 r = regexp_match(rx->regexp, str, strlen(str), 0, ®s);
563 make_exn_value(ref(info), "regexp match failed (internal error)");
570 match = strndup(str + regs.start[0], regs.end[0] - regs.start[0]);
573 result = info->error->exn;
575 result = make_value(V_STRING, ref(info));
576 result->string = make_string(match);
582 struct module *builtin_init(struct error *error) {
583 struct module *modl = module_create("Builtin");
586 #define DEFINE_NATIVE(modl, name, nargs, impl, types ...) \
587 r = define_native(error, modl, name, nargs, impl, ##types); \
588 if (r < 0) goto error;
590 DEFINE_NATIVE(modl, "gensym", 1, gensym, T_STRING, T_STRING);
592 /* Primitive lenses */
593 DEFINE_NATIVE(modl, "del", 2, lns_del, T_REGEXP, T_STRING, T_LENS);
594 DEFINE_NATIVE(modl, "store", 1, lns_store, T_REGEXP, T_LENS);
595 DEFINE_NATIVE(modl, "value", 1, lns_value, T_STRING, T_LENS);
596 DEFINE_NATIVE(modl, "key", 1, lns_key, T_REGEXP, T_LENS);
597 DEFINE_NATIVE(modl, "label", 1, lns_label, T_STRING, T_LENS);
598 DEFINE_NATIVE(modl, "seq", 1, lns_seq, T_STRING, T_LENS);
599 DEFINE_NATIVE(modl, "counter", 1, lns_counter, T_STRING, T_LENS);
600 DEFINE_NATIVE(modl, "square", 3, lns_square, T_LENS, T_LENS, T_LENS, T_LENS);
601 /* Applying lenses (mostly for tests) */
602 DEFINE_NATIVE(modl, "get", 2, lens_get, T_LENS, T_STRING, T_TREE);
603 DEFINE_NATIVE(modl, "put", 3, lens_put, T_LENS, T_TREE, T_STRING,
605 /* Tree manipulation used by the PUT tests */
606 DEFINE_NATIVE(modl, "set", 3, tree_set_glue, T_STRING, T_STRING, T_TREE,
608 DEFINE_NATIVE(modl, "clear", 2, tree_clear_glue, T_STRING, T_TREE,
610 DEFINE_NATIVE(modl, "rm", 2, tree_rm_glue, T_STRING, T_TREE, T_TREE);
611 DEFINE_NATIVE(modl, "insa", 3, tree_insa_glue, T_STRING, T_STRING, T_TREE,
613 DEFINE_NATIVE(modl, "insb", 3, tree_insb_glue, T_STRING, T_STRING, T_TREE,
615 /* Transforms and filters */
616 DEFINE_NATIVE(modl, "incl", 1, xform_incl, T_STRING, T_FILTER);
617 DEFINE_NATIVE(modl, "excl", 1, xform_excl, T_STRING, T_FILTER);
618 DEFINE_NATIVE(modl, "transform", 2, xform_transform, T_LENS, T_FILTER,
620 DEFINE_NATIVE(modl, LNS_CHECK_REC_NAME,
621 2, lns_check_rec_glue, T_LENS, T_LENS, T_LENS);
623 DEFINE_NATIVE(modl, "print_string", 1, pr_string, T_STRING, T_UNIT);
624 DEFINE_NATIVE(modl, "print_regexp", 1, pr_regexp, T_REGEXP, T_UNIT);
625 DEFINE_NATIVE(modl, "print_endline", 1, pr_endline, T_STRING, T_UNIT);
626 DEFINE_NATIVE(modl, "print_tree", 1, pr_tree, T_TREE, T_TREE);
628 /* Lens inspection */
629 DEFINE_NATIVE(modl, "lens_ctype", 1, lns_ctype, T_LENS, T_REGEXP);
630 DEFINE_NATIVE(modl, "lens_atype", 1, lns_atype, T_LENS, T_REGEXP);
631 DEFINE_NATIVE(modl, "lens_vtype", 1, lns_vtype, T_LENS, T_REGEXP);
632 DEFINE_NATIVE(modl, "lens_ktype", 1, lns_ktype, T_LENS, T_REGEXP);
633 DEFINE_NATIVE(modl, "lens_format_atype", 1, lns_fmt_atype,
636 /* Regexp matching */
637 DEFINE_NATIVE(modl, "regexp_match", 2, rx_match, T_REGEXP, T_STRING,
640 /* System functions */
641 struct module *sys = module_create("Sys");
643 DEFINE_NATIVE(sys, "getenv", 1, sys_getenv, T_STRING, T_STRING);
644 DEFINE_NATIVE(sys, "read_file", 1, sys_read_file, T_STRING, T_STRING);
653 * indent-tabs-mode: nil