isl_ast_build_set_iterators: reuse isl_ast_build_dim
[isl.git] / isl_printer.c
blob27b54b2b10bf8893fb3248b425e9ebce878380bf
1 #include <string.h>
2 #include <isl_int.h>
3 #include <isl/id.h>
4 #include <isl/id_to_id.h>
5 #include <isl_printer_private.h>
7 static __isl_give isl_printer *file_start_line(__isl_take isl_printer *p)
9 fprintf(p->file, "%s%*s%s", p->indent_prefix ? p->indent_prefix : "",
10 p->indent, "", p->prefix ? p->prefix : "");
11 return p;
14 static __isl_give isl_printer *file_end_line(__isl_take isl_printer *p)
16 fprintf(p->file, "%s\n", p->suffix ? p->suffix : "");
17 return p;
20 static __isl_give isl_printer *file_flush(__isl_take isl_printer *p)
22 fflush(p->file);
23 return p;
26 static __isl_give isl_printer *file_print_str(__isl_take isl_printer *p,
27 const char *s)
29 fprintf(p->file, "%s", s);
30 return p;
33 static __isl_give isl_printer *file_print_double(__isl_take isl_printer *p,
34 double d)
36 fprintf(p->file, "%g", d);
37 return p;
40 static __isl_give isl_printer *file_print_int(__isl_take isl_printer *p, int i)
42 fprintf(p->file, "%d", i);
43 return p;
46 static __isl_give isl_printer *file_print_isl_int(__isl_take isl_printer *p, isl_int i)
48 isl_int_print(p->file, i, p->width);
49 return p;
52 static int grow_buf(__isl_keep isl_printer *p, int extra)
54 int new_size;
55 char *new_buf;
57 if (p->buf_size == 0)
58 return -1;
60 new_size = ((p->buf_n + extra + 1) * 3) / 2;
61 new_buf = isl_realloc_array(p->ctx, p->buf, char, new_size);
62 if (!new_buf) {
63 p->buf_size = 0;
64 return -1;
66 p->buf = new_buf;
67 p->buf_size = new_size;
69 return 0;
72 static __isl_give isl_printer *str_print(__isl_take isl_printer *p,
73 const char *s, int len)
75 if (p->buf_n + len + 1 >= p->buf_size && grow_buf(p, len))
76 goto error;
77 memcpy(p->buf + p->buf_n, s, len);
78 p->buf_n += len;
80 p->buf[p->buf_n] = '\0';
81 return p;
82 error:
83 isl_printer_free(p);
84 return NULL;
87 static __isl_give isl_printer *str_print_indent(__isl_take isl_printer *p,
88 int indent)
90 int i;
92 if (p->buf_n + indent + 1 >= p->buf_size && grow_buf(p, indent))
93 goto error;
94 for (i = 0; i < indent; ++i)
95 p->buf[p->buf_n++] = ' ';
96 return p;
97 error:
98 isl_printer_free(p);
99 return NULL;
102 static __isl_give isl_printer *str_start_line(__isl_take isl_printer *p)
104 if (p->indent_prefix)
105 p = str_print(p, p->indent_prefix, strlen(p->indent_prefix));
106 p = str_print_indent(p, p->indent);
107 if (p->prefix)
108 p = str_print(p, p->prefix, strlen(p->prefix));
109 return p;
112 static __isl_give isl_printer *str_end_line(__isl_take isl_printer *p)
114 if (p->suffix)
115 p = str_print(p, p->suffix, strlen(p->suffix));
116 p = str_print(p, "\n", strlen("\n"));
117 return p;
120 static __isl_give isl_printer *str_flush(__isl_take isl_printer *p)
122 p->buf_n = 0;
123 p->buf[p->buf_n] = '\0';
124 return p;
127 static __isl_give isl_printer *str_print_str(__isl_take isl_printer *p,
128 const char *s)
130 return str_print(p, s, strlen(s));
133 static __isl_give isl_printer *str_print_double(__isl_take isl_printer *p,
134 double d)
136 int left = p->buf_size - p->buf_n;
137 int need = snprintf(p->buf + p->buf_n, left, "%g", d);
138 if (need >= left) {
139 if (grow_buf(p, need))
140 goto error;
141 left = p->buf_size - p->buf_n;
142 need = snprintf(p->buf + p->buf_n, left, "%g", d);
144 p->buf_n += need;
145 return p;
146 error:
147 isl_printer_free(p);
148 return NULL;
151 static __isl_give isl_printer *str_print_int(__isl_take isl_printer *p, int i)
153 int left = p->buf_size - p->buf_n;
154 int need = snprintf(p->buf + p->buf_n, left, "%d", i);
155 if (need >= left) {
156 if (grow_buf(p, need))
157 goto error;
158 left = p->buf_size - p->buf_n;
159 need = snprintf(p->buf + p->buf_n, left, "%d", i);
161 p->buf_n += need;
162 return p;
163 error:
164 isl_printer_free(p);
165 return NULL;
168 static __isl_give isl_printer *str_print_isl_int(__isl_take isl_printer *p,
169 isl_int i)
171 char *s;
172 int len;
174 s = isl_int_get_str(i);
175 len = strlen(s);
176 if (len < p->width)
177 p = str_print_indent(p, p->width - len);
178 p = str_print(p, s, len);
179 isl_int_free_str(s);
180 return p;
183 struct isl_printer_ops {
184 __isl_give isl_printer *(*start_line)(__isl_take isl_printer *p);
185 __isl_give isl_printer *(*end_line)(__isl_take isl_printer *p);
186 __isl_give isl_printer *(*print_double)(__isl_take isl_printer *p,
187 double d);
188 __isl_give isl_printer *(*print_int)(__isl_take isl_printer *p, int i);
189 __isl_give isl_printer *(*print_isl_int)(__isl_take isl_printer *p,
190 isl_int i);
191 __isl_give isl_printer *(*print_str)(__isl_take isl_printer *p,
192 const char *s);
193 __isl_give isl_printer *(*flush)(__isl_take isl_printer *p);
196 static struct isl_printer_ops file_ops = {
197 file_start_line,
198 file_end_line,
199 file_print_double,
200 file_print_int,
201 file_print_isl_int,
202 file_print_str,
203 file_flush
206 static struct isl_printer_ops str_ops = {
207 str_start_line,
208 str_end_line,
209 str_print_double,
210 str_print_int,
211 str_print_isl_int,
212 str_print_str,
213 str_flush
216 __isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, FILE *file)
218 struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer);
219 if (!p)
220 return NULL;
221 p->ctx = ctx;
222 isl_ctx_ref(p->ctx);
223 p->ops = &file_ops;
224 p->file = file;
225 p->buf = NULL;
226 p->buf_n = 0;
227 p->buf_size = 0;
228 p->indent = 0;
229 p->output_format = ISL_FORMAT_ISL;
230 p->indent_prefix = NULL;
231 p->prefix = NULL;
232 p->suffix = NULL;
233 p->width = 0;
234 p->yaml_style = ISL_YAML_STYLE_FLOW;
236 return p;
239 __isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx)
241 struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer);
242 if (!p)
243 return NULL;
244 p->ctx = ctx;
245 isl_ctx_ref(p->ctx);
246 p->ops = &str_ops;
247 p->file = NULL;
248 p->buf = isl_alloc_array(ctx, char, 256);
249 if (!p->buf)
250 goto error;
251 p->buf_n = 0;
252 p->buf[0] = '\0';
253 p->buf_size = 256;
254 p->indent = 0;
255 p->output_format = ISL_FORMAT_ISL;
256 p->indent_prefix = NULL;
257 p->prefix = NULL;
258 p->suffix = NULL;
259 p->width = 0;
260 p->yaml_style = ISL_YAML_STYLE_FLOW;
262 return p;
263 error:
264 isl_printer_free(p);
265 return NULL;
268 __isl_null isl_printer *isl_printer_free(__isl_take isl_printer *p)
270 if (!p)
271 return NULL;
272 free(p->buf);
273 free(p->indent_prefix);
274 free(p->prefix);
275 free(p->suffix);
276 free(p->yaml_state);
277 isl_id_to_id_free(p->notes);
278 isl_ctx_deref(p->ctx);
279 free(p);
281 return NULL;
284 isl_ctx *isl_printer_get_ctx(__isl_keep isl_printer *printer)
286 return printer ? printer->ctx : NULL;
289 FILE *isl_printer_get_file(__isl_keep isl_printer *printer)
291 if (!printer)
292 return NULL;
293 if (!printer->file)
294 isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
295 "not a file printer", return NULL);
296 return printer->file;
299 __isl_give isl_printer *isl_printer_set_isl_int_width(__isl_take isl_printer *p,
300 int width)
302 if (!p)
303 return NULL;
305 p->width = width;
307 return p;
310 __isl_give isl_printer *isl_printer_set_indent(__isl_take isl_printer *p,
311 int indent)
313 if (!p)
314 return NULL;
316 p->indent = indent;
318 return p;
321 __isl_give isl_printer *isl_printer_indent(__isl_take isl_printer *p,
322 int indent)
324 if (!p)
325 return NULL;
327 p->indent += indent;
328 if (p->indent < 0)
329 p->indent = 0;
331 return p;
334 /* Replace the indent prefix of "p" by "prefix".
336 __isl_give isl_printer *isl_printer_set_indent_prefix(__isl_take isl_printer *p,
337 const char *prefix)
339 if (!p)
340 return NULL;
342 free(p->indent_prefix);
343 p->indent_prefix = prefix ? strdup(prefix) : NULL;
345 return p;
348 __isl_give isl_printer *isl_printer_set_prefix(__isl_take isl_printer *p,
349 const char *prefix)
351 if (!p)
352 return NULL;
354 free(p->prefix);
355 p->prefix = prefix ? strdup(prefix) : NULL;
357 return p;
360 __isl_give isl_printer *isl_printer_set_suffix(__isl_take isl_printer *p,
361 const char *suffix)
363 if (!p)
364 return NULL;
366 free(p->suffix);
367 p->suffix = suffix ? strdup(suffix) : NULL;
369 return p;
372 __isl_give isl_printer *isl_printer_set_output_format(__isl_take isl_printer *p,
373 int output_format)
375 if (!p)
376 return NULL;
378 p->output_format = output_format;
380 return p;
383 int isl_printer_get_output_format(__isl_keep isl_printer *p)
385 if (!p)
386 return -1;
387 return p->output_format;
390 /* Does "p" have a note with identifier "id"?
392 isl_bool isl_printer_has_note(__isl_keep isl_printer *p,
393 __isl_keep isl_id *id)
395 if (!p || !id)
396 return isl_bool_error;
397 if (!p->notes)
398 return isl_bool_false;
399 return isl_id_to_id_has(p->notes, id);
402 /* Retrieve the note identified by "id" from "p".
403 * The note is assumed to exist.
405 __isl_give isl_id *isl_printer_get_note(__isl_keep isl_printer *p,
406 __isl_take isl_id *id)
408 isl_bool has_note;
410 has_note = isl_printer_has_note(p, id);
411 if (has_note < 0)
412 goto error;
413 if (!has_note)
414 isl_die(isl_printer_get_ctx(p), isl_error_invalid,
415 "no such note", goto error);
417 return isl_id_to_id_get(p->notes, id);
418 error:
419 isl_id_free(id);
420 return NULL;
423 /* Associate "note" to the identifier "id" in "p",
424 * replacing the previous note associated to the identifier, if any.
426 __isl_give isl_printer *isl_printer_set_note(__isl_take isl_printer *p,
427 __isl_take isl_id *id, __isl_take isl_id *note)
429 if (!p || !id || !note)
430 goto error;
431 if (!p->notes) {
432 p->notes = isl_id_to_id_alloc(isl_printer_get_ctx(p), 1);
433 if (!p->notes)
434 goto error;
436 p->notes = isl_id_to_id_set(p->notes, id, note);
437 if (!p->notes)
438 return isl_printer_free(p);
439 return p;
440 error:
441 isl_printer_free(p);
442 isl_id_free(id);
443 isl_id_free(note);
444 return NULL;
447 /* Keep track of whether the printing to "p" is being performed from
448 * an isl_*_dump function as specified by "dump".
450 __isl_give isl_printer *isl_printer_set_dump(__isl_take isl_printer *p,
451 int dump)
453 if (!p)
454 return NULL;
456 p->dump = dump;
458 return p;
461 /* Set the YAML style of "p" to "yaml_style" and return the updated printer.
463 __isl_give isl_printer *isl_printer_set_yaml_style(__isl_take isl_printer *p,
464 int yaml_style)
466 if (!p)
467 return NULL;
469 p->yaml_style = yaml_style;
471 return p;
474 /* Return the YAML style of "p" or -1 on error.
476 int isl_printer_get_yaml_style(__isl_keep isl_printer *p)
478 if (!p)
479 return -1;
480 return p->yaml_style;
483 /* Push "state" onto the stack of currently active YAML elements and
484 * return the updated printer.
486 static __isl_give isl_printer *push_state(__isl_take isl_printer *p,
487 enum isl_yaml_state state)
489 if (!p)
490 return NULL;
492 if (p->yaml_size < p->yaml_depth + 1) {
493 enum isl_yaml_state *state;
494 state = isl_realloc_array(p->ctx, p->yaml_state,
495 enum isl_yaml_state, p->yaml_depth + 1);
496 if (!state)
497 return isl_printer_free(p);
498 p->yaml_state = state;
499 p->yaml_size = p->yaml_depth + 1;
502 p->yaml_state[p->yaml_depth] = state;
503 p->yaml_depth++;
505 return p;
508 /* Remove the innermost active YAML element from the stack and
509 * return the updated printer.
511 static __isl_give isl_printer *pop_state(__isl_take isl_printer *p)
513 if (!p)
514 return NULL;
515 p->yaml_depth--;
516 return p;
519 /* Set the state of the innermost active YAML element to "state" and
520 * return the updated printer.
522 static __isl_give isl_printer *update_state(__isl_take isl_printer *p,
523 enum isl_yaml_state state)
525 if (!p)
526 return NULL;
527 if (p->yaml_depth < 1)
528 isl_die(isl_printer_get_ctx(p), isl_error_invalid,
529 "not in YAML construct", return isl_printer_free(p));
531 p->yaml_state[p->yaml_depth - 1] = state;
533 return p;
536 /* Return the state of the innermost active YAML element.
537 * Return isl_yaml_none if we are not inside any YAML element.
539 static enum isl_yaml_state current_state(__isl_keep isl_printer *p)
541 if (!p)
542 return isl_yaml_none;
543 if (p->yaml_depth < 1)
544 return isl_yaml_none;
545 return p->yaml_state[p->yaml_depth - 1];
548 /* If we are printing a YAML document and we are at the start of an element,
549 * print whatever is needed before we can print the actual element and
550 * keep track of the fact that we are now printing the element.
551 * If "eol" is set, then whatever we print is going to be the last
552 * thing that gets printed on this line.
554 * If we are about the print the first key of a mapping, then nothing
555 * extra needs to be printed. For any other key, however, we need
556 * to either move to the next line (in block format) or print a comma
557 * (in flow format).
558 * Before printing a value in a mapping, we need to print a colon.
560 * For sequences, in flow format, we only need to print a comma
561 * for each element except the first.
562 * In block format, before the first element in the sequence,
563 * we move to a new line, print a dash and increase the indentation.
564 * Before any other element, we print a dash on a new line,
565 * temporarily moving the indentation back.
567 static __isl_give isl_printer *enter_state(__isl_take isl_printer *p,
568 int eol)
570 enum isl_yaml_state state;
572 if (!p)
573 return NULL;
575 state = current_state(p);
576 if (state == isl_yaml_mapping_val_start) {
577 if (eol)
578 p = p->ops->print_str(p, ":");
579 else
580 p = p->ops->print_str(p, ": ");
581 p = update_state(p, isl_yaml_mapping_val);
582 } else if (state == isl_yaml_mapping_first_key_start) {
583 p = update_state(p, isl_yaml_mapping_key);
584 } else if (state == isl_yaml_mapping_key_start) {
585 if (p->yaml_style == ISL_YAML_STYLE_FLOW)
586 p = p->ops->print_str(p, ", ");
587 else {
588 p = p->ops->end_line(p);
589 p = p->ops->start_line(p);
591 p = update_state(p, isl_yaml_mapping_key);
592 } else if (state == isl_yaml_sequence_first_start) {
593 if (p->yaml_style != ISL_YAML_STYLE_FLOW) {
594 p = p->ops->end_line(p);
595 p = p->ops->start_line(p);
596 p = p->ops->print_str(p, "- ");
597 p = isl_printer_indent(p, 2);
599 p = update_state(p, isl_yaml_sequence);
600 } else if (state == isl_yaml_sequence_start) {
601 if (p->yaml_style == ISL_YAML_STYLE_FLOW)
602 p = p->ops->print_str(p, ", ");
603 else {
604 p = p->ops->end_line(p);
605 p = isl_printer_indent(p, -2);
606 p = p->ops->start_line(p);
607 p = p->ops->print_str(p, "- ");
608 p = isl_printer_indent(p, 2);
610 p = update_state(p, isl_yaml_sequence);
613 return p;
616 __isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p,
617 const char *s)
619 if (!p)
620 return NULL;
621 if (!s)
622 return isl_printer_free(p);
623 p = enter_state(p, 0);
624 if (!p)
625 return NULL;
626 return p->ops->print_str(p, s);
629 __isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p,
630 double d)
632 p = enter_state(p, 0);
633 if (!p)
634 return NULL;
636 return p->ops->print_double(p, d);
639 __isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i)
641 p = enter_state(p, 0);
642 if (!p)
643 return NULL;
645 return p->ops->print_int(p, i);
648 __isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p,
649 isl_int i)
651 p = enter_state(p, 0);
652 if (!p)
653 return NULL;
655 return p->ops->print_isl_int(p, i);
658 __isl_give isl_printer *isl_printer_start_line(__isl_take isl_printer *p)
660 if (!p)
661 return NULL;
663 return p->ops->start_line(p);
666 __isl_give isl_printer *isl_printer_end_line(__isl_take isl_printer *p)
668 if (!p)
669 return NULL;
671 return p->ops->end_line(p);
674 /* Return a copy of the string constructed by the string printer "printer".
676 __isl_give char *isl_printer_get_str(__isl_keep isl_printer *printer)
678 if (!printer)
679 return NULL;
680 if (printer->ops != &str_ops)
681 isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
682 "isl_printer_get_str can only be called on a string "
683 "printer", return NULL);
684 if (!printer->buf)
685 return NULL;
686 return strdup(printer->buf);
689 __isl_give isl_printer *isl_printer_flush(__isl_take isl_printer *p)
691 if (!p)
692 return NULL;
694 return p->ops->flush(p);
697 /* Start a YAML mapping and push a new state to reflect that we
698 * are about to print the first key in a mapping.
700 * In flow style, print the opening brace.
701 * In block style, move to the next line with an increased indentation,
702 * except if this is the outer mapping or if we are inside a sequence
703 * (in which case we have already increased the indentation and we want
704 * to print the first key on the same line as the dash).
706 __isl_give isl_printer *isl_printer_yaml_start_mapping(
707 __isl_take isl_printer *p)
709 enum isl_yaml_state state;
711 if (!p)
712 return NULL;
713 p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK);
714 if (!p)
715 return NULL;
716 state = current_state(p);
717 if (p->yaml_style == ISL_YAML_STYLE_FLOW)
718 p = p->ops->print_str(p, "{ ");
719 else if (state != isl_yaml_none && state != isl_yaml_sequence) {
720 p = p->ops->end_line(p);
721 p = isl_printer_indent(p, 2);
722 p = p->ops->start_line(p);
724 p = push_state(p, isl_yaml_mapping_first_key_start);
725 return p;
728 /* Finish a YAML mapping and pop it from the state stack.
730 * In flow style, print the closing brace.
732 * In block style, first check if we are still in the
733 * isl_yaml_mapping_first_key_start state. If so, we have not printed
734 * anything yet, so print "{}" to indicate an empty mapping.
735 * If we increased the indentation in isl_printer_yaml_start_mapping,
736 * then decrease it again.
737 * If this is the outer mapping then print a newline.
739 __isl_give isl_printer *isl_printer_yaml_end_mapping(
740 __isl_take isl_printer *p)
742 enum isl_yaml_state state;
744 state = current_state(p);
745 p = pop_state(p);
746 if (!p)
747 return NULL;
748 if (p->yaml_style == ISL_YAML_STYLE_FLOW)
749 return p->ops->print_str(p, " }");
750 if (state == isl_yaml_mapping_first_key_start)
751 p = p->ops->print_str(p, "{}");
752 if (!p)
753 return NULL;
754 state = current_state(p);
755 if (state != isl_yaml_none && state != isl_yaml_sequence)
756 p = isl_printer_indent(p, -2);
757 if (state == isl_yaml_none)
758 p = p->ops->end_line(p);
759 return p;
762 /* Start a YAML sequence and push a new state to reflect that we
763 * are about to print the first element in a sequence.
765 * In flow style, print the opening bracket.
767 __isl_give isl_printer *isl_printer_yaml_start_sequence(
768 __isl_take isl_printer *p)
770 if (!p)
771 return NULL;
772 p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK);
773 p = push_state(p, isl_yaml_sequence_first_start);
774 if (!p)
775 return NULL;
776 if (p->yaml_style == ISL_YAML_STYLE_FLOW)
777 p = p->ops->print_str(p, "[ ");
778 return p;
781 /* Finish a YAML sequence and pop it from the state stack.
783 * In flow style, print the closing bracket.
785 * In block style, check if we are still in the
786 * isl_yaml_sequence_first_start state. If so, we have not printed
787 * anything yet, so print "[]" or " []" to indicate an empty sequence.
788 * We print the extra space when we instructed enter_state not
789 * to print a space at the end of the line.
790 * Otherwise, undo the increase in indentation performed by
791 * enter_state when moving away from the isl_yaml_sequence_first_start
792 * state.
793 * If this is the outer sequence then print a newline.
795 __isl_give isl_printer *isl_printer_yaml_end_sequence(
796 __isl_take isl_printer *p)
798 enum isl_yaml_state state, up;
800 state = current_state(p);
801 p = pop_state(p);
802 if (!p)
803 return NULL;
804 if (p->yaml_style == ISL_YAML_STYLE_FLOW)
805 return p->ops->print_str(p, " ]");
806 up = current_state(p);
807 if (state == isl_yaml_sequence_first_start) {
808 if (up == isl_yaml_mapping_val)
809 p = p->ops->print_str(p, " []");
810 else
811 p = p->ops->print_str(p, "[]");
812 } else {
813 p = isl_printer_indent(p, -2);
815 if (!p)
816 return NULL;
817 state = current_state(p);
818 if (state == isl_yaml_none)
819 p = p->ops->end_line(p);
820 return p;
823 /* Mark the fact that the current element is finished and that
824 * the next output belongs to the next element.
825 * In particular, if we are printing a key, then prepare for
826 * printing the subsequent value. If we are printing a value,
827 * prepare for printing the next key. If we are printing an
828 * element in a sequence, prepare for printing the next element.
830 __isl_give isl_printer *isl_printer_yaml_next(__isl_take isl_printer *p)
832 enum isl_yaml_state state;
834 if (!p)
835 return NULL;
836 if (p->yaml_depth < 1)
837 isl_die(isl_printer_get_ctx(p), isl_error_invalid,
838 "not in YAML construct", return isl_printer_free(p));
840 state = current_state(p);
841 if (state == isl_yaml_mapping_key)
842 state = isl_yaml_mapping_val_start;
843 else if (state == isl_yaml_mapping_val)
844 state = isl_yaml_mapping_key_start;
845 else if (state == isl_yaml_sequence)
846 state = isl_yaml_sequence_start;
847 p = update_state(p, state);
849 return p;