isl_input.c: accept_div: do not push back unexpected tokens
[isl.git] / isl_input.c
blobdffb2cd7797a7231bc593166cf4093263cc33baa
1 /*
2 * Copyright 2008-2009 Katholieke Universiteit Leuven
3 * Copyright 2010 INRIA Saclay
4 * Copyright 2012-2013 Ecole Normale Superieure
5 * Copyright 2019,2022 Cerebras Systems
7 * Use of this software is governed by the MIT license
9 * Written by Sven Verdoolaege, K.U.Leuven, Departement
10 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
11 * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
12 * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
13 * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
14 * and Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA
17 #include <ctype.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <isl_ctx_private.h>
21 #include <isl_map_private.h>
22 #include <isl_id_private.h>
23 #include <isl/set.h>
24 #include <isl_seq.h>
25 #include <isl_stream_private.h>
26 #include <isl/obj.h>
27 #include "isl_polynomial_private.h"
28 #include <isl/union_set.h>
29 #include <isl/union_map.h>
30 #include <isl_mat_private.h>
31 #include <isl_aff_private.h>
32 #include <isl_vec_private.h>
33 #include <isl/list.h>
34 #include <isl_val_private.h>
36 struct variable {
37 char *name;
38 int pos;
39 struct variable *next;
42 struct vars {
43 struct isl_ctx *ctx;
44 int n;
45 struct variable *v;
48 static struct vars *vars_new(struct isl_ctx *ctx)
50 struct vars *v;
51 v = isl_alloc_type(ctx, struct vars);
52 if (!v)
53 return NULL;
54 v->ctx = ctx;
55 v->n = 0;
56 v->v = NULL;
57 return v;
60 static void variable_free(struct variable *var)
62 while (var) {
63 struct variable *next = var->next;
64 free(var->name);
65 free(var);
66 var = next;
70 static void vars_free(struct vars *v)
72 if (!v)
73 return;
74 variable_free(v->v);
75 free(v);
78 static void vars_drop(struct vars *v, int n)
80 struct variable *var;
82 if (!v || !v->v)
83 return;
85 v->n -= n;
87 var = v->v;
88 while (--n >= 0) {
89 struct variable *next = var->next;
90 free(var->name);
91 free(var);
92 var = next;
94 v->v = var;
97 static struct variable *variable_new(struct vars *v, const char *name, int len,
98 int pos)
100 struct variable *var;
101 var = isl_calloc_type(v->ctx, struct variable);
102 if (!var)
103 goto error;
104 var->name = strdup(name);
105 var->name[len] = '\0';
106 var->pos = pos;
107 var->next = v->v;
108 return var;
109 error:
110 variable_free(v->v);
111 return NULL;
114 static int vars_pos(struct vars *v, const char *s, int len)
116 int pos;
117 struct variable *q;
119 if (len == -1)
120 len = strlen(s);
121 for (q = v->v; q; q = q->next) {
122 if (strncmp(q->name, s, len) == 0 && q->name[len] == '\0')
123 break;
125 if (q)
126 pos = q->pos;
127 else {
128 pos = v->n;
129 v->v = variable_new(v, s, len, v->n);
130 if (!v->v)
131 return -1;
132 v->n++;
134 return pos;
137 static int vars_add_anon(struct vars *v)
139 v->v = variable_new(v, "", 0, v->n);
141 if (!v->v)
142 return -1;
143 v->n++;
145 return 0;
148 /* Obtain next token, with some preprocessing.
149 * In particular, evaluate expressions of the form x^y,
150 * with x and y values.
152 static struct isl_token *next_token(__isl_keep isl_stream *s)
154 struct isl_token *tok, *tok2;
156 tok = isl_stream_next_token(s);
157 if (!tok || tok->type != ISL_TOKEN_VALUE)
158 return tok;
159 if (!isl_stream_eat_if_available(s, '^'))
160 return tok;
161 tok2 = isl_stream_next_token(s);
162 if (!tok2 || tok2->type != ISL_TOKEN_VALUE) {
163 isl_stream_error(s, tok2, "expecting constant value");
164 goto error;
167 isl_int_pow_ui(tok->u.v, tok->u.v, isl_int_get_ui(tok2->u.v));
169 isl_token_free(tok2);
170 return tok;
171 error:
172 isl_token_free(tok);
173 isl_token_free(tok2);
174 return NULL;
177 /* Read an isl_val from "s".
179 * The following token sequences are recognized
181 * "infty" -> infty
182 * "-" "infty" -> -infty
183 * "NaN" -> NaN
184 * n "/" d -> n/d
185 * v -> v
187 * where n, d and v are integer constants.
189 __isl_give isl_val *isl_stream_read_val(__isl_keep isl_stream *s)
191 struct isl_token *tok = NULL;
192 struct isl_token *tok2 = NULL;
193 isl_val *val;
195 tok = next_token(s);
196 if (!tok) {
197 isl_stream_error(s, NULL, "unexpected EOF");
198 goto error;
200 if (tok->type == ISL_TOKEN_INFTY) {
201 isl_token_free(tok);
202 return isl_val_infty(s->ctx);
204 if (tok->type == '-' &&
205 isl_stream_eat_if_available(s, ISL_TOKEN_INFTY)) {
206 isl_token_free(tok);
207 return isl_val_neginfty(s->ctx);
209 if (tok->type == ISL_TOKEN_NAN) {
210 isl_token_free(tok);
211 return isl_val_nan(s->ctx);
213 if (tok->type != ISL_TOKEN_VALUE) {
214 isl_stream_error(s, tok, "expecting value");
215 goto error;
218 if (isl_stream_eat_if_available(s, '/')) {
219 tok2 = next_token(s);
220 if (!tok2) {
221 isl_stream_error(s, NULL, "unexpected EOF");
222 goto error;
224 if (tok2->type != ISL_TOKEN_VALUE) {
225 isl_stream_error(s, tok2, "expecting value");
226 goto error;
228 val = isl_val_rat_from_isl_int(s->ctx, tok->u.v, tok2->u.v);
229 val = isl_val_normalize(val);
230 } else {
231 val = isl_val_int_from_isl_int(s->ctx, tok->u.v);
234 isl_token_free(tok);
235 isl_token_free(tok2);
236 return val;
237 error:
238 isl_token_free(tok);
239 isl_token_free(tok2);
240 return NULL;
243 /* Read an isl_val from "str".
245 __isl_give isl_val *isl_val_read_from_str(isl_ctx *ctx, const char *str)
247 isl_val *val;
248 isl_stream *s = isl_stream_new_str(ctx, str);
249 if (!s)
250 return NULL;
251 val = isl_stream_read_val(s);
252 isl_stream_free(s);
253 return val;
256 /* Perform an integer division on *f and
257 * an integer value read from the stream.
259 static isl_stat int_div_by_cst(__isl_keep isl_stream *s, isl_int *f)
261 struct isl_token *tok;
263 tok = next_token(s);
264 if (!tok || tok->type != ISL_TOKEN_VALUE) {
265 isl_stream_error(s, tok, "expecting constant value");
266 goto error;
269 isl_int_fdiv_q(*f, *f, tok->u.v);
271 isl_token_free(tok);
273 return isl_stat_ok;
274 error:
275 isl_token_free(tok);
276 return isl_stat_error;
279 static isl_stat accept_cst_factor(__isl_keep isl_stream *s, isl_int *f)
281 struct isl_token *tok;
283 tok = next_token(s);
284 if (!tok || tok->type != ISL_TOKEN_VALUE) {
285 isl_stream_error(s, tok, "expecting constant value");
286 goto error;
289 isl_int_mul(*f, *f, tok->u.v);
291 isl_token_free(tok);
293 if (isl_stream_eat_if_available(s, '*'))
294 return accept_cst_factor(s, f);
296 return isl_stat_ok;
297 error:
298 isl_token_free(tok);
299 return isl_stat_error;
302 /* Given an affine expression aff, return an affine expression
303 * for aff % d, with d the next token on the stream, which is
304 * assumed to be a constant.
306 * We introduce an integer division q = [aff/d] and the result
307 * is set to aff - d q.
309 static __isl_give isl_pw_aff *affine_mod(__isl_keep isl_stream *s,
310 struct vars *v, __isl_take isl_pw_aff *aff)
312 struct isl_token *tok;
313 isl_pw_aff *q;
315 tok = next_token(s);
316 if (!tok || tok->type != ISL_TOKEN_VALUE) {
317 isl_stream_error(s, tok, "expecting constant value");
318 goto error;
321 q = isl_pw_aff_copy(aff);
322 q = isl_pw_aff_scale_down(q, tok->u.v);
323 q = isl_pw_aff_floor(q);
324 q = isl_pw_aff_scale(q, tok->u.v);
326 aff = isl_pw_aff_sub(aff, q);
328 isl_token_free(tok);
329 return aff;
330 error:
331 isl_pw_aff_free(aff);
332 isl_token_free(tok);
333 return NULL;
336 static __isl_give isl_pw_aff *accept_affine(__isl_keep isl_stream *s,
337 __isl_take isl_space *space, struct vars *v);
338 static __isl_give isl_pw_aff_list *accept_affine_list(__isl_keep isl_stream *s,
339 __isl_take isl_space *space, struct vars *v);
341 static __isl_give isl_pw_aff *accept_minmax(__isl_keep isl_stream *s,
342 __isl_take isl_space *space, struct vars *v)
344 struct isl_token *tok;
345 isl_pw_aff_list *list = NULL;
346 int min;
348 tok = isl_stream_next_token(s);
349 if (!tok)
350 goto error;
351 min = tok->type == ISL_TOKEN_MIN;
352 isl_token_free(tok);
354 if (isl_stream_eat(s, '('))
355 goto error;
357 list = accept_affine_list(s, isl_space_copy(space), v);
358 if (!list)
359 goto error;
361 if (isl_stream_eat(s, ')'))
362 goto error;
364 isl_space_free(space);
365 return min ? isl_pw_aff_list_min(list) : isl_pw_aff_list_max(list);
366 error:
367 isl_space_free(space);
368 isl_pw_aff_list_free(list);
369 return NULL;
372 /* Is "tok" the start of an integer division?
374 static int is_start_of_div(struct isl_token *tok)
376 if (!tok)
377 return 0;
378 if (tok->type == '[')
379 return 1;
380 if (tok->type == ISL_TOKEN_FLOOR)
381 return 1;
382 if (tok->type == ISL_TOKEN_CEIL)
383 return 1;
384 if (tok->type == ISL_TOKEN_FLOORD)
385 return 1;
386 if (tok->type == ISL_TOKEN_CEILD)
387 return 1;
388 return 0;
391 /* Read an integer division from "s" and return it as an isl_pw_aff.
393 * The integer division can be of the form
395 * [<affine expression>]
396 * floor(<affine expression>)
397 * ceil(<affine expression>)
398 * floord(<affine expression>,<denominator>)
399 * ceild(<affine expression>,<denominator>)
401 static __isl_give isl_pw_aff *accept_div(__isl_keep isl_stream *s,
402 __isl_take isl_space *space, struct vars *v)
404 struct isl_token *tok;
405 int f = 0;
406 int c = 0;
407 int extra = 0;
408 isl_pw_aff *pwaff = NULL;
410 if (isl_stream_eat_if_available(s, ISL_TOKEN_FLOORD))
411 extra = f = 1;
412 else if (isl_stream_eat_if_available(s, ISL_TOKEN_CEILD))
413 extra = c = 1;
414 else if (isl_stream_eat_if_available(s, ISL_TOKEN_FLOOR))
415 f = 1;
416 else if (isl_stream_eat_if_available(s, ISL_TOKEN_CEIL))
417 c = 1;
418 if (f || c) {
419 if (isl_stream_eat(s, '('))
420 goto error;
421 } else {
422 if (isl_stream_eat(s, '['))
423 goto error;
426 pwaff = accept_affine(s, isl_space_copy(space), v);
428 if (extra) {
429 if (isl_stream_eat(s, ','))
430 goto error;
432 tok = next_token(s);
433 if (!tok)
434 goto error;
435 if (tok->type != ISL_TOKEN_VALUE) {
436 isl_stream_error(s, tok, "expected denominator");
437 goto error;
439 pwaff = isl_pw_aff_scale_down(pwaff, tok->u.v);
440 isl_token_free(tok);
443 if (c)
444 pwaff = isl_pw_aff_ceil(pwaff);
445 else
446 pwaff = isl_pw_aff_floor(pwaff);
448 if (f || c) {
449 if (isl_stream_eat(s, ')'))
450 goto error;
451 } else {
452 if (isl_stream_eat(s, ']'))
453 goto error;
456 isl_space_free(space);
457 return pwaff;
458 error:
459 isl_space_free(space);
460 isl_pw_aff_free(pwaff);
461 return NULL;
464 /* Divide "pa" by an integer constant read from the stream.
466 static __isl_give isl_pw_aff *pw_aff_div_by_cst(__isl_keep isl_stream *s,
467 __isl_take isl_pw_aff *pa)
469 isl_int f;
470 isl_int_init(f);
471 isl_int_set_si(f, 1);
472 if (accept_cst_factor(s, &f) < 0)
473 pa = isl_pw_aff_free(pa);
474 pa = isl_pw_aff_scale_down(pa, f);
475 isl_int_clear(f);
477 return pa;
480 static __isl_give isl_pw_aff *accept_affine_factor(__isl_keep isl_stream *s,
481 __isl_take isl_space *space, struct vars *v)
483 struct isl_token *tok = NULL;
484 isl_pw_aff *res = NULL;
486 tok = next_token(s);
487 if (!tok) {
488 isl_stream_error(s, NULL, "unexpected EOF");
489 goto error;
492 if (tok->type == ISL_TOKEN_AFF) {
493 res = isl_pw_aff_copy(tok->u.pwaff);
494 isl_token_free(tok);
495 } else if (tok->type == ISL_TOKEN_IDENT) {
496 int n = v->n;
497 int pos = vars_pos(v, tok->u.s, -1);
498 isl_aff *aff;
500 if (pos < 0)
501 goto error;
502 if (pos >= n) {
503 vars_drop(v, v->n - n);
504 isl_stream_error(s, tok, "unknown identifier");
505 goto error;
508 aff = isl_aff_zero_on_domain(isl_local_space_from_space(isl_space_copy(space)));
509 if (!aff)
510 goto error;
511 aff->v = isl_vec_set_element_si(aff->v, 2 + pos, 1);
512 if (!aff->v)
513 aff = isl_aff_free(aff);
514 res = isl_pw_aff_from_aff(aff);
515 isl_token_free(tok);
516 } else if (tok->type == ISL_TOKEN_VALUE) {
517 if (isl_stream_eat_if_available(s, '*')) {
518 res = accept_affine_factor(s, isl_space_copy(space), v);
519 res = isl_pw_aff_scale(res, tok->u.v);
520 } else {
521 isl_local_space *ls;
522 isl_aff *aff;
523 ls = isl_local_space_from_space(isl_space_copy(space));
524 aff = isl_aff_zero_on_domain(ls);
525 aff = isl_aff_add_constant(aff, tok->u.v);
526 res = isl_pw_aff_from_aff(aff);
528 isl_token_free(tok);
529 } else if (tok->type == '(') {
530 isl_token_free(tok);
531 tok = NULL;
532 res = accept_affine(s, isl_space_copy(space), v);
533 if (!res)
534 goto error;
535 if (isl_stream_eat(s, ')'))
536 goto error;
537 } else if (is_start_of_div(tok)) {
538 isl_stream_push_token(s, tok);
539 tok = NULL;
540 res = accept_div(s, isl_space_copy(space), v);
541 } else if (tok->type == ISL_TOKEN_MIN || tok->type == ISL_TOKEN_MAX) {
542 isl_stream_push_token(s, tok);
543 tok = NULL;
544 res = accept_minmax(s, isl_space_copy(space), v);
545 } else {
546 isl_stream_error(s, tok, "expecting factor");
547 goto error;
549 if (isl_stream_eat_if_available(s, '%') ||
550 isl_stream_eat_if_available(s, ISL_TOKEN_MOD)) {
551 isl_space_free(space);
552 return affine_mod(s, v, res);
554 if (isl_stream_eat_if_available(s, '*')) {
555 isl_int f;
556 isl_int_init(f);
557 isl_int_set_si(f, 1);
558 if (accept_cst_factor(s, &f) < 0) {
559 isl_int_clear(f);
560 goto error2;
562 res = isl_pw_aff_scale(res, f);
563 isl_int_clear(f);
565 if (isl_stream_eat_if_available(s, '/'))
566 res = pw_aff_div_by_cst(s, res);
567 if (isl_stream_eat_if_available(s, ISL_TOKEN_INT_DIV))
568 res = isl_pw_aff_floor(pw_aff_div_by_cst(s, res));
570 isl_space_free(space);
571 return res;
572 error:
573 isl_token_free(tok);
574 error2:
575 isl_pw_aff_free(res);
576 isl_space_free(space);
577 return NULL;
580 static __isl_give isl_pw_aff *add_cst(__isl_take isl_pw_aff *pwaff, isl_int v)
582 isl_aff *aff;
583 isl_space *space;
585 space = isl_pw_aff_get_domain_space(pwaff);
586 aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
587 aff = isl_aff_add_constant(aff, v);
589 return isl_pw_aff_add(pwaff, isl_pw_aff_from_aff(aff));
592 /* Return a piecewise affine expression defined on the specified domain
593 * that represents NaN.
595 static __isl_give isl_pw_aff *nan_on_domain(__isl_keep isl_space *space)
597 return isl_pw_aff_nan_on_domain_space(isl_space_copy(space));
600 static __isl_give isl_pw_aff *accept_affine(__isl_keep isl_stream *s,
601 __isl_take isl_space *space, struct vars *v)
603 struct isl_token *tok = NULL;
604 isl_local_space *ls;
605 isl_pw_aff *res;
606 int sign = 1;
608 ls = isl_local_space_from_space(isl_space_copy(space));
609 res = isl_pw_aff_from_aff(isl_aff_zero_on_domain(ls));
610 if (!res)
611 goto error;
613 for (;;) {
614 tok = next_token(s);
615 if (!tok) {
616 isl_stream_error(s, NULL, "unexpected EOF");
617 goto error;
619 if (tok->type == '-') {
620 sign = -sign;
621 isl_token_free(tok);
622 continue;
624 if (tok->type == '(' || is_start_of_div(tok) ||
625 tok->type == ISL_TOKEN_MIN || tok->type == ISL_TOKEN_MAX ||
626 tok->type == ISL_TOKEN_IDENT ||
627 tok->type == ISL_TOKEN_AFF) {
628 isl_pw_aff *term;
629 isl_stream_push_token(s, tok);
630 tok = NULL;
631 term = accept_affine_factor(s,
632 isl_space_copy(space), v);
633 if (sign < 0)
634 res = isl_pw_aff_sub(res, term);
635 else
636 res = isl_pw_aff_add(res, term);
637 if (!res)
638 goto error;
639 sign = 1;
640 } else if (tok->type == ISL_TOKEN_VALUE) {
641 if (sign < 0)
642 isl_int_neg(tok->u.v, tok->u.v);
643 if (isl_stream_eat_if_available(s, '*') ||
644 isl_stream_next_token_is(s, ISL_TOKEN_IDENT)) {
645 isl_pw_aff *term;
646 term = accept_affine_factor(s,
647 isl_space_copy(space), v);
648 term = isl_pw_aff_scale(term, tok->u.v);
649 res = isl_pw_aff_add(res, term);
650 if (!res)
651 goto error;
652 } else {
653 if (isl_stream_eat_if_available(s,
654 ISL_TOKEN_INT_DIV) &&
655 int_div_by_cst(s, &tok->u.v) < 0)
656 goto error;
657 res = add_cst(res, tok->u.v);
659 sign = 1;
660 } else if (tok->type == ISL_TOKEN_NAN) {
661 res = isl_pw_aff_add(res, nan_on_domain(space));
662 } else {
663 isl_stream_error(s, tok, "unexpected isl_token");
664 isl_stream_push_token(s, tok);
665 isl_pw_aff_free(res);
666 isl_space_free(space);
667 return NULL;
669 isl_token_free(tok);
671 tok = next_token(s);
672 if (tok && tok->type == '-') {
673 sign = -sign;
674 isl_token_free(tok);
675 } else if (tok && tok->type == '+') {
676 /* nothing */
677 isl_token_free(tok);
678 } else if (tok && tok->type == ISL_TOKEN_VALUE &&
679 isl_int_is_neg(tok->u.v)) {
680 isl_stream_push_token(s, tok);
681 } else {
682 if (tok)
683 isl_stream_push_token(s, tok);
684 break;
688 isl_space_free(space);
689 return res;
690 error:
691 isl_space_free(space);
692 isl_token_free(tok);
693 isl_pw_aff_free(res);
694 return NULL;
697 /* Is "type" the type of a comparison operator between lists
698 * of affine expressions?
700 static int is_list_comparator_type(int type)
702 switch (type) {
703 case ISL_TOKEN_LEX_LT:
704 case ISL_TOKEN_LEX_GT:
705 case ISL_TOKEN_LEX_LE:
706 case ISL_TOKEN_LEX_GE:
707 return 1;
708 default:
709 return 0;
713 static int is_comparator(struct isl_token *tok)
715 if (!tok)
716 return 0;
717 if (is_list_comparator_type(tok->type))
718 return 1;
720 switch (tok->type) {
721 case ISL_TOKEN_LT:
722 case ISL_TOKEN_GT:
723 case ISL_TOKEN_LE:
724 case ISL_TOKEN_GE:
725 case ISL_TOKEN_NE:
726 case '=':
727 return 1;
728 default:
729 return 0;
733 static __isl_give isl_map *read_formula(__isl_keep isl_stream *s,
734 struct vars *v, __isl_take isl_map *map, int rational);
735 static __isl_give isl_pw_aff *accept_extended_affine(__isl_keep isl_stream *s,
736 __isl_take isl_space *space, struct vars *v, int rational);
738 /* Accept a ternary operator, given the first argument.
740 static __isl_give isl_pw_aff *accept_ternary(__isl_keep isl_stream *s,
741 __isl_take isl_map *cond, struct vars *v, int rational)
743 isl_space *space;
744 isl_pw_aff *pwaff1 = NULL, *pwaff2 = NULL, *pa_cond;
746 if (!cond)
747 return NULL;
749 if (isl_stream_eat(s, '?'))
750 goto error;
752 space = isl_space_wrap(isl_map_get_space(cond));
753 pwaff1 = accept_extended_affine(s, space, v, rational);
754 if (!pwaff1)
755 goto error;
757 if (isl_stream_eat(s, ':'))
758 goto error;
760 space = isl_pw_aff_get_domain_space(pwaff1);
761 pwaff2 = accept_extended_affine(s, space, v, rational);
762 if (!pwaff2)
763 goto error;
765 pa_cond = isl_set_indicator_function(isl_map_wrap(cond));
766 return isl_pw_aff_cond(pa_cond, pwaff1, pwaff2);
767 error:
768 isl_map_free(cond);
769 isl_pw_aff_free(pwaff1);
770 isl_pw_aff_free(pwaff2);
771 return NULL;
774 /* Set *line and *col to those of the next token, if any.
776 static void set_current_line_col(__isl_keep isl_stream *s, int *line, int *col)
778 struct isl_token *tok;
780 tok = isl_stream_next_token(s);
781 if (!tok)
782 return;
784 *line = tok->line;
785 *col = tok->col;
786 isl_stream_push_token(s, tok);
789 /* Push a token encapsulating "pa" onto "s", with the given
790 * line and column.
792 static isl_stat push_aff(__isl_keep isl_stream *s, int line, int col,
793 __isl_take isl_pw_aff *pa)
795 struct isl_token *tok;
797 tok = isl_token_new(s->ctx, line, col, 0);
798 if (!tok)
799 goto error;
800 tok->type = ISL_TOKEN_AFF;
801 tok->u.pwaff = pa;
802 isl_stream_push_token(s, tok);
804 return isl_stat_ok;
805 error:
806 isl_pw_aff_free(pa);
807 return isl_stat_error;
810 /* Is the next token a comparison operator?
812 static int next_is_comparator(__isl_keep isl_stream *s)
814 int is_comp;
815 struct isl_token *tok;
817 tok = isl_stream_next_token(s);
818 if (!tok)
819 return 0;
821 is_comp = is_comparator(tok);
822 isl_stream_push_token(s, tok);
824 return is_comp;
827 /* Accept an affine expression that may involve ternary operators.
828 * We first read an affine expression.
829 * If it is not followed by a comparison operator, we simply return it.
830 * Otherwise, we assume the affine expression is part of the first
831 * argument of a ternary operator and try to parse that.
833 static __isl_give isl_pw_aff *accept_extended_affine(__isl_keep isl_stream *s,
834 __isl_take isl_space *space, struct vars *v, int rational)
836 isl_map *cond;
837 isl_pw_aff *pwaff;
838 int line = -1, col = -1;
840 set_current_line_col(s, &line, &col);
842 pwaff = accept_affine(s, space, v);
843 if (rational)
844 pwaff = isl_pw_aff_set_rational(pwaff);
845 if (!pwaff)
846 return NULL;
847 if (!next_is_comparator(s))
848 return pwaff;
850 space = isl_pw_aff_get_domain_space(pwaff);
851 cond = isl_map_universe(isl_space_unwrap(space));
853 if (push_aff(s, line, col, pwaff) < 0)
854 cond = isl_map_free(cond);
855 if (!cond)
856 return NULL;
858 cond = read_formula(s, v, cond, rational);
860 return accept_ternary(s, cond, v, rational);
863 static __isl_give isl_map *read_var_def(__isl_keep isl_stream *s,
864 __isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
865 int rational)
867 isl_pw_aff *def;
868 isl_size pos;
869 isl_map *def_map;
871 if (type == isl_dim_param)
872 pos = isl_map_dim(map, isl_dim_param);
873 else {
874 pos = isl_map_dim(map, isl_dim_in);
875 if (type == isl_dim_out) {
876 isl_size n_out = isl_map_dim(map, isl_dim_out);
877 if (pos < 0 || n_out < 0)
878 return isl_map_free(map);
879 pos += n_out;
881 type = isl_dim_in;
883 if (pos < 0)
884 return isl_map_free(map);
885 --pos;
887 def = accept_extended_affine(s, isl_space_wrap(isl_map_get_space(map)),
888 v, rational);
889 def_map = isl_map_from_pw_aff(def);
890 def_map = isl_map_equate(def_map, type, pos, isl_dim_out, 0);
891 def_map = isl_set_unwrap(isl_map_domain(def_map));
893 map = isl_map_intersect(map, def_map);
895 return map;
898 static __isl_give isl_pw_aff_list *accept_affine_list(__isl_keep isl_stream *s,
899 __isl_take isl_space *space, struct vars *v)
901 isl_pw_aff *pwaff;
902 isl_pw_aff_list *list;
903 struct isl_token *tok = NULL;
905 pwaff = accept_affine(s, isl_space_copy(space), v);
906 list = isl_pw_aff_list_from_pw_aff(pwaff);
907 if (!list)
908 goto error;
910 for (;;) {
911 tok = isl_stream_next_token(s);
912 if (!tok) {
913 isl_stream_error(s, NULL, "unexpected EOF");
914 goto error;
916 if (tok->type != ',') {
917 isl_stream_push_token(s, tok);
918 break;
920 isl_token_free(tok);
922 pwaff = accept_affine(s, isl_space_copy(space), v);
923 list = isl_pw_aff_list_concat(list,
924 isl_pw_aff_list_from_pw_aff(pwaff));
925 if (!list)
926 goto error;
929 isl_space_free(space);
930 return list;
931 error:
932 isl_space_free(space);
933 isl_pw_aff_list_free(list);
934 return NULL;
937 static __isl_give isl_map *read_defined_var_list(__isl_keep isl_stream *s,
938 struct vars *v, __isl_take isl_map *map, int rational)
940 struct isl_token *tok;
942 while ((tok = isl_stream_next_token(s)) != NULL) {
943 int p;
944 int n = v->n;
946 if (tok->type != ISL_TOKEN_IDENT)
947 break;
949 p = vars_pos(v, tok->u.s, -1);
950 if (p < 0)
951 goto error;
952 if (p < n) {
953 isl_stream_error(s, tok, "expecting unique identifier");
954 goto error;
957 map = isl_map_add_dims(map, isl_dim_out, 1);
959 isl_token_free(tok);
960 tok = isl_stream_next_token(s);
961 if (tok && tok->type == '=') {
962 isl_token_free(tok);
963 map = read_var_def(s, map, isl_dim_out, v, rational);
964 tok = isl_stream_next_token(s);
967 if (!tok || tok->type != ',')
968 break;
970 isl_token_free(tok);
972 if (tok)
973 isl_stream_push_token(s, tok);
975 return map;
976 error:
977 isl_token_free(tok);
978 isl_map_free(map);
979 return NULL;
982 static int next_is_tuple(__isl_keep isl_stream *s)
984 struct isl_token *tok;
985 int is_tuple;
987 tok = isl_stream_next_token(s);
988 if (!tok)
989 return 0;
990 if (tok->type == '[') {
991 isl_stream_push_token(s, tok);
992 return 1;
994 if (tok->type != ISL_TOKEN_IDENT && !tok->is_keyword) {
995 isl_stream_push_token(s, tok);
996 return 0;
999 is_tuple = isl_stream_next_token_is(s, '[');
1001 isl_stream_push_token(s, tok);
1003 return is_tuple;
1006 /* Does the next token mark the end of a tuple element?
1008 static int next_is_end_tuple_element(__isl_keep isl_stream *s)
1010 return isl_stream_next_token_is(s, ',') ||
1011 isl_stream_next_token_is(s, ']');
1014 /* Is the next token one that necessarily forms the start of a condition?
1016 static int next_is_condition_start(__isl_keep isl_stream *s)
1018 return isl_stream_next_token_is(s, ISL_TOKEN_EXISTS) ||
1019 isl_stream_next_token_is(s, ISL_TOKEN_NOT) ||
1020 isl_stream_next_token_is(s, ISL_TOKEN_TRUE) ||
1021 isl_stream_next_token_is(s, ISL_TOKEN_FALSE) ||
1022 isl_stream_next_token_is(s, ISL_TOKEN_MAP);
1025 /* Is "pa" an expression in term of earlier dimensions?
1026 * The alternative is that the dimension is defined to be equal to itself,
1027 * meaning that it has a universe domain and an expression that depends
1028 * on itself. "i" is the position of the expression in a sequence
1029 * of "n" expressions. The final dimensions of "pa" correspond to
1030 * these "n" expressions.
1032 static isl_bool pw_aff_is_expr(__isl_keep isl_pw_aff *pa, int i, int n)
1034 isl_aff *aff;
1036 if (!pa)
1037 return isl_bool_error;
1038 if (pa->n != 1)
1039 return isl_bool_true;
1040 if (!isl_set_plain_is_universe(pa->p[0].set))
1041 return isl_bool_true;
1043 aff = pa->p[0].aff;
1044 if (isl_int_is_zero(aff->v->el[aff->v->size - n + i]))
1045 return isl_bool_true;
1046 return isl_bool_false;
1049 /* Does the tuple contain any dimensions that are defined
1050 * in terms of earlier dimensions?
1052 static isl_bool tuple_has_expr(__isl_keep isl_multi_pw_aff *tuple)
1054 int i;
1055 isl_size n;
1056 isl_bool has_expr = isl_bool_false;
1057 isl_pw_aff *pa;
1059 n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
1060 if (n < 0)
1061 return isl_bool_error;
1062 for (i = 0; i < n; ++i) {
1063 pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
1064 has_expr = pw_aff_is_expr(pa, i, n);
1065 isl_pw_aff_free(pa);
1066 if (has_expr < 0 || has_expr)
1067 break;
1070 return has_expr;
1073 /* Set the name of dimension "pos" in "space" to "name".
1074 * During printing, we add primes if the same name appears more than once
1075 * to distinguish the occurrences. Here, we remove those primes from "name"
1076 * before setting the name of the dimension.
1078 static __isl_give isl_space *space_set_dim_name(__isl_take isl_space *space,
1079 int pos, char *name)
1081 char *prime;
1083 if (!name)
1084 return space;
1086 prime = strchr(name, '\'');
1087 if (prime)
1088 *prime = '\0';
1089 space = isl_space_set_dim_name(space, isl_dim_out, pos, name);
1090 if (prime)
1091 *prime = '\'';
1093 return space;
1096 /* Set the name of the last (output) dimension of "space" to "name",
1097 * ignoring any primes in "name".
1099 static __isl_give isl_space *space_set_last_dim_name(
1100 __isl_take isl_space *space, char *name)
1102 isl_size pos;
1104 pos = isl_space_dim(space, isl_dim_out);
1105 if (pos < 0)
1106 return isl_space_free(space);
1107 return space_set_dim_name(space, pos - 1, name);
1110 /* Construct an isl_pw_aff defined on a "space" (with v->n variables)
1111 * that is equal to the last of those variables.
1113 static __isl_give isl_pw_aff *identity_tuple_el_on_space(
1114 __isl_take isl_space *space, struct vars *v)
1116 isl_aff *aff;
1118 aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
1119 aff = isl_aff_add_coefficient_si(aff, isl_dim_in, v->n - 1, 1);
1120 return isl_pw_aff_from_aff(aff);
1123 /* Construct an isl_pw_aff defined on the domain space of "pa"
1124 * that is equal to the last variable in "v".
1126 * That is, if D is the domain space of "pa", then construct
1128 * D[..., i] -> i.
1130 static __isl_give isl_pw_aff *init_range(__isl_keep isl_pw_aff *pa,
1131 struct vars *v)
1133 isl_space *space;
1135 space = isl_pw_aff_get_domain_space(pa);
1136 return identity_tuple_el_on_space(space, v);
1139 /* Impose the lower bound "lower" on the variable represented by "range_pa".
1141 * In particular, "range_pa" is of the form
1143 * D[..., i] -> i : C
1145 * with D also the domains space of "lower' and "C" some constraints.
1147 * Return the expression
1149 * D[..., i] -> i : C and i >= lower
1151 static __isl_give isl_pw_aff *set_lower(__isl_take isl_pw_aff *range_pa,
1152 __isl_take isl_pw_aff *lower)
1154 isl_set *range;
1156 range = isl_pw_aff_ge_set(isl_pw_aff_copy(range_pa), lower);
1157 return isl_pw_aff_intersect_domain(range_pa, range);
1160 /* Impose the upper bound "upper" on the variable represented by "range_pa".
1162 * In particular, "range_pa" is of the form
1164 * D[..., i] -> i : C
1166 * with D also the domains space of "upper' and "C" some constraints.
1168 * Return the expression
1170 * D[..., i] -> i : C and i <= upper
1172 static __isl_give isl_pw_aff *set_upper(__isl_take isl_pw_aff *range_pa,
1173 __isl_take isl_pw_aff *upper)
1175 isl_set *range;
1177 range = isl_pw_aff_le_set(isl_pw_aff_copy(range_pa), upper);
1178 return isl_pw_aff_intersect_domain(range_pa, range);
1181 /* Construct a piecewise affine expression corresponding
1182 * to the last variable in "v" that is greater than or equal to "pa".
1184 * In particular, if D is the domain space of "pa",
1185 * then construct the expression
1187 * D[..., i] -> i,
1189 * impose lower bound "pa" and return
1191 * D[..., i] -> i : i >= pa
1193 static __isl_give isl_pw_aff *construct_lower(__isl_take isl_pw_aff *pa,
1194 struct vars *v)
1196 return set_lower(init_range(pa, v), pa);
1199 /* Construct a piecewise affine expression corresponding
1200 * to the last variable in "v" that is smaller than or equal to "pa".
1202 * In particular, if D is the domain space of "pa",
1203 * then construct the expression
1205 * D[..., i] -> i,
1207 * impose lower bound "pa" and return
1209 * D[..., i] -> i : i <= pa
1211 static __isl_give isl_pw_aff *construct_upper(__isl_take isl_pw_aff *pa,
1212 struct vars *v)
1214 return set_upper(init_range(pa, v), pa);
1217 /* Construct a piecewise affine expression corresponding
1218 * to the last variable in "v" that ranges between "pa" and "pa2".
1220 * In particular, if D is the domain space of "pa" (and "pa2"),
1221 * then construct the expression
1223 * D[..., i] -> i,
1225 * impose lower bound "pa" and upper bound "pa2" and return
1227 * D[..., i] -> i : pa <= i <= pa2
1229 static __isl_give isl_pw_aff *construct_range(__isl_take isl_pw_aff *pa,
1230 __isl_take isl_pw_aff *pa2, struct vars *v)
1232 return set_upper(set_lower(init_range(pa, v), pa), pa2);
1235 static int resolve_paren_expr(__isl_keep isl_stream *s,
1236 struct vars *v, __isl_take isl_map *map, int rational);
1238 /* Given that the (piecewise) affine expression "pa"
1239 * has just been parsed, followed by a colon,
1240 * continue parsing as part of a piecewise affine expression.
1242 * In particular, check if the colon is followed by a condition.
1243 * If so, parse the conditions(a) on "pa" and include them in the domain.
1244 * Otherwise, if the colon is followed by another (piecewise) affine expression
1245 * then consider the two expressions as endpoints of a range of values and
1246 * return a piecewise affine expression that takes values in that range.
1247 * Note that an affine expression followed by a comparison operator
1248 * is considered to be part of a condition.
1249 * If the colon is not followed by anything (inside the tuple element),
1250 * then consider "pa" as a lower bound on a range of values without upper bound
1251 * and return a piecewise affine expression that takes values in that range.
1253 static __isl_give isl_pw_aff *update_piecewise_affine_colon(
1254 __isl_take isl_pw_aff *pa, __isl_keep isl_stream *s,
1255 struct vars *v, int rational)
1257 isl_space *dom_space;
1258 isl_map *map;
1260 dom_space = isl_pw_aff_get_domain_space(pa);
1261 map = isl_map_universe(isl_space_from_domain(dom_space));
1263 if (isl_stream_next_token_is(s, '('))
1264 if (resolve_paren_expr(s, v, isl_map_copy(map), rational))
1265 goto error;
1266 if (next_is_end_tuple_element(s)) {
1267 isl_map_free(map);
1268 return construct_lower(pa, v);
1270 if (!next_is_condition_start(s)) {
1271 int line = -1, col = -1;
1272 isl_space *space;
1273 isl_pw_aff *pa2;
1275 set_current_line_col(s, &line, &col);
1276 space = isl_space_wrap(isl_map_get_space(map));
1277 pa2 = accept_affine(s, space, v);
1278 if (rational)
1279 pa2 = isl_pw_aff_set_rational(pa2);
1280 if (!next_is_comparator(s)) {
1281 isl_map_free(map);
1282 pa2 = isl_pw_aff_domain_factor_domain(pa2);
1283 return construct_range(pa, pa2, v);
1285 if (push_aff(s, line, col, pa2) < 0)
1286 goto error;
1289 map = read_formula(s, v, map, rational);
1290 pa = isl_pw_aff_intersect_domain(pa, isl_map_domain(map));
1292 return pa;
1293 error:
1294 isl_map_free(map);
1295 isl_pw_aff_free(pa);
1296 return NULL;
1299 /* Accept a piecewise affine expression.
1301 * At the outer level, the piecewise affine expression may be of the form
1303 * aff1 : condition1; aff2 : conditions2; ...
1305 * or one of
1307 * aff :
1308 * aff1 : aff2
1309 * : aff
1312 * or simply
1314 * aff
1316 * each of the affine expressions may in turn include ternary operators.
1318 * If the first token is a colon, then the expression must be
1319 * ":" or ": aff2", depending on whether anything follows the colon
1320 * inside the tuple element.
1321 * The first is considered to represent an arbitrary value.
1322 * The second is considered to represent a range of values
1323 * with the given upper bound and no lower bound.
1325 * There may be parentheses around some subexpression of "aff1"
1326 * around "aff1" itself, around "aff1 : condition1" and/or
1327 * around the entire piecewise affine expression.
1328 * We therefore remove the opening parenthesis (if any) from the stream
1329 * in case the closing parenthesis follows the colon, but if the closing
1330 * parenthesis is the first thing in the stream after the parsed affine
1331 * expression, we push the parsed expression onto the stream and parse
1332 * again in case the parentheses enclose some subexpression of "aff1".
1334 static __isl_give isl_pw_aff *accept_piecewise_affine(__isl_keep isl_stream *s,
1335 __isl_take isl_space *space, struct vars *v, int rational)
1337 isl_pw_aff *res;
1338 isl_space *res_space;
1340 if (isl_stream_eat_if_available(s, ':')) {
1341 if (next_is_end_tuple_element(s))
1342 return identity_tuple_el_on_space(space, v);
1343 else
1344 return construct_upper(accept_affine(s, space, v), v);
1347 res_space = isl_space_from_domain(isl_space_copy(space));
1348 res_space = isl_space_add_dims(res_space, isl_dim_out, 1);
1349 res = isl_pw_aff_empty(res_space);
1350 do {
1351 isl_pw_aff *pa;
1352 int seen_paren;
1353 int line = -1, col = -1;
1355 set_current_line_col(s, &line, &col);
1356 seen_paren = isl_stream_eat_if_available(s, '(');
1357 if (seen_paren)
1358 pa = accept_piecewise_affine(s, isl_space_copy(space),
1359 v, rational);
1360 else
1361 pa = accept_extended_affine(s, isl_space_copy(space),
1362 v, rational);
1363 if (seen_paren && isl_stream_eat_if_available(s, ')')) {
1364 seen_paren = 0;
1365 if (push_aff(s, line, col, pa) < 0)
1366 goto error;
1367 pa = accept_extended_affine(s, isl_space_copy(space),
1368 v, rational);
1370 if (isl_stream_eat_if_available(s, ':'))
1371 pa = update_piecewise_affine_colon(pa, s, v, rational);
1373 res = isl_pw_aff_union_add(res, pa);
1375 if (seen_paren && isl_stream_eat(s, ')'))
1376 goto error;
1377 } while (isl_stream_eat_if_available(s, ';'));
1379 isl_space_free(space);
1381 return res;
1382 error:
1383 isl_space_free(space);
1384 return isl_pw_aff_free(res);
1387 /* Read an affine expression from "s" for use in read_tuple.
1389 * accept_extended_affine requires a wrapped space as input.
1390 * read_tuple on the other hand expects each isl_pw_aff
1391 * to have an anonymous space. We therefore adjust the space
1392 * of the isl_pw_aff before returning it.
1394 static __isl_give isl_pw_aff *read_tuple_var_def(__isl_keep isl_stream *s,
1395 struct vars *v, int rational)
1397 isl_space *space;
1398 isl_pw_aff *def;
1400 space = isl_space_wrap(isl_space_alloc(s->ctx, 0, v->n, 0));
1402 def = accept_piecewise_affine(s, space, v, rational);
1403 def = isl_pw_aff_domain_factor_domain(def);
1405 return def;
1408 /* Read a list of tuple elements by calling "read_el" on each of them and
1409 * return a space with the same number of set dimensions derived from
1410 * the parameter space "space" and possibly updated by "read_el".
1411 * The elements in the list are separated by either "," or "][".
1412 * If "comma" is set then only "," is allowed.
1414 static __isl_give isl_space *read_tuple_list(__isl_keep isl_stream *s,
1415 struct vars *v, __isl_take isl_space *space, int rational, int comma,
1416 __isl_give isl_space *(*read_el)(__isl_keep isl_stream *s,
1417 struct vars *v, __isl_take isl_space *space, int rational,
1418 void *user),
1419 void *user)
1421 if (!space)
1422 return NULL;
1424 space = isl_space_set_from_params(space);
1426 if (isl_stream_next_token_is(s, ']'))
1427 return space;
1429 for (;;) {
1430 struct isl_token *tok;
1432 space = isl_space_add_dims(space, isl_dim_set, 1);
1434 space = read_el(s, v, space, rational, user);
1435 if (!space)
1436 return NULL;
1438 tok = isl_stream_next_token(s);
1439 if (!comma && tok && tok->type == ']' &&
1440 isl_stream_next_token_is(s, '[')) {
1441 isl_token_free(tok);
1442 tok = isl_stream_next_token(s);
1443 } else if (!tok || tok->type != ',') {
1444 if (tok)
1445 isl_stream_push_token(s, tok);
1446 break;
1449 isl_token_free(tok);
1452 return space;
1455 /* Read a tuple space from "s" derived from the parameter space "space".
1456 * Call "read_el" on each element in the tuples.
1458 static __isl_give isl_space *read_tuple_space(__isl_keep isl_stream *s,
1459 struct vars *v, __isl_take isl_space *space, int rational, int comma,
1460 __isl_give isl_space *(*read_el)(__isl_keep isl_stream *s,
1461 struct vars *v, __isl_take isl_space *space, int rational,
1462 void *user),
1463 void *user)
1465 struct isl_token *tok;
1466 char *name = NULL;
1467 isl_space *res = NULL;
1469 tok = isl_stream_next_token(s);
1470 if (!tok)
1471 goto error;
1472 if (tok->type == ISL_TOKEN_IDENT || tok->is_keyword) {
1473 name = strdup(tok->u.s);
1474 isl_token_free(tok);
1475 if (!name)
1476 goto error;
1477 } else
1478 isl_stream_push_token(s, tok);
1479 if (isl_stream_eat(s, '['))
1480 goto error;
1481 if (next_is_tuple(s)) {
1482 isl_space *out;
1483 res = read_tuple_space(s, v, isl_space_copy(space),
1484 rational, comma, read_el, user);
1485 if (isl_stream_eat(s, ISL_TOKEN_TO))
1486 goto error;
1487 out = read_tuple_space(s, v, isl_space_copy(space),
1488 rational, comma, read_el, user);
1489 res = isl_space_product(res, out);
1490 } else
1491 res = read_tuple_list(s, v, isl_space_copy(space),
1492 rational, comma, read_el, user);
1493 if (isl_stream_eat(s, ']'))
1494 goto error;
1496 if (name) {
1497 res = isl_space_set_tuple_name(res, isl_dim_set, name);
1498 free(name);
1501 isl_space_free(space);
1502 return res;
1503 error:
1504 free(name);
1505 isl_space_free(res);
1506 isl_space_free(space);
1507 return NULL;
1510 /* Construct an isl_pw_aff defined on a space with v->n variables
1511 * that is equal to the last of those variables.
1513 static __isl_give isl_pw_aff *identity_tuple_el(struct vars *v)
1515 isl_space *space;
1517 space = isl_space_set_alloc(v->ctx, 0, v->n);
1518 return identity_tuple_el_on_space(space, v);
1521 /* This function is called for each element in a tuple inside read_tuple.
1522 * Add a new variable to "v" and construct a corresponding isl_pw_aff defined
1523 * over a space containing all variables in "v" defined so far.
1524 * The isl_pw_aff expresses the new variable in terms of earlier variables
1525 * if a definition is provided. Otherwise, it is represented as being
1526 * equal to itself.
1527 * Add the isl_pw_aff to *list.
1528 * If the new variable was named, then adjust "space" accordingly and
1529 * return the updated space.
1531 static __isl_give isl_space *read_tuple_pw_aff_el(__isl_keep isl_stream *s,
1532 struct vars *v, __isl_take isl_space *space, int rational, void *user)
1534 isl_pw_aff_list **list = (isl_pw_aff_list **) user;
1535 isl_pw_aff *pa;
1536 struct isl_token *tok;
1537 int new_name = 0;
1539 tok = next_token(s);
1540 if (!tok) {
1541 isl_stream_error(s, NULL, "unexpected EOF");
1542 return isl_space_free(space);
1545 if (tok->type == ISL_TOKEN_IDENT) {
1546 int n = v->n;
1547 int p = vars_pos(v, tok->u.s, -1);
1548 if (p < 0)
1549 goto error;
1550 new_name = p >= n;
1553 if (tok->type == '*') {
1554 if (vars_add_anon(v) < 0)
1555 goto error;
1556 isl_token_free(tok);
1557 pa = identity_tuple_el(v);
1558 } else if (new_name) {
1559 space = space_set_last_dim_name(space, v->v->name);
1560 isl_token_free(tok);
1561 if (isl_stream_eat_if_available(s, '='))
1562 pa = read_tuple_var_def(s, v, rational);
1563 else
1564 pa = identity_tuple_el(v);
1565 } else {
1566 isl_stream_push_token(s, tok);
1567 tok = NULL;
1568 if (vars_add_anon(v) < 0)
1569 goto error;
1570 pa = read_tuple_var_def(s, v, rational);
1573 *list = isl_pw_aff_list_add(*list, pa);
1574 if (!*list)
1575 return isl_space_free(space);
1577 return space;
1578 error:
1579 isl_token_free(tok);
1580 return isl_space_free(space);
1583 /* Read a tuple and represent it as an isl_multi_pw_aff.
1584 * The range space of the isl_multi_pw_aff is the space of the tuple.
1585 * The domain space is an anonymous space
1586 * with a dimension for each variable in the set of variables in "v",
1587 * including the variables in the range.
1588 * If a given dimension is not defined in terms of earlier dimensions in
1589 * the input, then the corresponding isl_pw_aff is set equal to one time
1590 * the variable corresponding to the dimension being defined.
1592 * The elements in the tuple are collected in a list by read_tuple_pw_aff_el.
1593 * Each element in this list is defined over a space representing
1594 * the variables defined so far. We need to adjust the earlier
1595 * elements to have as many variables in the domain as the final
1596 * element in the list.
1598 static __isl_give isl_multi_pw_aff *read_tuple(__isl_keep isl_stream *s,
1599 struct vars *v, int rational, int comma)
1601 int i;
1602 isl_size n;
1603 isl_space *space;
1604 isl_pw_aff_list *list;
1606 space = isl_space_params_alloc(v->ctx, 0);
1607 list = isl_pw_aff_list_alloc(s->ctx, 0);
1608 space = read_tuple_space(s, v, space, rational, comma,
1609 &read_tuple_pw_aff_el, &list);
1610 n = isl_space_dim(space, isl_dim_set);
1611 if (n < 0)
1612 space = isl_space_free(space);
1613 for (i = 0; i + 1 < n; ++i) {
1614 isl_pw_aff *pa;
1616 pa = isl_pw_aff_list_get_pw_aff(list, i);
1617 pa = isl_pw_aff_add_dims(pa, isl_dim_in, n - (i + 1));
1618 list = isl_pw_aff_list_set_pw_aff(list, i, pa);
1621 space = isl_space_from_range(space);
1622 space = isl_space_add_dims(space, isl_dim_in, v->n);
1623 return isl_multi_pw_aff_from_pw_aff_list(space, list);
1626 /* Add the tuple represented by the isl_multi_pw_aff "tuple" to "map".
1627 * We first create the appropriate space in "map" based on the range
1628 * space of this isl_multi_pw_aff. Then, we add equalities based
1629 * on the affine expressions. These live in an anonymous space,
1630 * however, so we first need to reset the space to that of "map".
1632 static __isl_give isl_map *map_from_tuple(__isl_take isl_multi_pw_aff *tuple,
1633 __isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
1634 int rational)
1636 int i;
1637 isl_size n;
1638 isl_ctx *ctx;
1639 isl_space *space = NULL;
1641 n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
1642 if (!map || n < 0)
1643 goto error;
1644 ctx = isl_multi_pw_aff_get_ctx(tuple);
1645 space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
1646 if (!space)
1647 goto error;
1649 if (type == isl_dim_param) {
1650 if (isl_space_has_tuple_name(space, isl_dim_set) ||
1651 isl_space_is_wrapping(space)) {
1652 isl_die(ctx, isl_error_invalid,
1653 "parameter tuples cannot be named or nested",
1654 goto error);
1656 map = isl_map_add_dims(map, type, n);
1657 for (i = 0; i < n; ++i) {
1658 isl_id *id;
1659 if (!isl_space_has_dim_name(space, isl_dim_set, i))
1660 isl_die(ctx, isl_error_invalid,
1661 "parameters must be named",
1662 goto error);
1663 id = isl_space_get_dim_id(space, isl_dim_set, i);
1664 map = isl_map_set_dim_id(map, isl_dim_param, i, id);
1666 } else if (type == isl_dim_in) {
1667 isl_set *set;
1669 set = isl_set_universe(isl_space_copy(space));
1670 if (rational)
1671 set = isl_set_set_rational(set);
1672 set = isl_set_intersect_params(set, isl_map_params(map));
1673 map = isl_map_from_domain(set);
1674 } else {
1675 isl_set *set;
1677 set = isl_set_universe(isl_space_copy(space));
1678 if (rational)
1679 set = isl_set_set_rational(set);
1680 map = isl_map_from_domain_and_range(isl_map_domain(map), set);
1683 for (i = 0; i < n; ++i) {
1684 isl_pw_aff *pa;
1685 isl_space *space;
1686 isl_aff *aff;
1687 isl_set *set;
1688 isl_map *map_i;
1690 pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
1691 space = isl_pw_aff_get_domain_space(pa);
1692 aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
1693 aff = isl_aff_add_coefficient_si(aff,
1694 isl_dim_in, v->n - n + i, -1);
1695 pa = isl_pw_aff_add(pa, isl_pw_aff_from_aff(aff));
1696 if (rational)
1697 pa = isl_pw_aff_set_rational(pa);
1698 set = isl_pw_aff_zero_set(pa);
1699 map_i = isl_map_from_range(set);
1700 map_i = isl_map_reset_space(map_i, isl_map_get_space(map));
1701 map = isl_map_intersect(map, map_i);
1704 isl_space_free(space);
1705 isl_multi_pw_aff_free(tuple);
1706 return map;
1707 error:
1708 isl_space_free(space);
1709 isl_multi_pw_aff_free(tuple);
1710 isl_map_free(map);
1711 return NULL;
1714 /* Read a tuple from "s" and add it to "map".
1715 * The tuple is initially represented as an isl_multi_pw_aff and
1716 * then added to "map".
1718 static __isl_give isl_map *read_map_tuple(__isl_keep isl_stream *s,
1719 __isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
1720 int rational, int comma)
1722 isl_multi_pw_aff *tuple;
1724 tuple = read_tuple(s, v, rational, comma);
1725 if (!tuple)
1726 return isl_map_free(map);
1728 return map_from_tuple(tuple, map, type, v, rational);
1731 /* Read the parameter domain of an expression from "s" (if any) and
1732 * check that it does not involve any constraints.
1733 * "v" contains a description of the identifiers parsed so far
1734 * (of which there should not be any at this point) and is extended
1735 * by this function.
1737 static __isl_give isl_set *read_universe_params(__isl_keep isl_stream *s,
1738 struct vars *v)
1740 isl_set *dom;
1742 dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
1743 if (next_is_tuple(s)) {
1744 dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
1745 if (isl_stream_eat(s, ISL_TOKEN_TO))
1746 return isl_set_free(dom);
1748 if (!isl_set_plain_is_universe(dom))
1749 isl_die(s->ctx, isl_error_invalid,
1750 "expecting universe parameter domain",
1751 return isl_set_free(dom));
1753 return dom;
1756 /* This function is called for each element in a tuple inside read_space_tuples.
1757 * Add a new variable to "v" and adjust "space" accordingly
1758 * if the variable has a name.
1760 static __isl_give isl_space *read_tuple_id(__isl_keep isl_stream *s,
1761 struct vars *v, __isl_take isl_space *space, int rational, void *user)
1763 struct isl_token *tok;
1765 tok = next_token(s);
1766 if (!tok) {
1767 isl_stream_error(s, NULL, "unexpected EOF");
1768 return isl_space_free(space);
1771 if (tok->type == ISL_TOKEN_IDENT) {
1772 int n = v->n;
1773 int p = vars_pos(v, tok->u.s, -1);
1774 if (p < 0)
1775 goto error;
1776 if (p < n) {
1777 isl_stream_error(s, tok, "expecting fresh identifier");
1778 goto error;
1780 space = space_set_last_dim_name(space, v->v->name);
1781 } else if (tok->type == '*') {
1782 if (vars_add_anon(v) < 0)
1783 goto error;
1784 } else {
1785 isl_stream_error(s, tok, "expecting identifier or '*'");
1786 goto error;
1789 isl_token_free(tok);
1790 return space;
1791 error:
1792 isl_token_free(tok);
1793 return isl_space_free(space);
1796 /* Given a parameter space "params", extend it with one or two tuples
1797 * read from "s".
1798 * "v" contains a description of the identifiers parsed so far and is extended
1799 * by this function.
1801 static __isl_give isl_space *read_space_tuples(__isl_keep isl_stream *s,
1802 struct vars *v, __isl_take isl_space *params)
1804 isl_space *space, *ran;
1806 space = read_tuple_space(s, v, isl_space_copy(params), 1, 1,
1807 &read_tuple_id, NULL);
1808 if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
1809 ran = read_tuple_space(s, v, isl_space_copy(params), 1, 1,
1810 &read_tuple_id, NULL);
1811 space = isl_space_unwrap(isl_space_product(space, ran));
1813 isl_space_free(params);
1815 return space;
1818 /* Read an isl_space object from "s".
1820 * First read the parameters (if any).
1822 * Then check if the description is of the special form "{ : }",
1823 * in which case it represents a parameter space.
1824 * Otherwise, it has one or two tuples.
1826 __isl_give isl_space *isl_stream_read_space(__isl_keep isl_stream *s)
1828 struct vars *v;
1829 isl_set *dom;
1830 isl_space *space;
1832 v = vars_new(s->ctx);
1833 if (!v)
1834 return NULL;
1835 dom = read_universe_params(s, v);
1836 space = isl_set_get_space(dom);
1837 isl_set_free(dom);
1839 if (isl_stream_eat(s, '{'))
1840 goto error;
1842 if (!isl_stream_eat_if_available(s, ':'))
1843 space = read_space_tuples(s, v, space);
1845 if (isl_stream_eat(s, '}'))
1846 goto error;
1848 vars_free(v);
1849 return space;
1850 error:
1851 vars_free(v);
1852 isl_space_free(space);
1853 return NULL;
1856 /* Read an isl_space object from "str".
1858 __isl_give isl_space *isl_space_read_from_str(isl_ctx *ctx,
1859 const char *str)
1861 struct isl_space *space;
1862 isl_stream *s = isl_stream_new_str(ctx, str);
1863 if (!s)
1864 return NULL;
1865 space = isl_stream_read_space(s);
1866 isl_stream_free(s);
1867 return space;
1870 /* Given two equal-length lists of piecewise affine expression with the space
1871 * of "set" as domain, construct a set in the same space that expresses
1872 * that "left" and "right" satisfy the comparison "type".
1874 * A space is constructed of the same dimension as the number of elements
1875 * in the two lists. The comparison is then expressed in a map from
1876 * this space to itself and wrapped into a set. Finally the two lists
1877 * of piecewise affine expressions are plugged into this set.
1879 * Let S be the space of "set" and T the constructed space.
1880 * The lists are first changed into two isl_multi_pw_affs in S -> T and
1881 * then combined into an isl_multi_pw_aff in S -> [T -> T],
1882 * while the comparison is first expressed in T -> T, then [T -> T]
1883 * and finally in S.
1885 static __isl_give isl_set *list_cmp(__isl_keep isl_set *set, int type,
1886 __isl_take isl_pw_aff_list *left, __isl_take isl_pw_aff_list *right)
1888 isl_space *space;
1889 isl_size n;
1890 isl_multi_pw_aff *mpa1, *mpa2;
1892 n = isl_pw_aff_list_n_pw_aff(left);
1893 if (!set || n < 0 || !right)
1894 goto error;
1896 space = isl_set_get_space(set);
1897 space = isl_space_from_domain(space);
1898 space = isl_space_add_dims(space, isl_dim_out, n);
1899 mpa1 = isl_multi_pw_aff_from_pw_aff_list(isl_space_copy(space), left);
1900 mpa2 = isl_multi_pw_aff_from_pw_aff_list(isl_space_copy(space), right);
1901 mpa1 = isl_multi_pw_aff_range_product(mpa1, mpa2);
1903 space = isl_space_range(space);
1904 switch (type) {
1905 case ISL_TOKEN_LEX_LT:
1906 set = isl_map_wrap(isl_map_lex_lt(space));
1907 break;
1908 case ISL_TOKEN_LEX_GT:
1909 set = isl_map_wrap(isl_map_lex_gt(space));
1910 break;
1911 case ISL_TOKEN_LEX_LE:
1912 set = isl_map_wrap(isl_map_lex_le(space));
1913 break;
1914 case ISL_TOKEN_LEX_GE:
1915 set = isl_map_wrap(isl_map_lex_ge(space));
1916 break;
1917 default:
1918 isl_multi_pw_aff_free(mpa1);
1919 isl_space_free(space);
1920 isl_die(isl_set_get_ctx(set), isl_error_internal,
1921 "unhandled list comparison type", return NULL);
1923 set = isl_set_preimage_multi_pw_aff(set, mpa1);
1924 return set;
1925 error:
1926 isl_pw_aff_list_free(left);
1927 isl_pw_aff_list_free(right);
1928 return NULL;
1931 /* Construct constraints of the form
1933 * a op b
1935 * where a is an element in "left", op is an operator of type "type" and
1936 * b is an element in "right", add the constraints to "set" and return
1937 * the result.
1938 * "rational" is set if the constraints should be treated as
1939 * a rational constraints.
1941 * If "type" is the type of a comparison operator between lists
1942 * of affine expressions, then a single (compound) constraint
1943 * is constructed by list_cmp instead.
1945 static __isl_give isl_set *construct_constraints(
1946 __isl_take isl_set *set, int type,
1947 __isl_keep isl_pw_aff_list *left, __isl_keep isl_pw_aff_list *right,
1948 int rational)
1950 isl_set *cond;
1952 left = isl_pw_aff_list_copy(left);
1953 right = isl_pw_aff_list_copy(right);
1954 if (rational) {
1955 left = isl_pw_aff_list_set_rational(left);
1956 right = isl_pw_aff_list_set_rational(right);
1958 if (is_list_comparator_type(type))
1959 cond = list_cmp(set, type, left, right);
1960 else if (type == ISL_TOKEN_LE)
1961 cond = isl_pw_aff_list_le_set(left, right);
1962 else if (type == ISL_TOKEN_GE)
1963 cond = isl_pw_aff_list_ge_set(left, right);
1964 else if (type == ISL_TOKEN_LT)
1965 cond = isl_pw_aff_list_lt_set(left, right);
1966 else if (type == ISL_TOKEN_GT)
1967 cond = isl_pw_aff_list_gt_set(left, right);
1968 else if (type == ISL_TOKEN_NE)
1969 cond = isl_pw_aff_list_ne_set(left, right);
1970 else
1971 cond = isl_pw_aff_list_eq_set(left, right);
1973 return isl_set_intersect(set, cond);
1976 /* Read a constraint from "s", add it to "map" and return the result.
1977 * "v" contains a description of the identifiers parsed so far.
1978 * "rational" is set if the constraint should be treated as
1979 * a rational constraint.
1980 * The constraint read from "s" may be applied to multiple pairs
1981 * of affine expressions and may be chained.
1982 * In particular, a list of affine expressions is read, followed
1983 * by a comparison operator and another list of affine expressions.
1984 * The comparison operator is then applied to each pair of elements
1985 * in the two lists and the results are added to "map".
1986 * However, if the operator expects two lists of affine expressions,
1987 * then it is applied directly to those lists and the two lists
1988 * are required to have the same length.
1989 * If the next token is another comparison operator, then another
1990 * list of affine expressions is read and the process repeats.
1992 * The processing is performed on a wrapped copy of "map" because
1993 * an affine expression cannot have a binary relation as domain.
1995 static __isl_give isl_map *add_constraint(__isl_keep isl_stream *s,
1996 struct vars *v, __isl_take isl_map *map, int rational)
1998 struct isl_token *tok;
1999 int type;
2000 isl_pw_aff_list *list1 = NULL, *list2 = NULL;
2001 isl_size n1, n2;
2002 isl_set *set;
2004 set = isl_map_wrap(map);
2005 list1 = accept_affine_list(s, isl_set_get_space(set), v);
2006 if (!list1)
2007 goto error;
2008 tok = isl_stream_next_token(s);
2009 if (!is_comparator(tok)) {
2010 isl_stream_error(s, tok, "missing operator");
2011 if (tok)
2012 isl_stream_push_token(s, tok);
2013 goto error;
2015 type = tok->type;
2016 isl_token_free(tok);
2017 for (;;) {
2018 list2 = accept_affine_list(s, isl_set_get_space(set), v);
2019 n1 = isl_pw_aff_list_n_pw_aff(list1);
2020 n2 = isl_pw_aff_list_n_pw_aff(list2);
2021 if (n1 < 0 || n2 < 0)
2022 goto error;
2023 if (is_list_comparator_type(type) && n1 != n2) {
2024 isl_stream_error(s, NULL,
2025 "list arguments not of same size");
2026 goto error;
2029 set = construct_constraints(set, type, list1, list2, rational);
2030 isl_pw_aff_list_free(list1);
2031 list1 = list2;
2033 if (!next_is_comparator(s))
2034 break;
2035 tok = isl_stream_next_token(s);
2036 type = tok->type;
2037 isl_token_free(tok);
2039 isl_pw_aff_list_free(list1);
2041 return isl_set_unwrap(set);
2042 error:
2043 isl_pw_aff_list_free(list1);
2044 isl_pw_aff_list_free(list2);
2045 isl_set_free(set);
2046 return NULL;
2049 static __isl_give isl_map *read_exists(__isl_keep isl_stream *s,
2050 struct vars *v, __isl_take isl_map *map, int rational)
2052 int n = v->n;
2053 int seen_paren = isl_stream_eat_if_available(s, '(');
2055 map = isl_map_from_domain(isl_map_wrap(map));
2056 map = read_defined_var_list(s, v, map, rational);
2058 if (isl_stream_eat(s, ':'))
2059 goto error;
2061 map = read_formula(s, v, map, rational);
2062 map = isl_set_unwrap(isl_map_domain(map));
2064 vars_drop(v, v->n - n);
2065 if (seen_paren && isl_stream_eat(s, ')'))
2066 goto error;
2068 return map;
2069 error:
2070 isl_map_free(map);
2071 return NULL;
2074 /* Parse an expression between parentheses and push the result
2075 * back on the stream.
2077 * The parsed expression may be either an affine expression
2078 * or a condition. The first type is pushed onto the stream
2079 * as an isl_pw_aff, while the second is pushed as an isl_map.
2081 * If the initial token indicates the start of a condition,
2082 * we parse it as such.
2083 * Otherwise, we first parse an affine expression and push
2084 * that onto the stream. If the affine expression covers the
2085 * entire expression between parentheses, we return.
2086 * Otherwise, we assume that the affine expression is the
2087 * start of a condition and continue parsing.
2089 static int resolve_paren_expr(__isl_keep isl_stream *s,
2090 struct vars *v, __isl_take isl_map *map, int rational)
2092 struct isl_token *tok, *tok2;
2093 int has_paren;
2094 int line, col;
2095 isl_pw_aff *pwaff;
2097 tok = isl_stream_next_token(s);
2098 if (!tok || tok->type != '(')
2099 goto error;
2101 if (isl_stream_next_token_is(s, '('))
2102 if (resolve_paren_expr(s, v, isl_map_copy(map), rational))
2103 goto error;
2105 if (next_is_condition_start(s)) {
2106 map = read_formula(s, v, map, rational);
2107 if (isl_stream_eat(s, ')'))
2108 goto error;
2109 tok->type = ISL_TOKEN_MAP;
2110 tok->u.map = map;
2111 isl_stream_push_token(s, tok);
2112 return 0;
2115 tok2 = isl_stream_next_token(s);
2116 if (!tok2)
2117 goto error;
2118 line = tok2->line;
2119 col = tok2->col;
2120 isl_stream_push_token(s, tok2);
2122 pwaff = accept_affine(s, isl_space_wrap(isl_map_get_space(map)), v);
2123 if (!pwaff)
2124 goto error;
2126 has_paren = isl_stream_eat_if_available(s, ')');
2128 if (push_aff(s, line, col, pwaff) < 0)
2129 goto error;
2131 if (has_paren) {
2132 isl_token_free(tok);
2133 isl_map_free(map);
2134 return 0;
2137 map = read_formula(s, v, map, rational);
2138 if (isl_stream_eat(s, ')'))
2139 goto error;
2141 tok->type = ISL_TOKEN_MAP;
2142 tok->u.map = map;
2143 isl_stream_push_token(s, tok);
2145 return 0;
2146 error:
2147 isl_token_free(tok);
2148 isl_map_free(map);
2149 return -1;
2152 static __isl_give isl_map *read_conjunct(__isl_keep isl_stream *s,
2153 struct vars *v, __isl_take isl_map *map, int rational)
2155 if (isl_stream_next_token_is(s, '('))
2156 if (resolve_paren_expr(s, v, isl_map_copy(map), rational))
2157 goto error;
2159 if (isl_stream_next_token_is(s, ISL_TOKEN_MAP)) {
2160 struct isl_token *tok;
2161 tok = isl_stream_next_token(s);
2162 if (!tok)
2163 goto error;
2164 isl_map_free(map);
2165 map = isl_map_copy(tok->u.map);
2166 isl_token_free(tok);
2167 return map;
2170 if (isl_stream_eat_if_available(s, ISL_TOKEN_EXISTS))
2171 return read_exists(s, v, map, rational);
2173 if (isl_stream_eat_if_available(s, ISL_TOKEN_TRUE))
2174 return map;
2176 if (isl_stream_eat_if_available(s, ISL_TOKEN_FALSE)) {
2177 isl_space *space = isl_map_get_space(map);
2178 isl_map_free(map);
2179 return isl_map_empty(space);
2182 return add_constraint(s, v, map, rational);
2183 error:
2184 isl_map_free(map);
2185 return NULL;
2188 static __isl_give isl_map *read_conjuncts(__isl_keep isl_stream *s,
2189 struct vars *v, __isl_take isl_map *map, int rational)
2191 isl_map *res;
2192 int negate;
2194 negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT);
2195 res = read_conjunct(s, v, isl_map_copy(map), rational);
2196 if (negate)
2197 res = isl_map_subtract(isl_map_copy(map), res);
2199 while (res && isl_stream_eat_if_available(s, ISL_TOKEN_AND)) {
2200 isl_map *res_i;
2202 negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT);
2203 res_i = read_conjunct(s, v, isl_map_copy(map), rational);
2204 if (negate)
2205 res = isl_map_subtract(res, res_i);
2206 else
2207 res = isl_map_intersect(res, res_i);
2210 isl_map_free(map);
2211 return res;
2214 static __isl_give isl_map *read_disjuncts(__isl_keep isl_stream *s,
2215 struct vars *v, __isl_take isl_map *map, int rational)
2217 isl_map *res;
2219 if (isl_stream_next_token_is(s, '}'))
2220 return map;
2222 res = read_conjuncts(s, v, isl_map_copy(map), rational);
2223 while (isl_stream_eat_if_available(s, ISL_TOKEN_OR)) {
2224 isl_map *res_i;
2226 res_i = read_conjuncts(s, v, isl_map_copy(map), rational);
2227 res = isl_map_union(res, res_i);
2230 isl_map_free(map);
2231 return res;
2234 /* Read a first order formula from "s", add the corresponding
2235 * constraints to "map" and return the result.
2237 * In particular, read a formula of the form
2241 * or
2243 * a implies b
2245 * where a and b are disjunctions.
2247 * In the first case, map is replaced by
2249 * map \cap { [..] : a }
2251 * In the second case, it is replaced by
2253 * (map \setminus { [..] : a}) \cup (map \cap { [..] : b })
2255 static __isl_give isl_map *read_formula(__isl_keep isl_stream *s,
2256 struct vars *v, __isl_take isl_map *map, int rational)
2258 isl_map *res;
2260 res = read_disjuncts(s, v, isl_map_copy(map), rational);
2262 if (isl_stream_eat_if_available(s, ISL_TOKEN_IMPLIES)) {
2263 isl_map *res2;
2265 res = isl_map_subtract(isl_map_copy(map), res);
2266 res2 = read_disjuncts(s, v, map, rational);
2267 res = isl_map_union(res, res2);
2268 } else
2269 isl_map_free(map);
2271 return res;
2274 static isl_size polylib_pos_to_isl_pos(__isl_keep isl_basic_map *bmap, int pos)
2276 isl_size n_out, n_in, n_param, n_div;
2278 n_param = isl_basic_map_dim(bmap, isl_dim_param);
2279 n_in = isl_basic_map_dim(bmap, isl_dim_in);
2280 n_out = isl_basic_map_dim(bmap, isl_dim_out);
2281 n_div = isl_basic_map_dim(bmap, isl_dim_div);
2282 if (n_param < 0 || n_in < 0 || n_out < 0 || n_div < 0)
2283 return isl_size_error;
2285 if (pos < n_out)
2286 return 1 + n_param + n_in + pos;
2287 pos -= n_out;
2289 if (pos < n_in)
2290 return 1 + n_param + pos;
2291 pos -= n_in;
2293 if (pos < n_div)
2294 return 1 + n_param + n_in + n_out + pos;
2295 pos -= n_div;
2297 if (pos < n_param)
2298 return 1 + pos;
2300 return 0;
2303 static __isl_give isl_basic_map *basic_map_read_polylib_constraint(
2304 __isl_keep isl_stream *s, __isl_take isl_basic_map *bmap)
2306 int j;
2307 struct isl_token *tok;
2308 int type;
2309 int k;
2310 isl_int *c;
2311 isl_size total;
2313 if (!bmap)
2314 return NULL;
2316 tok = isl_stream_next_token(s);
2317 if (!tok || tok->type != ISL_TOKEN_VALUE) {
2318 isl_stream_error(s, tok, "expecting coefficient");
2319 if (tok)
2320 isl_stream_push_token(s, tok);
2321 goto error;
2323 if (!tok->on_new_line) {
2324 isl_stream_error(s, tok, "coefficient should appear on new line");
2325 isl_stream_push_token(s, tok);
2326 goto error;
2329 type = isl_int_get_si(tok->u.v);
2330 isl_token_free(tok);
2332 isl_assert(s->ctx, type == 0 || type == 1, goto error);
2333 if (type == 0) {
2334 k = isl_basic_map_alloc_equality(bmap);
2335 c = bmap->eq[k];
2336 } else {
2337 k = isl_basic_map_alloc_inequality(bmap);
2338 c = bmap->ineq[k];
2340 if (k < 0)
2341 goto error;
2343 total = isl_basic_map_dim(bmap, isl_dim_all);
2344 if (total < 0)
2345 return isl_basic_map_free(bmap);
2346 for (j = 0; j < 1 + total; ++j) {
2347 isl_size pos;
2348 tok = isl_stream_next_token(s);
2349 if (!tok || tok->type != ISL_TOKEN_VALUE) {
2350 isl_stream_error(s, tok, "expecting coefficient");
2351 if (tok)
2352 isl_stream_push_token(s, tok);
2353 goto error;
2355 if (tok->on_new_line) {
2356 isl_stream_error(s, tok,
2357 "coefficient should not appear on new line");
2358 isl_stream_push_token(s, tok);
2359 goto error;
2361 pos = polylib_pos_to_isl_pos(bmap, j);
2362 if (pos >= 0)
2363 isl_int_set(c[pos], tok->u.v);
2364 isl_token_free(tok);
2365 if (pos < 0)
2366 return isl_basic_map_free(bmap);
2369 return bmap;
2370 error:
2371 isl_basic_map_free(bmap);
2372 return NULL;
2375 static __isl_give isl_basic_map *basic_map_read_polylib(
2376 __isl_keep isl_stream *s)
2378 int i;
2379 struct isl_token *tok;
2380 struct isl_token *tok2;
2381 int n_row, n_col;
2382 int on_new_line;
2383 unsigned in = 0, out, local = 0;
2384 struct isl_basic_map *bmap = NULL;
2385 int nparam = 0;
2387 tok = isl_stream_next_token(s);
2388 if (!tok) {
2389 isl_stream_error(s, NULL, "unexpected EOF");
2390 return NULL;
2392 tok2 = isl_stream_next_token(s);
2393 if (!tok2) {
2394 isl_token_free(tok);
2395 isl_stream_error(s, NULL, "unexpected EOF");
2396 return NULL;
2398 if (tok->type != ISL_TOKEN_VALUE || tok2->type != ISL_TOKEN_VALUE) {
2399 isl_stream_push_token(s, tok2);
2400 isl_stream_push_token(s, tok);
2401 isl_stream_error(s, NULL,
2402 "expecting constraint matrix dimensions");
2403 return NULL;
2405 n_row = isl_int_get_si(tok->u.v);
2406 n_col = isl_int_get_si(tok2->u.v);
2407 on_new_line = tok2->on_new_line;
2408 isl_token_free(tok2);
2409 isl_token_free(tok);
2410 isl_assert(s->ctx, !on_new_line, return NULL);
2411 isl_assert(s->ctx, n_row >= 0, return NULL);
2412 isl_assert(s->ctx, n_col >= 2 + nparam, return NULL);
2413 tok = isl_stream_next_token_on_same_line(s);
2414 if (tok) {
2415 if (tok->type != ISL_TOKEN_VALUE) {
2416 isl_stream_error(s, tok,
2417 "expecting number of output dimensions");
2418 isl_stream_push_token(s, tok);
2419 goto error;
2421 out = isl_int_get_si(tok->u.v);
2422 isl_token_free(tok);
2424 tok = isl_stream_next_token_on_same_line(s);
2425 if (!tok || tok->type != ISL_TOKEN_VALUE) {
2426 isl_stream_error(s, tok,
2427 "expecting number of input dimensions");
2428 if (tok)
2429 isl_stream_push_token(s, tok);
2430 goto error;
2432 in = isl_int_get_si(tok->u.v);
2433 isl_token_free(tok);
2435 tok = isl_stream_next_token_on_same_line(s);
2436 if (!tok || tok->type != ISL_TOKEN_VALUE) {
2437 isl_stream_error(s, tok,
2438 "expecting number of existentials");
2439 if (tok)
2440 isl_stream_push_token(s, tok);
2441 goto error;
2443 local = isl_int_get_si(tok->u.v);
2444 isl_token_free(tok);
2446 tok = isl_stream_next_token_on_same_line(s);
2447 if (!tok || tok->type != ISL_TOKEN_VALUE) {
2448 isl_stream_error(s, tok,
2449 "expecting number of parameters");
2450 if (tok)
2451 isl_stream_push_token(s, tok);
2452 goto error;
2454 nparam = isl_int_get_si(tok->u.v);
2455 isl_token_free(tok);
2456 if (n_col != 1 + out + in + local + nparam + 1) {
2457 isl_stream_error(s, NULL,
2458 "dimensions don't match");
2459 goto error;
2461 } else
2462 out = n_col - 2 - nparam;
2463 bmap = isl_basic_map_alloc(s->ctx, nparam, in, out, local, n_row, n_row);
2464 if (!bmap)
2465 return NULL;
2467 for (i = 0; i < local; ++i) {
2468 int k = isl_basic_map_alloc_div(bmap);
2469 if (k < 0)
2470 goto error;
2471 isl_seq_clr(bmap->div[k], 1 + 1 + nparam + in + out + local);
2474 for (i = 0; i < n_row; ++i)
2475 bmap = basic_map_read_polylib_constraint(s, bmap);
2477 tok = isl_stream_next_token_on_same_line(s);
2478 if (tok) {
2479 isl_stream_error(s, tok, "unexpected extra token on line");
2480 isl_stream_push_token(s, tok);
2481 goto error;
2484 bmap = isl_basic_map_simplify(bmap);
2485 bmap = isl_basic_map_finalize(bmap);
2486 return bmap;
2487 error:
2488 isl_basic_map_free(bmap);
2489 return NULL;
2492 static __isl_give isl_map *map_read_polylib(__isl_keep isl_stream *s)
2494 struct isl_token *tok;
2495 struct isl_token *tok2;
2496 int i, n;
2497 struct isl_map *map;
2499 tok = isl_stream_next_token(s);
2500 if (!tok) {
2501 isl_stream_error(s, NULL, "unexpected EOF");
2502 return NULL;
2504 tok2 = isl_stream_next_token_on_same_line(s);
2505 if (tok2 && tok2->type == ISL_TOKEN_VALUE) {
2506 isl_stream_push_token(s, tok2);
2507 isl_stream_push_token(s, tok);
2508 return isl_map_from_basic_map(basic_map_read_polylib(s));
2510 if (tok2) {
2511 isl_stream_error(s, tok2, "unexpected token");
2512 isl_stream_push_token(s, tok2);
2513 isl_stream_push_token(s, tok);
2514 return NULL;
2516 n = isl_int_get_si(tok->u.v);
2517 isl_token_free(tok);
2519 isl_assert(s->ctx, n >= 1, return NULL);
2521 map = isl_map_from_basic_map(basic_map_read_polylib(s));
2523 for (i = 1; map && i < n; ++i)
2524 map = isl_map_union(map,
2525 isl_map_from_basic_map(basic_map_read_polylib(s)));
2527 return map;
2530 static int optional_power(__isl_keep isl_stream *s)
2532 int pow;
2533 struct isl_token *tok;
2535 tok = isl_stream_next_token(s);
2536 if (!tok)
2537 return 1;
2538 if (tok->type != '^') {
2539 isl_stream_push_token(s, tok);
2540 return 1;
2542 isl_token_free(tok);
2543 tok = isl_stream_next_token(s);
2544 if (!tok || tok->type != ISL_TOKEN_VALUE) {
2545 isl_stream_error(s, tok, "expecting exponent");
2546 if (tok)
2547 isl_stream_push_token(s, tok);
2548 return 1;
2550 pow = isl_int_get_si(tok->u.v);
2551 isl_token_free(tok);
2552 return pow;
2555 static __isl_give isl_pw_qpolynomial *read_term(__isl_keep isl_stream *s,
2556 __isl_keep isl_map *map, struct vars *v);
2558 static __isl_give isl_pw_qpolynomial *read_factor(__isl_keep isl_stream *s,
2559 __isl_keep isl_map *map, struct vars *v)
2561 isl_pw_qpolynomial *pwqp;
2562 struct isl_token *tok;
2564 tok = next_token(s);
2565 if (!tok) {
2566 isl_stream_error(s, NULL, "unexpected EOF");
2567 return NULL;
2569 if (tok->type == '(') {
2570 int pow;
2572 isl_token_free(tok);
2573 pwqp = read_term(s, map, v);
2574 if (!pwqp)
2575 return NULL;
2576 if (isl_stream_eat(s, ')'))
2577 goto error;
2578 pow = optional_power(s);
2579 pwqp = isl_pw_qpolynomial_pow(pwqp, pow);
2580 } else if (tok->type == ISL_TOKEN_VALUE) {
2581 struct isl_token *tok2;
2582 isl_qpolynomial *qp;
2584 tok2 = isl_stream_next_token(s);
2585 if (tok2 && tok2->type == '/') {
2586 isl_token_free(tok2);
2587 tok2 = next_token(s);
2588 if (!tok2 || tok2->type != ISL_TOKEN_VALUE) {
2589 isl_stream_error(s, tok2, "expected denominator");
2590 isl_token_free(tok);
2591 isl_token_free(tok2);
2592 return NULL;
2594 qp = isl_qpolynomial_rat_cst_on_domain(isl_map_get_space(map),
2595 tok->u.v, tok2->u.v);
2596 isl_token_free(tok2);
2597 } else {
2598 isl_stream_push_token(s, tok2);
2599 qp = isl_qpolynomial_cst_on_domain(isl_map_get_space(map),
2600 tok->u.v);
2602 isl_token_free(tok);
2603 pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
2604 } else if (tok->type == ISL_TOKEN_INFTY) {
2605 isl_qpolynomial *qp;
2606 isl_token_free(tok);
2607 qp = isl_qpolynomial_infty_on_domain(isl_map_get_space(map));
2608 pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
2609 } else if (tok->type == ISL_TOKEN_NAN) {
2610 isl_qpolynomial *qp;
2611 isl_token_free(tok);
2612 qp = isl_qpolynomial_nan_on_domain(isl_map_get_space(map));
2613 pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
2614 } else if (tok->type == ISL_TOKEN_IDENT) {
2615 int n = v->n;
2616 int pos = vars_pos(v, tok->u.s, -1);
2617 int pow;
2618 isl_qpolynomial *qp;
2619 if (pos < 0) {
2620 isl_token_free(tok);
2621 return NULL;
2623 if (pos >= n) {
2624 vars_drop(v, v->n - n);
2625 isl_stream_error(s, tok, "unknown identifier");
2626 isl_token_free(tok);
2627 return NULL;
2629 isl_token_free(tok);
2630 pow = optional_power(s);
2631 qp = isl_qpolynomial_var_pow_on_domain(isl_map_get_space(map), pos, pow);
2632 pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
2633 } else if (is_start_of_div(tok)) {
2634 isl_pw_aff *pwaff;
2635 int pow;
2637 isl_stream_push_token(s, tok);
2638 pwaff = accept_div(s, isl_map_get_space(map), v);
2639 pow = optional_power(s);
2640 pwqp = isl_pw_qpolynomial_from_pw_aff(pwaff);
2641 pwqp = isl_pw_qpolynomial_pow(pwqp, pow);
2642 } else if (tok->type == '-') {
2643 isl_token_free(tok);
2644 pwqp = read_factor(s, map, v);
2645 pwqp = isl_pw_qpolynomial_neg(pwqp);
2646 } else {
2647 isl_stream_error(s, tok, "unexpected isl_token");
2648 isl_stream_push_token(s, tok);
2649 return NULL;
2652 if (isl_stream_eat_if_available(s, '*') ||
2653 isl_stream_next_token_is(s, ISL_TOKEN_IDENT)) {
2654 isl_pw_qpolynomial *pwqp2;
2656 pwqp2 = read_factor(s, map, v);
2657 pwqp = isl_pw_qpolynomial_mul(pwqp, pwqp2);
2660 return pwqp;
2661 error:
2662 isl_pw_qpolynomial_free(pwqp);
2663 return NULL;
2666 static __isl_give isl_pw_qpolynomial *read_term(__isl_keep isl_stream *s,
2667 __isl_keep isl_map *map, struct vars *v)
2669 struct isl_token *tok;
2670 isl_pw_qpolynomial *pwqp;
2672 pwqp = read_factor(s, map, v);
2674 for (;;) {
2675 tok = next_token(s);
2676 if (!tok)
2677 return pwqp;
2679 if (tok->type == '+') {
2680 isl_pw_qpolynomial *pwqp2;
2682 isl_token_free(tok);
2683 pwqp2 = read_factor(s, map, v);
2684 pwqp = isl_pw_qpolynomial_add(pwqp, pwqp2);
2685 } else if (tok->type == '-') {
2686 isl_pw_qpolynomial *pwqp2;
2688 isl_token_free(tok);
2689 pwqp2 = read_factor(s, map, v);
2690 pwqp = isl_pw_qpolynomial_sub(pwqp, pwqp2);
2691 } else if (tok->type == ISL_TOKEN_VALUE &&
2692 isl_int_is_neg(tok->u.v)) {
2693 isl_pw_qpolynomial *pwqp2;
2695 isl_stream_push_token(s, tok);
2696 pwqp2 = read_factor(s, map, v);
2697 pwqp = isl_pw_qpolynomial_add(pwqp, pwqp2);
2698 } else {
2699 isl_stream_push_token(s, tok);
2700 break;
2704 return pwqp;
2707 static __isl_give isl_map *read_optional_formula(__isl_keep isl_stream *s,
2708 __isl_take isl_map *map, struct vars *v, int rational)
2710 struct isl_token *tok;
2712 tok = isl_stream_next_token(s);
2713 if (!tok) {
2714 isl_stream_error(s, NULL, "unexpected EOF");
2715 goto error;
2717 if (tok->type == ':' ||
2718 (tok->type == ISL_TOKEN_OR && !strcmp(tok->u.s, "|"))) {
2719 isl_token_free(tok);
2720 map = read_formula(s, v, map, rational);
2721 } else
2722 isl_stream_push_token(s, tok);
2724 return map;
2725 error:
2726 isl_map_free(map);
2727 return NULL;
2730 static struct isl_obj obj_read_poly(__isl_keep isl_stream *s,
2731 __isl_take isl_map *map, struct vars *v, int n)
2733 struct isl_obj obj = { isl_obj_pw_qpolynomial, NULL };
2734 isl_pw_qpolynomial *pwqp;
2735 struct isl_set *set;
2737 pwqp = read_term(s, map, v);
2738 map = read_optional_formula(s, map, v, 0);
2739 set = isl_map_range(map);
2741 pwqp = isl_pw_qpolynomial_intersect_domain(pwqp, set);
2743 vars_drop(v, v->n - n);
2745 obj.v = pwqp;
2746 return obj;
2749 static struct isl_obj obj_read_poly_or_fold(__isl_keep isl_stream *s,
2750 __isl_take isl_set *set, struct vars *v, int n)
2752 int min, max;
2753 struct isl_obj obj = { isl_obj_pw_qpolynomial_fold, NULL };
2754 isl_pw_qpolynomial *pwqp;
2755 isl_pw_qpolynomial_fold *pwf = NULL;
2756 enum isl_fold fold;
2758 max = isl_stream_eat_if_available(s, ISL_TOKEN_MAX);
2759 min = !max && isl_stream_eat_if_available(s, ISL_TOKEN_MIN);
2760 if (!min && !max)
2761 return obj_read_poly(s, set, v, n);
2762 fold = max ? isl_fold_max : isl_fold_min;
2764 if (isl_stream_eat(s, '('))
2765 goto error;
2767 pwqp = read_term(s, set, v);
2768 pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(fold, pwqp);
2770 while (isl_stream_eat_if_available(s, ',')) {
2771 isl_pw_qpolynomial_fold *pwf_i;
2772 pwqp = read_term(s, set, v);
2773 pwf_i = isl_pw_qpolynomial_fold_from_pw_qpolynomial(fold, pwqp);
2774 pwf = isl_pw_qpolynomial_fold_fold(pwf, pwf_i);
2777 if (isl_stream_eat(s, ')'))
2778 goto error;
2780 set = read_optional_formula(s, set, v, 0);
2781 pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, set);
2783 vars_drop(v, v->n - n);
2785 obj.v = pwf;
2786 return obj;
2787 error:
2788 isl_set_free(set);
2789 isl_pw_qpolynomial_fold_free(pwf);
2790 obj.type = isl_obj_none;
2791 return obj;
2794 static int is_rational(__isl_keep isl_stream *s)
2796 struct isl_token *tok;
2798 tok = isl_stream_next_token(s);
2799 if (!tok)
2800 return 0;
2801 if (tok->type == ISL_TOKEN_RAT && isl_stream_next_token_is(s, ':')) {
2802 isl_token_free(tok);
2803 isl_stream_eat(s, ':');
2804 return 1;
2807 isl_stream_push_token(s, tok);
2809 return 0;
2812 static struct isl_obj obj_read_body(__isl_keep isl_stream *s,
2813 __isl_take isl_map *map, struct vars *v)
2815 struct isl_token *tok;
2816 struct isl_obj obj = { isl_obj_set, NULL };
2817 int n = v->n;
2818 int rational;
2820 rational = is_rational(s);
2821 if (rational)
2822 map = isl_map_set_rational(map);
2824 if (isl_stream_next_token_is(s, ':')) {
2825 obj.type = isl_obj_set;
2826 obj.v = read_optional_formula(s, map, v, rational);
2827 return obj;
2830 if (!next_is_tuple(s))
2831 return obj_read_poly_or_fold(s, map, v, n);
2833 map = read_map_tuple(s, map, isl_dim_in, v, rational, 0);
2834 if (!map)
2835 goto error;
2836 tok = isl_stream_next_token(s);
2837 if (!tok)
2838 goto error;
2839 if (tok->type == ISL_TOKEN_TO) {
2840 obj.type = isl_obj_map;
2841 isl_token_free(tok);
2842 if (!next_is_tuple(s)) {
2843 isl_set *set = isl_map_domain(map);
2844 return obj_read_poly_or_fold(s, set, v, n);
2846 map = read_map_tuple(s, map, isl_dim_out, v, rational, 0);
2847 if (!map)
2848 goto error;
2849 } else {
2850 map = isl_map_domain(map);
2851 isl_stream_push_token(s, tok);
2854 map = read_optional_formula(s, map, v, rational);
2856 vars_drop(v, v->n - n);
2858 obj.v = map;
2859 return obj;
2860 error:
2861 isl_map_free(map);
2862 obj.type = isl_obj_none;
2863 return obj;
2866 static struct isl_obj to_union(isl_ctx *ctx, struct isl_obj obj)
2868 if (obj.type == isl_obj_map) {
2869 obj.v = isl_union_map_from_map(obj.v);
2870 obj.type = isl_obj_union_map;
2871 } else if (obj.type == isl_obj_set) {
2872 obj.v = isl_union_set_from_set(obj.v);
2873 obj.type = isl_obj_union_set;
2874 } else if (obj.type == isl_obj_pw_qpolynomial) {
2875 obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v);
2876 obj.type = isl_obj_union_pw_qpolynomial;
2877 } else if (obj.type == isl_obj_pw_qpolynomial_fold) {
2878 obj.v = isl_union_pw_qpolynomial_fold_from_pw_qpolynomial_fold(obj.v);
2879 obj.type = isl_obj_union_pw_qpolynomial_fold;
2880 } else
2881 isl_assert(ctx, 0, goto error);
2882 return obj;
2883 error:
2884 obj.type->free(obj.v);
2885 obj.type = isl_obj_none;
2886 return obj;
2889 static struct isl_obj obj_add(__isl_keep isl_stream *s,
2890 struct isl_obj obj1, struct isl_obj obj2)
2892 if (obj2.type == isl_obj_none || !obj2.v)
2893 goto error;
2894 if (obj1.type == isl_obj_set && obj2.type == isl_obj_union_set)
2895 obj1 = to_union(s->ctx, obj1);
2896 if (obj1.type == isl_obj_union_set && obj2.type == isl_obj_set)
2897 obj2 = to_union(s->ctx, obj2);
2898 if (obj1.type == isl_obj_map && obj2.type == isl_obj_union_map)
2899 obj1 = to_union(s->ctx, obj1);
2900 if (obj1.type == isl_obj_union_map && obj2.type == isl_obj_map)
2901 obj2 = to_union(s->ctx, obj2);
2902 if (obj1.type == isl_obj_pw_qpolynomial &&
2903 obj2.type == isl_obj_union_pw_qpolynomial)
2904 obj1 = to_union(s->ctx, obj1);
2905 if (obj1.type == isl_obj_union_pw_qpolynomial &&
2906 obj2.type == isl_obj_pw_qpolynomial)
2907 obj2 = to_union(s->ctx, obj2);
2908 if (obj1.type == isl_obj_pw_qpolynomial_fold &&
2909 obj2.type == isl_obj_union_pw_qpolynomial_fold)
2910 obj1 = to_union(s->ctx, obj1);
2911 if (obj1.type == isl_obj_union_pw_qpolynomial_fold &&
2912 obj2.type == isl_obj_pw_qpolynomial_fold)
2913 obj2 = to_union(s->ctx, obj2);
2914 if (obj1.type != obj2.type) {
2915 isl_stream_error(s, NULL,
2916 "attempt to combine incompatible objects");
2917 goto error;
2919 if (!obj1.type->add)
2920 isl_die(s->ctx, isl_error_internal,
2921 "combination not supported on object type", goto error);
2922 if (obj1.type == isl_obj_map && !isl_map_has_equal_space(obj1.v, obj2.v)) {
2923 obj1 = to_union(s->ctx, obj1);
2924 obj2 = to_union(s->ctx, obj2);
2926 if (obj1.type == isl_obj_set && !isl_set_has_equal_space(obj1.v, obj2.v)) {
2927 obj1 = to_union(s->ctx, obj1);
2928 obj2 = to_union(s->ctx, obj2);
2930 if (obj1.type == isl_obj_pw_qpolynomial &&
2931 !isl_pw_qpolynomial_has_equal_space(obj1.v, obj2.v)) {
2932 obj1 = to_union(s->ctx, obj1);
2933 obj2 = to_union(s->ctx, obj2);
2935 if (obj1.type == isl_obj_pw_qpolynomial_fold &&
2936 !isl_pw_qpolynomial_fold_has_equal_space(obj1.v, obj2.v)) {
2937 obj1 = to_union(s->ctx, obj1);
2938 obj2 = to_union(s->ctx, obj2);
2940 obj1.v = obj1.type->add(obj1.v, obj2.v);
2941 return obj1;
2942 error:
2943 obj1.type->free(obj1.v);
2944 obj2.type->free(obj2.v);
2945 obj1.type = isl_obj_none;
2946 obj1.v = NULL;
2947 return obj1;
2950 /* Are the first two tokens on "s", "domain" (either as a string
2951 * or as an identifier) followed by ":"?
2953 static int next_is_domain_colon(__isl_keep isl_stream *s)
2955 struct isl_token *tok;
2956 char *name;
2957 int res;
2959 tok = isl_stream_next_token(s);
2960 if (!tok)
2961 return 0;
2962 if (tok->type != ISL_TOKEN_IDENT && tok->type != ISL_TOKEN_STRING) {
2963 isl_stream_push_token(s, tok);
2964 return 0;
2967 name = isl_token_get_str(s->ctx, tok);
2968 res = !strcmp(name, "domain") && isl_stream_next_token_is(s, ':');
2969 free(name);
2971 isl_stream_push_token(s, tok);
2973 return res;
2976 /* Do the first tokens on "s" look like a schedule?
2978 * The root of a schedule is always a domain node, so the first thing
2979 * we expect in the stream is a domain key, i.e., "domain" followed
2980 * by ":". If the schedule was printed in YAML flow style, then
2981 * we additionally expect a "{" to open the outer mapping.
2983 static int next_is_schedule(__isl_keep isl_stream *s)
2985 struct isl_token *tok;
2986 int is_schedule;
2988 tok = isl_stream_next_token(s);
2989 if (!tok)
2990 return 0;
2991 if (tok->type != '{') {
2992 isl_stream_push_token(s, tok);
2993 return next_is_domain_colon(s);
2996 is_schedule = next_is_domain_colon(s);
2997 isl_stream_push_token(s, tok);
2999 return is_schedule;
3002 /* Read an isl_schedule from "s" and store it in an isl_obj.
3004 static struct isl_obj schedule_read(__isl_keep isl_stream *s)
3006 struct isl_obj obj;
3008 obj.type = isl_obj_schedule;
3009 obj.v = isl_stream_read_schedule(s);
3011 return obj;
3014 /* Read a disjunction of object bodies from "s".
3015 * That is, read the inside of the braces, but not the braces themselves.
3016 * "v" contains a description of the identifiers parsed so far.
3017 * "map" contains information about the parameters.
3019 static struct isl_obj obj_read_disjuncts(__isl_keep isl_stream *s,
3020 struct vars *v, __isl_keep isl_map *map)
3022 struct isl_obj obj = { isl_obj_set, NULL };
3024 if (isl_stream_next_token_is(s, '}')) {
3025 obj.type = isl_obj_union_set;
3026 obj.v = isl_union_set_empty(isl_map_get_space(map));
3027 return obj;
3030 for (;;) {
3031 struct isl_obj o;
3032 o = obj_read_body(s, isl_map_copy(map), v);
3033 if (!obj.v)
3034 obj = o;
3035 else
3036 obj = obj_add(s, obj, o);
3037 if (obj.type == isl_obj_none || !obj.v)
3038 return obj;
3039 if (!isl_stream_eat_if_available(s, ';'))
3040 break;
3041 if (isl_stream_next_token_is(s, '}'))
3042 break;
3045 return obj;
3048 static struct isl_obj obj_read(__isl_keep isl_stream *s)
3050 isl_map *map = NULL;
3051 struct isl_token *tok;
3052 struct vars *v = NULL;
3053 struct isl_obj obj = { isl_obj_set, NULL };
3055 if (next_is_schedule(s))
3056 return schedule_read(s);
3058 tok = next_token(s);
3059 if (!tok) {
3060 isl_stream_error(s, NULL, "unexpected EOF");
3061 goto error;
3063 if (tok->type == ISL_TOKEN_VALUE) {
3064 struct isl_token *tok2;
3065 struct isl_map *map;
3067 tok2 = isl_stream_next_token(s);
3068 if (!tok2 || tok2->type != ISL_TOKEN_VALUE ||
3069 isl_int_is_neg(tok2->u.v)) {
3070 if (tok2)
3071 isl_stream_push_token(s, tok2);
3072 obj.type = isl_obj_val;
3073 obj.v = isl_val_int_from_isl_int(s->ctx, tok->u.v);
3074 isl_token_free(tok);
3075 return obj;
3077 isl_stream_push_token(s, tok2);
3078 isl_stream_push_token(s, tok);
3079 map = map_read_polylib(s);
3080 if (!map)
3081 goto error;
3082 if (isl_map_may_be_set(map))
3083 obj.v = isl_map_range(map);
3084 else {
3085 obj.type = isl_obj_map;
3086 obj.v = map;
3088 return obj;
3090 v = vars_new(s->ctx);
3091 if (!v) {
3092 isl_stream_push_token(s, tok);
3093 goto error;
3095 map = isl_map_universe(isl_space_params_alloc(s->ctx, 0));
3096 if (tok->type == '[') {
3097 isl_stream_push_token(s, tok);
3098 map = read_map_tuple(s, map, isl_dim_param, v, 0, 0);
3099 if (!map)
3100 goto error;
3101 tok = isl_stream_next_token(s);
3102 if (!tok || tok->type != ISL_TOKEN_TO) {
3103 isl_stream_error(s, tok, "expecting '->'");
3104 if (tok)
3105 isl_stream_push_token(s, tok);
3106 goto error;
3108 isl_token_free(tok);
3109 tok = isl_stream_next_token(s);
3111 if (!tok || tok->type != '{') {
3112 isl_stream_error(s, tok, "expecting '{'");
3113 if (tok)
3114 isl_stream_push_token(s, tok);
3115 goto error;
3117 isl_token_free(tok);
3119 tok = isl_stream_next_token(s);
3120 if (!tok)
3122 else if (tok->type == ISL_TOKEN_IDENT && !strcmp(tok->u.s, "Sym")) {
3123 isl_token_free(tok);
3124 if (isl_stream_eat(s, '='))
3125 goto error;
3126 map = read_map_tuple(s, map, isl_dim_param, v, 0, 1);
3127 if (!map)
3128 goto error;
3129 } else
3130 isl_stream_push_token(s, tok);
3132 obj = obj_read_disjuncts(s, v, map);
3133 if (obj.type == isl_obj_none || !obj.v)
3134 goto error;
3136 tok = isl_stream_next_token(s);
3137 if (tok && tok->type == '}') {
3138 isl_token_free(tok);
3139 } else {
3140 isl_stream_error(s, tok, "unexpected isl_token");
3141 if (tok)
3142 isl_token_free(tok);
3143 goto error;
3146 vars_free(v);
3147 isl_map_free(map);
3149 return obj;
3150 error:
3151 isl_map_free(map);
3152 obj.type->free(obj.v);
3153 if (v)
3154 vars_free(v);
3155 obj.v = NULL;
3156 return obj;
3159 struct isl_obj isl_stream_read_obj(__isl_keep isl_stream *s)
3161 return obj_read(s);
3164 __isl_give isl_map *isl_stream_read_map(__isl_keep isl_stream *s)
3166 struct isl_obj obj;
3168 obj = obj_read(s);
3169 if (obj.v)
3170 isl_assert(s->ctx, obj.type == isl_obj_map ||
3171 obj.type == isl_obj_set, goto error);
3173 if (obj.type == isl_obj_set)
3174 obj.v = isl_map_from_range(obj.v);
3176 return obj.v;
3177 error:
3178 obj.type->free(obj.v);
3179 return NULL;
3182 __isl_give isl_set *isl_stream_read_set(__isl_keep isl_stream *s)
3184 struct isl_obj obj;
3186 obj = obj_read(s);
3187 if (obj.v) {
3188 if (obj.type == isl_obj_map && isl_map_may_be_set(obj.v)) {
3189 obj.v = isl_map_range(obj.v);
3190 obj.type = isl_obj_set;
3192 isl_assert(s->ctx, obj.type == isl_obj_set, goto error);
3195 return obj.v;
3196 error:
3197 obj.type->free(obj.v);
3198 return NULL;
3201 __isl_give isl_union_map *isl_stream_read_union_map(__isl_keep isl_stream *s)
3203 struct isl_obj obj;
3205 obj = obj_read(s);
3206 if (obj.type == isl_obj_map) {
3207 obj.type = isl_obj_union_map;
3208 obj.v = isl_union_map_from_map(obj.v);
3210 if (obj.type == isl_obj_set) {
3211 obj.type = isl_obj_union_set;
3212 obj.v = isl_union_set_from_set(obj.v);
3214 if (obj.v && obj.type == isl_obj_union_set &&
3215 isl_union_set_is_empty(obj.v))
3216 obj.type = isl_obj_union_map;
3217 if (obj.v && obj.type != isl_obj_union_map)
3218 isl_die(s->ctx, isl_error_invalid, "invalid input", goto error);
3220 return obj.v;
3221 error:
3222 obj.type->free(obj.v);
3223 return NULL;
3226 /* Extract an isl_union_set from "obj".
3227 * This only works if the object was detected as either a set
3228 * (in which case it is converted to a union set) or a union set.
3230 static __isl_give isl_union_set *extract_union_set(isl_ctx *ctx,
3231 struct isl_obj obj)
3233 if (obj.type == isl_obj_set) {
3234 obj.type = isl_obj_union_set;
3235 obj.v = isl_union_set_from_set(obj.v);
3237 if (obj.v)
3238 isl_assert(ctx, obj.type == isl_obj_union_set, goto error);
3240 return obj.v;
3241 error:
3242 obj.type->free(obj.v);
3243 return NULL;
3246 /* Read an isl_union_set from "s".
3247 * First read a generic object and then try and extract
3248 * an isl_union_set from that.
3250 __isl_give isl_union_set *isl_stream_read_union_set(__isl_keep isl_stream *s)
3252 struct isl_obj obj;
3254 obj = obj_read(s);
3255 return extract_union_set(s->ctx, obj);
3258 static __isl_give isl_basic_map *basic_map_read(__isl_keep isl_stream *s)
3260 struct isl_obj obj;
3261 struct isl_map *map;
3262 struct isl_basic_map *bmap;
3264 obj = obj_read(s);
3265 if (obj.v && (obj.type != isl_obj_map && obj.type != isl_obj_set))
3266 isl_die(s->ctx, isl_error_invalid, "not a (basic) set or map",
3267 goto error);
3268 map = obj.v;
3269 if (!map)
3270 return NULL;
3272 if (map->n > 1)
3273 isl_die(s->ctx, isl_error_invalid,
3274 "set or map description involves "
3275 "more than one disjunct", goto error);
3277 if (map->n == 0)
3278 bmap = isl_basic_map_empty(isl_map_get_space(map));
3279 else
3280 bmap = isl_basic_map_copy(map->p[0]);
3282 isl_map_free(map);
3284 return bmap;
3285 error:
3286 obj.type->free(obj.v);
3287 return NULL;
3290 static __isl_give isl_basic_set *basic_set_read(__isl_keep isl_stream *s)
3292 isl_basic_map *bmap;
3293 bmap = basic_map_read(s);
3294 if (!bmap)
3295 return NULL;
3296 if (!isl_basic_map_may_be_set(bmap))
3297 isl_die(s->ctx, isl_error_invalid,
3298 "input is not a set", goto error);
3299 return isl_basic_map_range(bmap);
3300 error:
3301 isl_basic_map_free(bmap);
3302 return NULL;
3305 __isl_give isl_basic_map *isl_basic_map_read_from_file(isl_ctx *ctx,
3306 FILE *input)
3308 struct isl_basic_map *bmap;
3309 isl_stream *s = isl_stream_new_file(ctx, input);
3310 if (!s)
3311 return NULL;
3312 bmap = basic_map_read(s);
3313 isl_stream_free(s);
3314 return bmap;
3317 __isl_give isl_basic_set *isl_basic_set_read_from_file(isl_ctx *ctx,
3318 FILE *input)
3320 isl_basic_set *bset;
3321 isl_stream *s = isl_stream_new_file(ctx, input);
3322 if (!s)
3323 return NULL;
3324 bset = basic_set_read(s);
3325 isl_stream_free(s);
3326 return bset;
3329 __isl_give isl_basic_map *isl_basic_map_read_from_str(isl_ctx *ctx,
3330 const char *str)
3332 struct isl_basic_map *bmap;
3333 isl_stream *s = isl_stream_new_str(ctx, str);
3334 if (!s)
3335 return NULL;
3336 bmap = basic_map_read(s);
3337 isl_stream_free(s);
3338 return bmap;
3341 __isl_give isl_basic_set *isl_basic_set_read_from_str(isl_ctx *ctx,
3342 const char *str)
3344 isl_basic_set *bset;
3345 isl_stream *s = isl_stream_new_str(ctx, str);
3346 if (!s)
3347 return NULL;
3348 bset = basic_set_read(s);
3349 isl_stream_free(s);
3350 return bset;
3353 __isl_give isl_map *isl_map_read_from_file(struct isl_ctx *ctx,
3354 FILE *input)
3356 struct isl_map *map;
3357 isl_stream *s = isl_stream_new_file(ctx, input);
3358 if (!s)
3359 return NULL;
3360 map = isl_stream_read_map(s);
3361 isl_stream_free(s);
3362 return map;
3365 __isl_give isl_map *isl_map_read_from_str(struct isl_ctx *ctx,
3366 const char *str)
3368 struct isl_map *map;
3369 isl_stream *s = isl_stream_new_str(ctx, str);
3370 if (!s)
3371 return NULL;
3372 map = isl_stream_read_map(s);
3373 isl_stream_free(s);
3374 return map;
3377 __isl_give isl_set *isl_set_read_from_file(struct isl_ctx *ctx,
3378 FILE *input)
3380 isl_set *set;
3381 isl_stream *s = isl_stream_new_file(ctx, input);
3382 if (!s)
3383 return NULL;
3384 set = isl_stream_read_set(s);
3385 isl_stream_free(s);
3386 return set;
3389 __isl_give isl_set *isl_set_read_from_str(isl_ctx *ctx, const char *str)
3391 isl_set *set;
3392 isl_stream *s = isl_stream_new_str(ctx, str);
3393 if (!s)
3394 return NULL;
3395 set = isl_stream_read_set(s);
3396 isl_stream_free(s);
3397 return set;
3400 __isl_give isl_union_map *isl_union_map_read_from_file(isl_ctx *ctx,
3401 FILE *input)
3403 isl_union_map *umap;
3404 isl_stream *s = isl_stream_new_file(ctx, input);
3405 if (!s)
3406 return NULL;
3407 umap = isl_stream_read_union_map(s);
3408 isl_stream_free(s);
3409 return umap;
3412 __isl_give isl_union_map *isl_union_map_read_from_str(struct isl_ctx *ctx,
3413 const char *str)
3415 isl_union_map *umap;
3416 isl_stream *s = isl_stream_new_str(ctx, str);
3417 if (!s)
3418 return NULL;
3419 umap = isl_stream_read_union_map(s);
3420 isl_stream_free(s);
3421 return umap;
3424 __isl_give isl_union_set *isl_union_set_read_from_file(isl_ctx *ctx,
3425 FILE *input)
3427 isl_union_set *uset;
3428 isl_stream *s = isl_stream_new_file(ctx, input);
3429 if (!s)
3430 return NULL;
3431 uset = isl_stream_read_union_set(s);
3432 isl_stream_free(s);
3433 return uset;
3436 __isl_give isl_union_set *isl_union_set_read_from_str(struct isl_ctx *ctx,
3437 const char *str)
3439 isl_union_set *uset;
3440 isl_stream *s = isl_stream_new_str(ctx, str);
3441 if (!s)
3442 return NULL;
3443 uset = isl_stream_read_union_set(s);
3444 isl_stream_free(s);
3445 return uset;
3448 static __isl_give isl_vec *isl_vec_read_polylib(__isl_keep isl_stream *s)
3450 struct isl_vec *vec = NULL;
3451 struct isl_token *tok;
3452 unsigned size;
3453 int j;
3455 tok = isl_stream_next_token(s);
3456 if (!tok || tok->type != ISL_TOKEN_VALUE) {
3457 isl_stream_error(s, tok, "expecting vector length");
3458 goto error;
3461 size = isl_int_get_si(tok->u.v);
3462 isl_token_free(tok);
3464 vec = isl_vec_alloc(s->ctx, size);
3466 for (j = 0; j < size; ++j) {
3467 tok = isl_stream_next_token(s);
3468 if (!tok || tok->type != ISL_TOKEN_VALUE) {
3469 isl_stream_error(s, tok, "expecting constant value");
3470 goto error;
3472 isl_int_set(vec->el[j], tok->u.v);
3473 isl_token_free(tok);
3476 return vec;
3477 error:
3478 isl_token_free(tok);
3479 isl_vec_free(vec);
3480 return NULL;
3483 static __isl_give isl_vec *vec_read(__isl_keep isl_stream *s)
3485 return isl_vec_read_polylib(s);
3488 __isl_give isl_vec *isl_vec_read_from_file(isl_ctx *ctx, FILE *input)
3490 isl_vec *v;
3491 isl_stream *s = isl_stream_new_file(ctx, input);
3492 if (!s)
3493 return NULL;
3494 v = vec_read(s);
3495 isl_stream_free(s);
3496 return v;
3499 __isl_give isl_pw_qpolynomial *isl_stream_read_pw_qpolynomial(
3500 __isl_keep isl_stream *s)
3502 struct isl_obj obj;
3504 obj = obj_read(s);
3505 if (obj.v)
3506 isl_assert(s->ctx, obj.type == isl_obj_pw_qpolynomial,
3507 goto error);
3509 return obj.v;
3510 error:
3511 obj.type->free(obj.v);
3512 return NULL;
3515 __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_str(isl_ctx *ctx,
3516 const char *str)
3518 isl_pw_qpolynomial *pwqp;
3519 isl_stream *s = isl_stream_new_str(ctx, str);
3520 if (!s)
3521 return NULL;
3522 pwqp = isl_stream_read_pw_qpolynomial(s);
3523 isl_stream_free(s);
3524 return pwqp;
3527 __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_file(isl_ctx *ctx,
3528 FILE *input)
3530 isl_pw_qpolynomial *pwqp;
3531 isl_stream *s = isl_stream_new_file(ctx, input);
3532 if (!s)
3533 return NULL;
3534 pwqp = isl_stream_read_pw_qpolynomial(s);
3535 isl_stream_free(s);
3536 return pwqp;
3539 /* Read an isl_pw_qpolynomial_fold from "s".
3540 * First read a generic object and
3541 * then check that it is an isl_pw_qpolynomial_fold.
3543 __isl_give isl_pw_qpolynomial_fold *isl_stream_read_pw_qpolynomial_fold(
3544 __isl_keep isl_stream *s)
3546 struct isl_obj obj;
3548 obj = obj_read(s);
3549 if (obj.v && obj.type != isl_obj_pw_qpolynomial_fold)
3550 isl_die(s->ctx, isl_error_invalid, "invalid input", goto error);
3552 return obj.v;
3553 error:
3554 obj.type->free(obj.v);
3555 return NULL;
3558 /* Read an isl_pw_qpolynomial_fold from "str".
3560 __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_read_from_str(
3561 isl_ctx *ctx, const char *str)
3563 isl_pw_qpolynomial_fold *pwqp;
3564 isl_stream *s;
3566 s = isl_stream_new_str(ctx, str);
3567 if (!s)
3568 return NULL;
3569 pwqp = isl_stream_read_pw_qpolynomial_fold(s);
3570 isl_stream_free(s);
3572 return pwqp;
3575 /* Is the next token an identifier not in "v"?
3577 static int next_is_fresh_ident(__isl_keep isl_stream *s, struct vars *v)
3579 int n = v->n;
3580 int fresh;
3581 struct isl_token *tok;
3583 tok = isl_stream_next_token(s);
3584 if (!tok)
3585 return 0;
3586 fresh = tok->type == ISL_TOKEN_IDENT && vars_pos(v, tok->u.s, -1) >= n;
3587 isl_stream_push_token(s, tok);
3589 vars_drop(v, v->n - n);
3591 return fresh;
3594 /* First read the domain of the affine expression, which may be
3595 * a parameter space or a set.
3596 * The tricky part is that we don't know if the domain is a set or not,
3597 * so when we are trying to read the domain, we may actually be reading
3598 * the affine expression itself (defined on a parameter domains)
3599 * If the tuple we are reading is named, we assume it's the domain.
3600 * Also, if inside the tuple, the first thing we find is a nested tuple
3601 * or a new identifier, we again assume it's the domain.
3602 * Finally, if the tuple is empty, then it must be the domain
3603 * since it does not contain an affine expression.
3604 * Otherwise, we assume we are reading an affine expression.
3606 static __isl_give isl_set *read_aff_domain(__isl_keep isl_stream *s,
3607 __isl_take isl_set *dom, struct vars *v)
3609 struct isl_token *tok, *tok2;
3610 int is_empty;
3612 tok = isl_stream_next_token(s);
3613 if (tok && (tok->type == ISL_TOKEN_IDENT || tok->is_keyword)) {
3614 isl_stream_push_token(s, tok);
3615 return read_map_tuple(s, dom, isl_dim_set, v, 0, 0);
3617 if (!tok || tok->type != '[') {
3618 isl_stream_error(s, tok, "expecting '['");
3619 goto error;
3621 tok2 = isl_stream_next_token(s);
3622 is_empty = tok2 && tok2->type == ']';
3623 if (tok2)
3624 isl_stream_push_token(s, tok2);
3625 if (is_empty || next_is_tuple(s) || next_is_fresh_ident(s, v)) {
3626 isl_stream_push_token(s, tok);
3627 dom = read_map_tuple(s, dom, isl_dim_set, v, 0, 0);
3628 } else
3629 isl_stream_push_token(s, tok);
3631 return dom;
3632 error:
3633 if (tok)
3634 isl_stream_push_token(s, tok);
3635 isl_set_free(dom);
3636 return NULL;
3639 /* Read an affine expression from "s".
3641 __isl_give isl_aff *isl_stream_read_aff(__isl_keep isl_stream *s)
3643 isl_aff *aff;
3644 isl_multi_aff *ma;
3645 isl_size dim;
3647 ma = isl_stream_read_multi_aff(s);
3648 dim = isl_multi_aff_dim(ma, isl_dim_out);
3649 if (dim < 0)
3650 goto error;
3651 if (dim != 1)
3652 isl_die(s->ctx, isl_error_invalid,
3653 "expecting single affine expression",
3654 goto error);
3656 aff = isl_multi_aff_get_aff(ma, 0);
3657 isl_multi_aff_free(ma);
3658 return aff;
3659 error:
3660 isl_multi_aff_free(ma);
3661 return NULL;
3664 /* Read a piecewise affine expression from "s" with domain (space) "dom".
3666 static __isl_give isl_pw_aff *read_pw_aff_with_dom(__isl_keep isl_stream *s,
3667 __isl_take isl_set *dom, struct vars *v)
3669 isl_pw_aff *pwaff = NULL;
3671 if (!isl_set_is_params(dom) && isl_stream_eat(s, ISL_TOKEN_TO))
3672 goto error;
3674 if (isl_stream_eat(s, '['))
3675 goto error;
3677 pwaff = accept_affine(s, isl_set_get_space(dom), v);
3679 if (isl_stream_eat(s, ']'))
3680 goto error;
3682 dom = read_optional_formula(s, dom, v, 0);
3683 pwaff = isl_pw_aff_intersect_domain(pwaff, dom);
3685 return pwaff;
3686 error:
3687 isl_set_free(dom);
3688 isl_pw_aff_free(pwaff);
3689 return NULL;
3692 __isl_give isl_pw_aff *isl_stream_read_pw_aff(__isl_keep isl_stream *s)
3694 struct vars *v;
3695 isl_set *dom = NULL;
3696 isl_set *aff_dom;
3697 isl_pw_aff *pa = NULL;
3698 int n;
3700 v = vars_new(s->ctx);
3701 if (!v)
3702 return NULL;
3704 dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
3705 if (next_is_tuple(s)) {
3706 dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
3707 if (isl_stream_eat(s, ISL_TOKEN_TO))
3708 goto error;
3710 if (isl_stream_eat(s, '{'))
3711 goto error;
3713 n = v->n;
3714 aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
3715 pa = read_pw_aff_with_dom(s, aff_dom, v);
3716 vars_drop(v, v->n - n);
3718 while (isl_stream_eat_if_available(s, ';')) {
3719 isl_pw_aff *pa_i;
3721 n = v->n;
3722 aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
3723 pa_i = read_pw_aff_with_dom(s, aff_dom, v);
3724 vars_drop(v, v->n - n);
3726 pa = isl_pw_aff_union_add(pa, pa_i);
3729 if (isl_stream_eat(s, '}'))
3730 goto error;
3732 vars_free(v);
3733 isl_set_free(dom);
3734 return pa;
3735 error:
3736 vars_free(v);
3737 isl_set_free(dom);
3738 isl_pw_aff_free(pa);
3739 return NULL;
3742 __isl_give isl_aff *isl_aff_read_from_str(isl_ctx *ctx, const char *str)
3744 isl_aff *aff;
3745 isl_stream *s = isl_stream_new_str(ctx, str);
3746 if (!s)
3747 return NULL;
3748 aff = isl_stream_read_aff(s);
3749 isl_stream_free(s);
3750 return aff;
3753 __isl_give isl_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str)
3755 isl_pw_aff *pa;
3756 isl_stream *s = isl_stream_new_str(ctx, str);
3757 if (!s)
3758 return NULL;
3759 pa = isl_stream_read_pw_aff(s);
3760 isl_stream_free(s);
3761 return pa;
3764 /* Extract an isl_multi_pw_aff with domain space "dom_space"
3765 * from a tuple "tuple" read by read_tuple.
3767 * Note that the function read_tuple accepts tuples where some output or
3768 * set dimensions are defined in terms of other output or set dimensions
3769 * since this function is also used to read maps. As a special case,
3770 * read_tuple also accepts dimensions that are defined in terms of themselves
3771 * (i.e., that are not defined).
3772 * These cases are not allowed when extracting an isl_multi_pw_aff so check
3773 * that the definitions of the output/set dimensions do not involve any
3774 * output/set dimensions.
3775 * Finally, drop the output dimensions from the domain of the result
3776 * of read_tuple (which is of the form [input, output] -> [output],
3777 * with anonymous domain) and reset the space.
3779 static __isl_give isl_multi_pw_aff *extract_mpa_from_tuple(
3780 __isl_take isl_space *dom_space, __isl_keep isl_multi_pw_aff *tuple)
3782 int i;
3783 isl_size dim, n;
3784 isl_space *space;
3785 isl_multi_pw_aff *mpa;
3787 n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
3788 dim = isl_space_dim(dom_space, isl_dim_all);
3789 if (n < 0 || dim < 0)
3790 dom_space = isl_space_free(dom_space);
3791 space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
3792 space = isl_space_align_params(space, isl_space_copy(dom_space));
3793 if (!isl_space_is_params(dom_space))
3794 space = isl_space_map_from_domain_and_range(
3795 isl_space_copy(dom_space), space);
3796 isl_space_free(dom_space);
3797 mpa = isl_multi_pw_aff_alloc(space);
3799 for (i = 0; i < n; ++i) {
3800 isl_pw_aff *pa;
3801 pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
3802 if (!pa)
3803 return isl_multi_pw_aff_free(mpa);
3804 if (isl_pw_aff_involves_dims(pa, isl_dim_in, dim, i + 1)) {
3805 isl_ctx *ctx = isl_pw_aff_get_ctx(pa);
3806 isl_pw_aff_free(pa);
3807 isl_die(ctx, isl_error_invalid,
3808 "not an affine expression",
3809 return isl_multi_pw_aff_free(mpa));
3811 pa = isl_pw_aff_drop_dims(pa, isl_dim_in, dim, n);
3812 space = isl_multi_pw_aff_get_domain_space(mpa);
3813 pa = isl_pw_aff_reset_domain_space(pa, space);
3814 mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa);
3817 return mpa;
3820 /* Read a tuple of affine expressions, together with optional constraints
3821 * on the domain from "s". "dom" represents the initial constraints
3822 * on the domain.
3824 * The isl_multi_aff may live in either a set or a map space.
3825 * First read the first tuple and check if it is followed by a "->".
3826 * If so, convert the tuple into the domain of the isl_multi_pw_aff and
3827 * read in the next tuple. This tuple (or the first tuple if it was
3828 * not followed by a "->") is then converted into an isl_multi_pw_aff
3829 * through a call to extract_mpa_from_tuple.
3830 * The result is converted to an isl_pw_multi_aff and
3831 * its domain is intersected with the domain.
3833 * Note that the last tuple may introduce new identifiers,
3834 * but these cannot be referenced in the description of the domain.
3836 static __isl_give isl_pw_multi_aff *read_conditional_multi_aff(
3837 __isl_keep isl_stream *s, __isl_take isl_set *dom, struct vars *v)
3839 isl_multi_pw_aff *tuple;
3840 isl_multi_pw_aff *mpa;
3841 isl_pw_multi_aff *pma;
3842 int n = v->n;
3843 int n_dom;
3845 n_dom = v->n;
3846 tuple = read_tuple(s, v, 0, 0);
3847 if (!tuple)
3848 goto error;
3849 if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
3850 isl_map *map = map_from_tuple(tuple, dom, isl_dim_in, v, 0);
3851 dom = isl_map_domain(map);
3852 n_dom = v->n;
3853 tuple = read_tuple(s, v, 0, 0);
3854 if (!tuple)
3855 goto error;
3857 mpa = extract_mpa_from_tuple(isl_set_get_space(dom), tuple);
3858 isl_multi_pw_aff_free(tuple);
3859 if (!mpa)
3860 dom = isl_set_free(dom);
3862 vars_drop(v, v->n - n_dom);
3863 dom = read_optional_formula(s, dom, v, 0);
3865 vars_drop(v, v->n - n);
3867 pma = isl_pw_multi_aff_from_multi_pw_aff(mpa);
3868 pma = isl_pw_multi_aff_intersect_domain(pma, dom);
3870 return pma;
3871 error:
3872 isl_set_free(dom);
3873 return NULL;
3876 /* Read an isl_union_pw_multi_aff from "s".
3878 * In particular, first read the parameters and then read a sequence
3879 * of zero or more tuples of affine expressions with optional conditions and
3880 * add them up.
3882 __isl_give isl_union_pw_multi_aff *isl_stream_read_union_pw_multi_aff(
3883 __isl_keep isl_stream *s)
3885 struct vars *v;
3886 isl_set *dom;
3887 isl_union_pw_multi_aff *upma = NULL;
3889 v = vars_new(s->ctx);
3890 if (!v)
3891 return NULL;
3893 dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
3894 if (next_is_tuple(s)) {
3895 dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
3896 if (isl_stream_eat(s, ISL_TOKEN_TO))
3897 goto error;
3899 if (isl_stream_eat(s, '{'))
3900 goto error;
3902 upma = isl_union_pw_multi_aff_empty(isl_set_get_space(dom));
3904 do {
3905 isl_pw_multi_aff *pma;
3906 isl_union_pw_multi_aff *upma2;
3908 if (isl_stream_next_token_is(s, '}'))
3909 break;
3911 pma = read_conditional_multi_aff(s, isl_set_copy(dom), v);
3912 upma2 = isl_union_pw_multi_aff_from_pw_multi_aff(pma);
3913 upma = isl_union_pw_multi_aff_union_add(upma, upma2);
3914 if (!upma)
3915 goto error;
3916 } while (isl_stream_eat_if_available(s, ';'));
3918 if (isl_stream_eat(s, '}'))
3919 goto error;
3921 isl_set_free(dom);
3922 vars_free(v);
3923 return upma;
3924 error:
3925 isl_union_pw_multi_aff_free(upma);
3926 isl_set_free(dom);
3927 vars_free(v);
3928 return NULL;
3931 /* Read an isl_pw_multi_aff from "s".
3933 * Read a more generic isl_union_pw_multi_aff first and
3934 * then check that the result lives in a single space.
3936 __isl_give isl_pw_multi_aff *isl_stream_read_pw_multi_aff(
3937 __isl_keep isl_stream *s)
3939 isl_bool single_space;
3940 isl_union_pw_multi_aff *upma;
3942 upma = isl_stream_read_union_pw_multi_aff(s);
3943 single_space = isl_union_pw_multi_aff_isa_pw_multi_aff(upma);
3944 if (single_space < 0)
3945 upma = isl_union_pw_multi_aff_free(upma);
3946 else if (!single_space)
3947 isl_die(s->ctx, isl_error_invalid,
3948 "expecting expression in single space",
3949 upma = isl_union_pw_multi_aff_free(upma));
3950 return isl_union_pw_multi_aff_as_pw_multi_aff(upma);
3953 __isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(isl_ctx *ctx,
3954 const char *str)
3956 isl_pw_multi_aff *pma;
3957 isl_stream *s = isl_stream_new_str(ctx, str);
3958 if (!s)
3959 return NULL;
3960 pma = isl_stream_read_pw_multi_aff(s);
3961 isl_stream_free(s);
3962 return pma;
3965 /* Read an isl_union_pw_multi_aff from "str".
3967 __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_read_from_str(
3968 isl_ctx *ctx, const char *str)
3970 isl_union_pw_multi_aff *upma;
3971 isl_stream *s = isl_stream_new_str(ctx, str);
3972 if (!s)
3973 return NULL;
3974 upma = isl_stream_read_union_pw_multi_aff(s);
3975 isl_stream_free(s);
3976 return upma;
3979 /* Assuming "pa" represents a single affine expression defined on a universe
3980 * domain, extract this affine expression.
3982 static __isl_give isl_aff *aff_from_pw_aff(__isl_take isl_pw_aff *pa)
3984 isl_aff *aff;
3986 if (!pa)
3987 return NULL;
3988 if (pa->n != 1)
3989 isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
3990 "expecting single affine expression",
3991 goto error);
3992 if (!isl_set_plain_is_universe(pa->p[0].set))
3993 isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
3994 "expecting universe domain",
3995 goto error);
3997 aff = isl_aff_copy(pa->p[0].aff);
3998 isl_pw_aff_free(pa);
3999 return aff;
4000 error:
4001 isl_pw_aff_free(pa);
4002 return NULL;
4005 #undef BASE
4006 #define BASE val
4008 #include <isl_multi_read_no_explicit_domain_templ.c>
4010 #undef BASE
4011 #define BASE id
4013 #include <isl_multi_read_no_explicit_domain_templ.c>
4015 /* Read a multi-affine expression from "s".
4016 * If the multi-affine expression has a domain, then the tuple
4017 * representing this domain cannot involve any affine expressions.
4018 * The tuple representing the actual expressions needs to consist
4019 * of only affine expressions. Moreover, these expressions can
4020 * only depend on parameters and input dimensions and not on other
4021 * output dimensions.
4023 __isl_give isl_multi_aff *isl_stream_read_multi_aff(__isl_keep isl_stream *s)
4025 struct vars *v;
4026 isl_set *dom = NULL;
4027 isl_multi_pw_aff *tuple = NULL;
4028 int i;
4029 isl_size dim, n;
4030 isl_space *space, *dom_space;
4031 isl_multi_aff *ma = NULL;
4033 v = vars_new(s->ctx);
4034 if (!v)
4035 return NULL;
4037 dom = read_universe_params(s, v);
4038 if (!dom)
4039 goto error;
4040 if (isl_stream_eat(s, '{'))
4041 goto error;
4043 tuple = read_tuple(s, v, 0, 0);
4044 if (!tuple)
4045 goto error;
4046 if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
4047 isl_set *set;
4048 isl_space *space;
4049 isl_bool has_expr;
4051 has_expr = tuple_has_expr(tuple);
4052 if (has_expr < 0)
4053 goto error;
4054 if (has_expr)
4055 isl_die(s->ctx, isl_error_invalid,
4056 "expecting universe domain", goto error);
4057 space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
4058 set = isl_set_universe(space);
4059 dom = isl_set_intersect_params(set, dom);
4060 isl_multi_pw_aff_free(tuple);
4061 tuple = read_tuple(s, v, 0, 0);
4062 if (!tuple)
4063 goto error;
4066 if (isl_stream_eat(s, '}'))
4067 goto error;
4069 n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
4070 dim = isl_set_dim(dom, isl_dim_all);
4071 if (n < 0 || dim < 0)
4072 goto error;
4073 dom_space = isl_set_get_space(dom);
4074 space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
4075 space = isl_space_align_params(space, isl_space_copy(dom_space));
4076 if (!isl_space_is_params(dom_space))
4077 space = isl_space_map_from_domain_and_range(
4078 isl_space_copy(dom_space), space);
4079 isl_space_free(dom_space);
4080 ma = isl_multi_aff_alloc(space);
4082 for (i = 0; i < n; ++i) {
4083 isl_pw_aff *pa;
4084 isl_aff *aff;
4085 pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
4086 aff = aff_from_pw_aff(pa);
4087 if (!aff)
4088 goto error;
4089 if (isl_aff_involves_dims(aff, isl_dim_in, dim, i + 1)) {
4090 isl_aff_free(aff);
4091 isl_die(s->ctx, isl_error_invalid,
4092 "not an affine expression", goto error);
4094 aff = isl_aff_drop_dims(aff, isl_dim_in, dim, n);
4095 space = isl_multi_aff_get_domain_space(ma);
4096 aff = isl_aff_reset_domain_space(aff, space);
4097 ma = isl_multi_aff_set_aff(ma, i, aff);
4100 isl_multi_pw_aff_free(tuple);
4101 vars_free(v);
4102 isl_set_free(dom);
4103 return ma;
4104 error:
4105 isl_multi_pw_aff_free(tuple);
4106 vars_free(v);
4107 isl_set_free(dom);
4108 isl_multi_aff_free(ma);
4109 return NULL;
4112 __isl_give isl_multi_aff *isl_multi_aff_read_from_str(isl_ctx *ctx,
4113 const char *str)
4115 isl_multi_aff *maff;
4116 isl_stream *s = isl_stream_new_str(ctx, str);
4117 if (!s)
4118 return NULL;
4119 maff = isl_stream_read_multi_aff(s);
4120 isl_stream_free(s);
4121 return maff;
4124 /* Read an isl_multi_pw_aff from "s".
4126 * The input format is similar to that of map, except that any conditions
4127 * on the domains should be specified inside the tuple since each
4128 * piecewise affine expression may have a different domain.
4129 * However, additional, shared conditions can also be specified.
4130 * This is especially useful for setting the explicit domain
4131 * of a zero-dimensional isl_multi_pw_aff.
4133 * Since we do not know in advance if the isl_multi_pw_aff lives
4134 * in a set or a map space, we first read the first tuple and check
4135 * if it is followed by a "->". If so, we convert the tuple into
4136 * the domain of the isl_multi_pw_aff and read in the next tuple.
4137 * This tuple (or the first tuple if it was not followed by a "->")
4138 * is then converted into the isl_multi_pw_aff through a call
4139 * to extract_mpa_from_tuple and the domain of the result
4140 * is intersected with the domain.
4142 * Note that the last tuple may introduce new identifiers,
4143 * but these cannot be referenced in the description of the domain.
4145 __isl_give isl_multi_pw_aff *isl_stream_read_multi_pw_aff(
4146 __isl_keep isl_stream *s)
4148 int n_dom;
4149 struct vars *v;
4150 isl_set *dom = NULL;
4151 isl_multi_pw_aff *tuple = NULL;
4152 isl_multi_pw_aff *mpa = NULL;
4154 v = vars_new(s->ctx);
4155 if (!v)
4156 return NULL;
4158 dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
4159 if (next_is_tuple(s)) {
4160 dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
4161 if (isl_stream_eat(s, ISL_TOKEN_TO))
4162 goto error;
4164 if (isl_stream_eat(s, '{'))
4165 goto error;
4167 n_dom = v->n;
4168 tuple = read_tuple(s, v, 0, 0);
4169 if (!tuple)
4170 goto error;
4171 if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
4172 isl_map *map = map_from_tuple(tuple, dom, isl_dim_in, v, 0);
4173 dom = isl_map_domain(map);
4174 n_dom = v->n;
4175 tuple = read_tuple(s, v, 0, 0);
4176 if (!tuple)
4177 goto error;
4180 vars_drop(v, v->n - n_dom);
4181 if (isl_stream_eat_if_available(s, ':'))
4182 dom = read_formula(s, v, dom, 0);
4184 if (isl_stream_eat(s, '}'))
4185 goto error;
4187 mpa = extract_mpa_from_tuple(isl_set_get_space(dom), tuple);
4189 isl_multi_pw_aff_free(tuple);
4190 vars_free(v);
4191 mpa = isl_multi_pw_aff_intersect_domain(mpa, dom);
4192 return mpa;
4193 error:
4194 isl_multi_pw_aff_free(tuple);
4195 vars_free(v);
4196 isl_set_free(dom);
4197 isl_multi_pw_aff_free(mpa);
4198 return NULL;
4201 /* Read an isl_multi_pw_aff from "str".
4203 __isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(isl_ctx *ctx,
4204 const char *str)
4206 isl_multi_pw_aff *mpa;
4207 isl_stream *s = isl_stream_new_str(ctx, str);
4208 if (!s)
4209 return NULL;
4210 mpa = isl_stream_read_multi_pw_aff(s);
4211 isl_stream_free(s);
4212 return mpa;
4215 /* Read the body of an isl_union_pw_aff from "s" with parameter domain "dom".
4217 static __isl_give isl_union_pw_aff *read_union_pw_aff_with_dom(
4218 __isl_keep isl_stream *s, __isl_take isl_set *dom, struct vars *v)
4220 isl_pw_aff *pa;
4221 isl_union_pw_aff *upa = NULL;
4222 isl_set *aff_dom;
4223 int n;
4225 n = v->n;
4226 aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
4227 pa = read_pw_aff_with_dom(s, aff_dom, v);
4228 vars_drop(v, v->n - n);
4230 upa = isl_union_pw_aff_from_pw_aff(pa);
4232 while (isl_stream_eat_if_available(s, ';')) {
4233 isl_pw_aff *pa_i;
4234 isl_union_pw_aff *upa_i;
4236 n = v->n;
4237 aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
4238 pa_i = read_pw_aff_with_dom(s, aff_dom, v);
4239 vars_drop(v, v->n - n);
4241 upa_i = isl_union_pw_aff_from_pw_aff(pa_i);
4242 upa = isl_union_pw_aff_union_add(upa, upa_i);
4245 isl_set_free(dom);
4246 return upa;
4249 /* Read an isl_union_pw_aff from "s".
4251 * First check if there are any paramters, then read in the opening brace
4252 * and use read_union_pw_aff_with_dom to read in the body of
4253 * the isl_union_pw_aff. Finally, read the closing brace.
4255 __isl_give isl_union_pw_aff *isl_stream_read_union_pw_aff(
4256 __isl_keep isl_stream *s)
4258 struct vars *v;
4259 isl_set *dom;
4260 isl_union_pw_aff *upa = NULL;
4262 v = vars_new(s->ctx);
4263 if (!v)
4264 return NULL;
4266 dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
4267 if (next_is_tuple(s)) {
4268 dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
4269 if (isl_stream_eat(s, ISL_TOKEN_TO))
4270 goto error;
4272 if (isl_stream_eat(s, '{'))
4273 goto error;
4275 upa = read_union_pw_aff_with_dom(s, isl_set_copy(dom), v);
4277 if (isl_stream_eat(s, '}'))
4278 goto error;
4280 vars_free(v);
4281 isl_set_free(dom);
4282 return upa;
4283 error:
4284 vars_free(v);
4285 isl_set_free(dom);
4286 isl_union_pw_aff_free(upa);
4287 return NULL;
4290 /* Read an isl_union_pw_aff from "str".
4292 __isl_give isl_union_pw_aff *isl_union_pw_aff_read_from_str(isl_ctx *ctx,
4293 const char *str)
4295 isl_union_pw_aff *upa;
4296 isl_stream *s = isl_stream_new_str(ctx, str);
4297 if (!s)
4298 return NULL;
4299 upa = isl_stream_read_union_pw_aff(s);
4300 isl_stream_free(s);
4301 return upa;
4304 /* This function is called for each element in a tuple inside
4305 * isl_stream_read_multi_union_pw_aff.
4307 * Read a '{', the union piecewise affine expression body and a '}' and
4308 * add the isl_union_pw_aff to *list.
4310 static __isl_give isl_space *read_union_pw_aff_el(__isl_keep isl_stream *s,
4311 struct vars *v, __isl_take isl_space *space, int rational, void *user)
4313 isl_set *dom;
4314 isl_union_pw_aff *upa;
4315 isl_union_pw_aff_list **list = (isl_union_pw_aff_list **) user;
4317 dom = isl_set_universe(isl_space_params(isl_space_copy(space)));
4318 if (isl_stream_eat(s, '{'))
4319 goto error;
4320 upa = read_union_pw_aff_with_dom(s, dom, v);
4321 *list = isl_union_pw_aff_list_add(*list, upa);
4322 if (isl_stream_eat(s, '}'))
4323 return isl_space_free(space);
4324 if (!*list)
4325 return isl_space_free(space);
4326 return space;
4327 error:
4328 isl_set_free(dom);
4329 return isl_space_free(space);
4332 /* Do the next tokens in "s" correspond to an empty tuple?
4333 * In particular, does the stream start with a '[', followed by a ']',
4334 * not followed by a "->"?
4336 static int next_is_empty_tuple(__isl_keep isl_stream *s)
4338 struct isl_token *tok, *tok2, *tok3;
4339 int is_empty_tuple = 0;
4341 tok = isl_stream_next_token(s);
4342 if (!tok)
4343 return 0;
4344 if (tok->type != '[') {
4345 isl_stream_push_token(s, tok);
4346 return 0;
4349 tok2 = isl_stream_next_token(s);
4350 if (tok2 && tok2->type == ']') {
4351 tok3 = isl_stream_next_token(s);
4352 is_empty_tuple = !tok || tok->type != ISL_TOKEN_TO;
4353 if (tok3)
4354 isl_stream_push_token(s, tok3);
4356 if (tok2)
4357 isl_stream_push_token(s, tok2);
4358 isl_stream_push_token(s, tok);
4360 return is_empty_tuple;
4363 /* Do the next tokens in "s" correspond to a tuple of parameters?
4364 * In particular, does the stream start with a '[' that is not
4365 * followed by a '{' or a nested tuple?
4367 static int next_is_param_tuple(__isl_keep isl_stream *s)
4369 struct isl_token *tok, *tok2;
4370 int is_tuple;
4372 tok = isl_stream_next_token(s);
4373 if (!tok)
4374 return 0;
4375 if (tok->type != '[' || next_is_tuple(s)) {
4376 isl_stream_push_token(s, tok);
4377 return 0;
4380 tok2 = isl_stream_next_token(s);
4381 is_tuple = tok2 && tok2->type != '{';
4382 if (tok2)
4383 isl_stream_push_token(s, tok2);
4384 isl_stream_push_token(s, tok);
4386 return is_tuple;
4389 /* Read the core of a body of an isl_multi_union_pw_aff from "s",
4390 * i.e., everything except the parameter specification and
4391 * without shared domain constraints.
4392 * "v" contains a description of the identifiers parsed so far.
4393 * The parameters, if any, are specified by "space".
4395 * The body is of the form
4397 * [{ [..] : ... ; [..] : ... }, { [..] : ... ; [..] : ... }]
4399 * Read the tuple, collecting the individual isl_union_pw_aff
4400 * elements in a list and construct the result from the tuple space and
4401 * the list.
4403 static __isl_give isl_multi_union_pw_aff *read_multi_union_pw_aff_body_core(
4404 __isl_keep isl_stream *s, struct vars *v, __isl_take isl_space *space)
4406 isl_union_pw_aff_list *list;
4407 isl_multi_union_pw_aff *mupa;
4409 list = isl_union_pw_aff_list_alloc(s->ctx, 0);
4410 space = read_tuple_space(s, v, space, 1, 0,
4411 &read_union_pw_aff_el, &list);
4412 mupa = isl_multi_union_pw_aff_from_union_pw_aff_list(space, list);
4414 return mupa;
4417 /* Read the body of an isl_union_set from "s",
4418 * i.e., everything except the parameter specification.
4419 * "v" contains a description of the identifiers parsed so far.
4420 * The parameters, if any, are specified by "space".
4422 * First read a generic disjunction of object bodies and then try and extract
4423 * an isl_union_set from that.
4425 static __isl_give isl_union_set *read_union_set_body(__isl_keep isl_stream *s,
4426 struct vars *v, __isl_take isl_space *space)
4428 struct isl_obj obj = { isl_obj_set, NULL };
4429 isl_map *map;
4431 map = isl_set_universe(space);
4432 if (isl_stream_eat(s, '{') < 0)
4433 goto error;
4434 obj = obj_read_disjuncts(s, v, map);
4435 if (isl_stream_eat(s, '}') < 0)
4436 goto error;
4437 isl_map_free(map);
4439 return extract_union_set(s->ctx, obj);
4440 error:
4441 obj.type->free(obj.v);
4442 isl_map_free(map);
4443 return NULL;
4446 /* Read the body of an isl_multi_union_pw_aff from "s",
4447 * i.e., everything except the parameter specification.
4448 * "v" contains a description of the identifiers parsed so far.
4449 * The parameters, if any, are specified by "space".
4451 * In particular, handle the special case with shared domain constraints.
4452 * These are specified as
4454 * ([...] : ...)
4456 * and are especially useful for setting the explicit domain
4457 * of a zero-dimensional isl_multi_union_pw_aff.
4458 * The core isl_multi_union_pw_aff body ([...]) is read by
4459 * read_multi_union_pw_aff_body_core.
4461 static __isl_give isl_multi_union_pw_aff *read_multi_union_pw_aff_body(
4462 __isl_keep isl_stream *s, struct vars *v, __isl_take isl_space *space)
4464 isl_multi_union_pw_aff *mupa;
4466 if (!isl_stream_next_token_is(s, '('))
4467 return read_multi_union_pw_aff_body_core(s, v, space);
4469 if (isl_stream_eat(s, '(') < 0)
4470 goto error;
4471 mupa = read_multi_union_pw_aff_body_core(s, v, isl_space_copy(space));
4472 if (isl_stream_eat_if_available(s, ':')) {
4473 isl_union_set *dom;
4475 dom = read_union_set_body(s, v, space);
4476 mupa = isl_multi_union_pw_aff_intersect_domain(mupa, dom);
4477 } else {
4478 isl_space_free(space);
4480 if (isl_stream_eat(s, ')') < 0)
4481 return isl_multi_union_pw_aff_free(mupa);
4483 return mupa;
4484 error:
4485 isl_space_free(space);
4486 return NULL;
4489 /* Read an isl_multi_union_pw_aff from "s".
4491 * The input has the form
4493 * [{ [..] : ... ; [..] : ... }, { [..] : ... ; [..] : ... }]
4495 * or
4497 * [..] -> [{ [..] : ... ; [..] : ... }, { [..] : ... ; [..] : ... }]
4499 * Additionally, a shared domain may be specified as
4501 * ([..] : ...)
4503 * or
4505 * [..] -> ([..] : ...)
4507 * The first case is handled by the caller, the second case
4508 * is handled by read_multi_union_pw_aff_body.
4510 * We first check for the special case of an empty tuple "[]".
4511 * Then we check if there are any parameters.
4512 * Finally, read the tuple and construct the result.
4514 static __isl_give isl_multi_union_pw_aff *read_multi_union_pw_aff_core(
4515 __isl_keep isl_stream *s)
4517 struct vars *v;
4518 isl_set *dom = NULL;
4519 isl_space *space;
4520 isl_multi_union_pw_aff *mupa = NULL;
4522 if (next_is_empty_tuple(s)) {
4523 if (isl_stream_eat(s, '['))
4524 return NULL;
4525 if (isl_stream_eat(s, ']'))
4526 return NULL;
4527 space = isl_space_set_alloc(s->ctx, 0, 0);
4528 return isl_multi_union_pw_aff_zero(space);
4531 v = vars_new(s->ctx);
4532 if (!v)
4533 return NULL;
4535 dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
4536 if (next_is_param_tuple(s)) {
4537 dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
4538 if (isl_stream_eat(s, ISL_TOKEN_TO))
4539 goto error;
4541 space = isl_set_get_space(dom);
4542 isl_set_free(dom);
4543 mupa = read_multi_union_pw_aff_body(s, v, space);
4545 vars_free(v);
4547 return mupa;
4548 error:
4549 vars_free(v);
4550 isl_set_free(dom);
4551 isl_multi_union_pw_aff_free(mupa);
4552 return NULL;
4555 /* Read an isl_multi_union_pw_aff from "s".
4557 * In particular, handle the special case with shared domain constraints.
4558 * These are specified as
4560 * ([...] : ...)
4562 * and are especially useful for setting the explicit domain
4563 * of a zero-dimensional isl_multi_union_pw_aff.
4564 * The core isl_multi_union_pw_aff ([...]) is read by
4565 * read_multi_union_pw_aff_core.
4567 __isl_give isl_multi_union_pw_aff *isl_stream_read_multi_union_pw_aff(
4568 __isl_keep isl_stream *s)
4570 isl_multi_union_pw_aff *mupa;
4572 if (!isl_stream_next_token_is(s, '('))
4573 return read_multi_union_pw_aff_core(s);
4575 if (isl_stream_eat(s, '(') < 0)
4576 return NULL;
4577 mupa = read_multi_union_pw_aff_core(s);
4578 if (isl_stream_eat_if_available(s, ':')) {
4579 isl_union_set *dom;
4581 dom = isl_stream_read_union_set(s);
4582 mupa = isl_multi_union_pw_aff_intersect_domain(mupa, dom);
4584 if (isl_stream_eat(s, ')') < 0)
4585 return isl_multi_union_pw_aff_free(mupa);
4586 return mupa;
4589 /* Read an isl_multi_union_pw_aff from "str".
4591 __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_read_from_str(
4592 isl_ctx *ctx, const char *str)
4594 isl_multi_union_pw_aff *mupa;
4595 isl_stream *s = isl_stream_new_str(ctx, str);
4596 if (!s)
4597 return NULL;
4598 mupa = isl_stream_read_multi_union_pw_aff(s);
4599 isl_stream_free(s);
4600 return mupa;
4603 __isl_give isl_union_pw_qpolynomial *isl_stream_read_union_pw_qpolynomial(
4604 __isl_keep isl_stream *s)
4606 struct isl_obj obj;
4608 obj = obj_read(s);
4609 if (obj.type == isl_obj_pw_qpolynomial) {
4610 obj.type = isl_obj_union_pw_qpolynomial;
4611 obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v);
4613 if (obj.v)
4614 isl_assert(s->ctx, obj.type == isl_obj_union_pw_qpolynomial,
4615 goto error);
4617 return obj.v;
4618 error:
4619 obj.type->free(obj.v);
4620 return NULL;
4623 __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_read_from_str(
4624 isl_ctx *ctx, const char *str)
4626 isl_union_pw_qpolynomial *upwqp;
4627 isl_stream *s = isl_stream_new_str(ctx, str);
4628 if (!s)
4629 return NULL;
4630 upwqp = isl_stream_read_union_pw_qpolynomial(s);
4631 isl_stream_free(s);
4632 return upwqp;