/* * Typechecking of lenses */ static struct value *disjoint_check(struct info *info, const char *msg, struct regexp *r1, struct regexp *r2) { struct fa *fa1 = NULL; struct fa *fa2 = NULL; struct fa *fa = NULL; struct value *exn = NULL; exn = regexp_to_fa(r1, &fa1); if (exn != NULL) goto done; exn = regexp_to_fa(r2, &fa2); if (exn != NULL) goto done; fa = fa_intersect(fa1, fa2); if (! fa_is_basic(fa, FA_EMPTY)) { size_t xmpl_len; char *xmpl; fa_example(fa, &xmpl, &xmpl_len); exn = make_exn_value(ref(info), "overlapping lenses in %s", msg); exn_printf_line(exn, "Example matched by both: '%s'", xmpl); free(xmpl); } done: fa_free(fa); fa_free(fa1); fa_free(fa2); return exn; }
struct regexp * regexp_minus(struct info *info, struct regexp *r1, struct regexp *r2) { struct regexp *result = NULL; struct fa *fa = NULL, *fa1 = NULL, *fa2 = NULL; int r; char *s = NULL; size_t s_len; fa1 = regexp_to_fa(r1); ERR_BAIL(r1->info); fa2 = regexp_to_fa(r2); ERR_BAIL(r2->info); fa = fa_minus(fa1, fa2); if (fa == NULL) goto error; r = fa_as_regexp(fa, &s, &s_len); if (r < 0) goto error; if (s == NULL) { /* FA is the empty set, which we can't represent as a regexp */ goto error; } if (regexp_c_locale(&s, NULL) < 0) goto error; result = make_regexp(info, s, fa_is_nocase(fa)); s = NULL; done: fa_free(fa); fa_free(fa1); fa_free(fa2); free(s); return result; error: unref(result, regexp); goto done; }
static struct value *ambig_concat_check(struct info *info, const char *msg, struct regexp *r1, struct regexp *r2) { struct fa *fa1 = NULL; struct fa *fa2 = NULL; struct value *result = NULL; result = regexp_to_fa(r1, &fa1); if (result != NULL) goto done; result = regexp_to_fa(r2, &fa2); if (result != NULL) goto done; result = ambig_check(info, fa1, fa2, msg); done: fa_free(fa1); fa_free(fa2); return result; }
static struct value *ambig_iter_check(struct info *info, const char *msg, struct regexp *r) { struct fa *fas = NULL, *fa = NULL; struct value *result = NULL; result = regexp_to_fa(r, &fa); if (result != NULL) goto done; fas = fa_iter(fa, 0, -1); result = ambig_check(info, fa, fas, msg); done: fa_free(fa); fa_free(fas); return result; }
/* * Lens primitives */ struct value *lns_make_prim(enum lens_tag tag, struct info *info, struct regexp *regexp, struct string *string) { struct lens *lens = NULL; struct value *exn = NULL; struct fa *fa_slash = NULL; struct fa *fa_key = NULL; struct fa *fa_isect = NULL; /* Typecheck */ if (tag == L_KEY) { exn = str_to_fa(info, "(.|\n)*/(.|\n)*", &fa_slash); if (exn != NULL) goto error; exn = regexp_to_fa(regexp, &fa_key); if (exn != NULL) goto error; fa_isect = fa_intersect(fa_slash, fa_key); if (! fa_is_basic(fa_isect, FA_EMPTY)) { exn = make_exn_value(info, "The key regexp /%s/ matches a '/'", regexp->pattern->str); goto error; } fa_free(fa_isect); fa_free(fa_key); fa_free(fa_slash); fa_isect = fa_key = fa_slash = NULL; } else if (tag == L_LABEL) { if (strchr(string->str, SEP) != NULL) { exn = make_exn_value(info, "The label string \"%s\" contains a '/'", string->str); goto error; } } else if (tag == L_DEL) { int cnt; const char *dflt = string->str; cnt = regexp_match(regexp, dflt, strlen(dflt), 0, NULL); if (cnt != strlen(dflt)) { char *s = escape(dflt, -1); char *r = escape(regexp->pattern->str, -1); exn = make_exn_value(info, "del: the default value '%s' does not match /%s/", s, r); FREE(s); FREE(r); goto error; } } /* Build the actual lens */ lens = make_lens(tag, info); lens->regexp = regexp; lens->string = string; lens->key = (tag == L_KEY || tag == L_LABEL || tag == L_SEQ); lens->value = (tag == L_STORE); lens->consumes_value = (tag == L_STORE); lens->atype = regexp_make_empty(info); if (tag == L_DEL || tag == L_STORE || tag == L_KEY) { lens->ctype = ref(regexp); } else if (tag == L_LABEL || tag == L_SEQ || tag == L_COUNTER) { lens->ctype = regexp_make_empty(info); } else { assert(0); } return make_lens_value(lens); error: fa_free(fa_isect); fa_free(fa_key); fa_free(fa_slash); return exn; }