isl_ast_build_get_space: improve error handling
[isl.git] / isl_printer.c
blob05860da7303fe29de022d6de7d6ebcb6a7bcb129
1 #include <string.h>
2 #include <isl_int.h>
3 #include <isl_printer_private.h>
5 static __isl_give isl_printer *file_start_line(__isl_take isl_printer *p)
7 fprintf(p->file, "%s%*s%s", p->indent_prefix ? p->indent_prefix : "",
8 p->indent, "", p->prefix ? p->prefix : "");
9 return p;
12 static __isl_give isl_printer *file_end_line(__isl_take isl_printer *p)
14 fprintf(p->file, "%s\n", p->suffix ? p->suffix : "");
15 return p;
18 static __isl_give isl_printer *file_flush(__isl_take isl_printer *p)
20 fflush(p->file);
21 return p;
24 static __isl_give isl_printer *file_print_str(__isl_take isl_printer *p,
25 const char *s)
27 fprintf(p->file, "%s", s);
28 return p;
31 static __isl_give isl_printer *file_print_double(__isl_take isl_printer *p,
32 double d)
34 fprintf(p->file, "%g", d);
35 return p;
38 static __isl_give isl_printer *file_print_int(__isl_take isl_printer *p, int i)
40 fprintf(p->file, "%d", i);
41 return p;
44 static __isl_give isl_printer *file_print_isl_int(__isl_take isl_printer *p, isl_int i)
46 isl_int_print(p->file, i, p->width);
47 return p;
50 static int grow_buf(__isl_keep isl_printer *p, int extra)
52 int new_size;
53 char *new_buf;
55 if (p->buf_size == 0)
56 return -1;
58 new_size = ((p->buf_n + extra + 1) * 3) / 2;
59 new_buf = isl_realloc_array(p->ctx, p->buf, char, new_size);
60 if (!new_buf) {
61 p->buf_size = 0;
62 return -1;
64 p->buf = new_buf;
65 p->buf_size = new_size;
67 return 0;
70 static __isl_give isl_printer *str_print(__isl_take isl_printer *p,
71 const char *s, int len)
73 if (p->buf_n + len + 1 >= p->buf_size && grow_buf(p, len))
74 goto error;
75 memcpy(p->buf + p->buf_n, s, len);
76 p->buf_n += len;
78 p->buf[p->buf_n] = '\0';
79 return p;
80 error:
81 isl_printer_free(p);
82 return NULL;
85 static __isl_give isl_printer *str_print_indent(__isl_take isl_printer *p,
86 int indent)
88 int i;
90 if (p->buf_n + indent + 1 >= p->buf_size && grow_buf(p, indent))
91 goto error;
92 for (i = 0; i < indent; ++i)
93 p->buf[p->buf_n++] = ' ';
94 return p;
95 error:
96 isl_printer_free(p);
97 return NULL;
100 static __isl_give isl_printer *str_start_line(__isl_take isl_printer *p)
102 if (p->indent_prefix)
103 p = str_print(p, p->indent_prefix, strlen(p->indent_prefix));
104 p = str_print_indent(p, p->indent);
105 if (p->prefix)
106 p = str_print(p, p->prefix, strlen(p->prefix));
107 return p;
110 static __isl_give isl_printer *str_end_line(__isl_take isl_printer *p)
112 if (p->suffix)
113 p = str_print(p, p->suffix, strlen(p->suffix));
114 p = str_print(p, "\n", strlen("\n"));
115 return p;
118 static __isl_give isl_printer *str_flush(__isl_take isl_printer *p)
120 p->buf_n = 0;
121 p->buf[p->buf_n] = '\0';
122 return p;
125 static __isl_give isl_printer *str_print_str(__isl_take isl_printer *p,
126 const char *s)
128 return str_print(p, s, strlen(s));
131 static __isl_give isl_printer *str_print_double(__isl_take isl_printer *p,
132 double d)
134 int left = p->buf_size - p->buf_n;
135 int need = snprintf(p->buf + p->buf_n, left, "%g", d);
136 if (need >= left) {
137 if (grow_buf(p, need))
138 goto error;
139 left = p->buf_size - p->buf_n;
140 need = snprintf(p->buf + p->buf_n, left, "%g", d);
142 p->buf_n += need;
143 return p;
144 error:
145 isl_printer_free(p);
146 return NULL;
149 static __isl_give isl_printer *str_print_int(__isl_take isl_printer *p, int i)
151 int left = p->buf_size - p->buf_n;
152 int need = snprintf(p->buf + p->buf_n, left, "%d", i);
153 if (need >= left) {
154 if (grow_buf(p, need))
155 goto error;
156 left = p->buf_size - p->buf_n;
157 need = snprintf(p->buf + p->buf_n, left, "%d", i);
159 p->buf_n += need;
160 return p;
161 error:
162 isl_printer_free(p);
163 return NULL;
166 static __isl_give isl_printer *str_print_isl_int(__isl_take isl_printer *p,
167 isl_int i)
169 char *s;
170 int len;
172 s = isl_int_get_str(i);
173 len = strlen(s);
174 if (len < p->width)
175 p = str_print_indent(p, p->width - len);
176 p = str_print(p, s, len);
177 isl_int_free_str(s);
178 return p;
181 struct isl_printer_ops {
182 __isl_give isl_printer *(*start_line)(__isl_take isl_printer *p);
183 __isl_give isl_printer *(*end_line)(__isl_take isl_printer *p);
184 __isl_give isl_printer *(*print_double)(__isl_take isl_printer *p,
185 double d);
186 __isl_give isl_printer *(*print_int)(__isl_take isl_printer *p, int i);
187 __isl_give isl_printer *(*print_isl_int)(__isl_take isl_printer *p,
188 isl_int i);
189 __isl_give isl_printer *(*print_str)(__isl_take isl_printer *p,
190 const char *s);
191 __isl_give isl_printer *(*flush)(__isl_take isl_printer *p);
194 static struct isl_printer_ops file_ops = {
195 file_start_line,
196 file_end_line,
197 file_print_double,
198 file_print_int,
199 file_print_isl_int,
200 file_print_str,
201 file_flush
204 static struct isl_printer_ops str_ops = {
205 str_start_line,
206 str_end_line,
207 str_print_double,
208 str_print_int,
209 str_print_isl_int,
210 str_print_str,
211 str_flush
214 __isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, FILE *file)
216 struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer);
217 if (!p)
218 return NULL;
219 p->ctx = ctx;
220 isl_ctx_ref(p->ctx);
221 p->ops = &file_ops;
222 p->file = file;
223 p->buf = NULL;
224 p->buf_n = 0;
225 p->buf_size = 0;
226 p->indent = 0;
227 p->output_format = ISL_FORMAT_ISL;
228 p->indent_prefix = NULL;
229 p->prefix = NULL;
230 p->suffix = NULL;
231 p->width = 0;
232 p->yaml_style = ISL_YAML_STYLE_FLOW;
234 return p;
237 __isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx)
239 struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer);
240 if (!p)
241 return NULL;
242 p->ctx = ctx;
243 isl_ctx_ref(p->ctx);
244 p->ops = &str_ops;
245 p->file = NULL;
246 p->buf = isl_alloc_array(ctx, char, 256);
247 if (!p->buf)
248 goto error;
249 p->buf_n = 0;
250 p->buf[0] = '\0';
251 p->buf_size = 256;
252 p->indent = 0;
253 p->output_format = ISL_FORMAT_ISL;
254 p->indent_prefix = NULL;
255 p->prefix = NULL;
256 p->suffix = NULL;
257 p->width = 0;
258 p->yaml_style = ISL_YAML_STYLE_FLOW;
260 return p;
261 error:
262 isl_printer_free(p);
263 return NULL;
266 __isl_null isl_printer *isl_printer_free(__isl_take isl_printer *p)
268 if (!p)
269 return NULL;
270 free(p->buf);
271 free(p->indent_prefix);
272 free(p->prefix);
273 free(p->suffix);
274 free(p->yaml_state);
275 isl_id_to_id_free(p->notes);
276 isl_ctx_deref(p->ctx);
277 free(p);
279 return NULL;
282 isl_ctx *isl_printer_get_ctx(__isl_keep isl_printer *printer)
284 return printer ? printer->ctx : NULL;
287 FILE *isl_printer_get_file(__isl_keep isl_printer *printer)
289 if (!printer)
290 return NULL;
291 if (!printer->file)
292 isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
293 "not a file printer", return NULL);
294 return printer->file;
297 __isl_give isl_printer *isl_printer_set_isl_int_width(__isl_take isl_printer *p,
298 int width)
300 if (!p)
301 return NULL;
303 p->width = width;
305 return p;
308 __isl_give isl_printer *isl_printer_set_indent(__isl_take isl_printer *p,
309 int indent)
311 if (!p)
312 return NULL;
314 p->indent = indent;
316 return p;
319 __isl_give isl_printer *isl_printer_indent(__isl_take isl_printer *p,
320 int indent)
322 if (!p)
323 return NULL;
325 p->indent += indent;
326 if (p->indent < 0)
327 p->indent = 0;
329 return p;
332 /* Replace the indent prefix of "p" by "prefix".
334 __isl_give isl_printer *isl_printer_set_indent_prefix(__isl_take isl_printer *p,
335 const char *prefix)
337 if (!p)
338 return NULL;
340 free(p->indent_prefix);
341 p->indent_prefix = prefix ? strdup(prefix) : NULL;
343 return p;
346 __isl_give isl_printer *isl_printer_set_prefix(__isl_take isl_printer *p,
347 const char *prefix)
349 if (!p)
350 return NULL;
352 free(p->prefix);
353 p->prefix = prefix ? strdup(prefix) : NULL;
355 return p;
358 __isl_give isl_printer *isl_printer_set_suffix(__isl_take isl_printer *p,
359 const char *suffix)
361 if (!p)
362 return NULL;
364 free(p->suffix);
365 p->suffix = suffix ? strdup(suffix) : NULL;
367 return p;
370 __isl_give isl_printer *isl_printer_set_output_format(__isl_take isl_printer *p,
371 int output_format)
373 if (!p)
374 return NULL;
376 p->output_format = output_format;
378 return p;
381 int isl_printer_get_output_format(__isl_keep isl_printer *p)
383 if (!p)
384 return -1;
385 return p->output_format;
388 /* Does "p" have a note with identifier "id"?
390 isl_bool isl_printer_has_note(__isl_keep isl_printer *p,
391 __isl_keep isl_id *id)
393 if (!p || !id)
394 return isl_bool_error;
395 if (!p->notes)
396 return isl_bool_false;
397 return isl_id_to_id_has(p->notes, id);
400 /* Retrieve the note identified by "id" from "p".
401 * The note is assumed to exist.
403 __isl_give isl_id *isl_printer_get_note(__isl_keep isl_printer *p,
404 __isl_take isl_id *id)
406 isl_bool has_note;
408 has_note = isl_printer_has_note(p, id);
409 if (has_note < 0)
410 goto error;
411 if (!has_note)
412 isl_die(isl_printer_get_ctx(p), isl_error_invalid,
413 "no such note", goto error);
415 return isl_id_to_id_get(p->notes, id);
416 error:
417 isl_id_free(id);
418 return NULL;
421 /* Associate "note" to the identifier "id" in "p",
422 * replacing the previous note associated to the identifier, if any.
424 __isl_give isl_printer *isl_printer_set_note(__isl_take isl_printer *p,
425 __isl_take isl_id *id, __isl_take isl_id *note)
427 if (!p || !id || !note)
428 goto error;
429 if (!p->notes) {
430 p->notes = isl_id_to_id_alloc(isl_printer_get_ctx(p), 1);
431 if (!p->notes)
432 goto error;
434 p->notes = isl_id_to_id_set(p->notes, id, note);
435 if (!p->notes)
436 return isl_printer_free(p);
437 return p;
438 error:
439 isl_printer_free(p);
440 isl_id_free(id);
441 isl_id_free(note);
442 return NULL;
445 /* Keep track of whether the printing to "p" is being performed from
446 * an isl_*_dump function as specified by "dump".
448 __isl_give isl_printer *isl_printer_set_dump(__isl_take isl_printer *p,
449 int dump)
451 if (!p)
452 return NULL;
454 p->dump = dump;
456 return p;
459 /* Set the YAML style of "p" to "yaml_style" and return the updated printer.
461 __isl_give isl_printer *isl_printer_set_yaml_style(__isl_take isl_printer *p,
462 int yaml_style)
464 if (!p)
465 return NULL;
467 p->yaml_style = yaml_style;
469 return p;
472 /* Return the YAML style of "p" or -1 on error.
474 int isl_printer_get_yaml_style(__isl_keep isl_printer *p)
476 if (!p)
477 return -1;
478 return p->yaml_style;
481 /* Push "state" onto the stack of currently active YAML elements and
482 * return the updated printer.
484 static __isl_give isl_printer *push_state(__isl_take isl_printer *p,
485 enum isl_yaml_state state)
487 if (!p)
488 return NULL;
490 if (p->yaml_size < p->yaml_depth + 1) {
491 enum isl_yaml_state *state;
492 state = isl_realloc_array(p->ctx, p->yaml_state,
493 enum isl_yaml_state, p->yaml_depth + 1);
494 if (!state)
495 return isl_printer_free(p);
496 p->yaml_state = state;
497 p->yaml_size = p->yaml_depth + 1;
500 p->yaml_state[p->yaml_depth] = state;
501 p->yaml_depth++;
503 return p;
506 /* Remove the innermost active YAML element from the stack and
507 * return the updated printer.
509 static __isl_give isl_printer *pop_state(__isl_take isl_printer *p)
511 if (!p)
512 return NULL;
513 p->yaml_depth--;
514 return p;
517 /* Set the state of the innermost active YAML element to "state" and
518 * return the updated printer.
520 static __isl_give isl_printer *update_state(__isl_take isl_printer *p,
521 enum isl_yaml_state state)
523 if (!p)
524 return NULL;
525 if (p->yaml_depth < 1)
526 isl_die(isl_printer_get_ctx(p), isl_error_invalid,
527 "not in YAML construct", return isl_printer_free(p));
529 p->yaml_state[p->yaml_depth - 1] = state;
531 return p;
534 /* Return the state of the innermost active YAML element.
535 * Return isl_yaml_none if we are not inside any YAML element.
537 static enum isl_yaml_state current_state(__isl_keep isl_printer *p)
539 if (!p)
540 return isl_yaml_none;
541 if (p->yaml_depth < 1)
542 return isl_yaml_none;
543 return p->yaml_state[p->yaml_depth - 1];
546 /* If we are printing a YAML document and we are at the start of an element,
547 * print whatever is needed before we can print the actual element and
548 * keep track of the fact that we are now printing the element.
549 * If "eol" is set, then whatever we print is going to be the last
550 * thing that gets printed on this line.
552 * If we are about the print the first key of a mapping, then nothing
553 * extra needs to be printed. For any other key, however, we need
554 * to either move to the next line (in block format) or print a comma
555 * (in flow format).
556 * Before printing a value in a mapping, we need to print a colon.
558 * For sequences, in flow format, we only need to print a comma
559 * for each element except the first.
560 * In block format, before the first element in the sequence,
561 * we move to a new line, print a dash and increase the indentation.
562 * Before any other element, we print a dash on a new line,
563 * temporarily moving the indentation back.
565 static __isl_give isl_printer *enter_state(__isl_take isl_printer *p,
566 int eol)
568 enum isl_yaml_state state;
570 if (!p)
571 return NULL;
573 state = current_state(p);
574 if (state == isl_yaml_mapping_val_start) {
575 if (eol)
576 p = p->ops->print_str(p, ":");
577 else
578 p = p->ops->print_str(p, ": ");
579 p = update_state(p, isl_yaml_mapping_val);
580 } else if (state == isl_yaml_mapping_first_key_start) {
581 p = update_state(p, isl_yaml_mapping_key);
582 } else if (state == isl_yaml_mapping_key_start) {
583 if (p->yaml_style == ISL_YAML_STYLE_FLOW)
584 p = p->ops->print_str(p, ", ");
585 else {
586 p = p->ops->end_line(p);
587 p = p->ops->start_line(p);
589 p = update_state(p, isl_yaml_mapping_key);
590 } else if (state == isl_yaml_sequence_first_start) {
591 if (p->yaml_style != ISL_YAML_STYLE_FLOW) {
592 p = p->ops->end_line(p);
593 p = p->ops->start_line(p);
594 p = p->ops->print_str(p, "- ");
595 p = isl_printer_indent(p, 2);
597 p = update_state(p, isl_yaml_sequence);
598 } else if (state == isl_yaml_sequence_start) {
599 if (p->yaml_style == ISL_YAML_STYLE_FLOW)
600 p = p->ops->print_str(p, ", ");
601 else {
602 p = p->ops->end_line(p);
603 p = isl_printer_indent(p, -2);
604 p = p->ops->start_line(p);
605 p = p->ops->print_str(p, "- ");
606 p = isl_printer_indent(p, 2);
608 p = update_state(p, isl_yaml_sequence);
611 return p;
614 __isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p,
615 const char *s)
617 if (!p)
618 return NULL;
619 if (!s)
620 return isl_printer_free(p);
621 p = enter_state(p, 0);
622 if (!p)
623 return NULL;
624 return p->ops->print_str(p, s);
627 __isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p,
628 double d)
630 p = enter_state(p, 0);
631 if (!p)
632 return NULL;
634 return p->ops->print_double(p, d);
637 __isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i)
639 p = enter_state(p, 0);
640 if (!p)
641 return NULL;
643 return p->ops->print_int(p, i);
646 __isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p,
647 isl_int i)
649 p = enter_state(p, 0);
650 if (!p)
651 return NULL;
653 return p->ops->print_isl_int(p, i);
656 __isl_give isl_printer *isl_printer_start_line(__isl_take isl_printer *p)
658 if (!p)
659 return NULL;
661 return p->ops->start_line(p);
664 __isl_give isl_printer *isl_printer_end_line(__isl_take isl_printer *p)
666 if (!p)
667 return NULL;
669 return p->ops->end_line(p);
672 /* Return a copy of the string constructed by the string printer "printer".
674 __isl_give char *isl_printer_get_str(__isl_keep isl_printer *printer)
676 if (!printer)
677 return NULL;
678 if (printer->ops != &str_ops)
679 isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
680 "isl_printer_get_str can only be called on a string "
681 "printer", return NULL);
682 if (!printer->buf)
683 return NULL;
684 return strdup(printer->buf);
687 __isl_give isl_printer *isl_printer_flush(__isl_take isl_printer *p)
689 if (!p)
690 return NULL;
692 return p->ops->flush(p);
695 /* Start a YAML mapping and push a new state to reflect that we
696 * are about to print the first key in a mapping.
698 * In flow style, print the opening brace.
699 * In block style, move to the next line with an increased indentation,
700 * except if this is the outer mapping or if we are inside a sequence
701 * (in which case we have already increased the indentation and we want
702 * to print the first key on the same line as the dash).
704 __isl_give isl_printer *isl_printer_yaml_start_mapping(
705 __isl_take isl_printer *p)
707 enum isl_yaml_state state;
709 if (!p)
710 return NULL;
711 p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK);
712 if (!p)
713 return NULL;
714 state = current_state(p);
715 if (p->yaml_style == ISL_YAML_STYLE_FLOW)
716 p = p->ops->print_str(p, "{ ");
717 else if (state != isl_yaml_none && state != isl_yaml_sequence) {
718 p = p->ops->end_line(p);
719 p = isl_printer_indent(p, 2);
720 p = p->ops->start_line(p);
722 p = push_state(p, isl_yaml_mapping_first_key_start);
723 return p;
726 /* Finish a YAML mapping and pop it from the state stack.
728 * In flow style, print the closing brace.
730 * In block style, first check if we are still in the
731 * isl_yaml_mapping_first_key_start state. If so, we have not printed
732 * anything yet, so print "{}" to indicate an empty mapping.
733 * If we increased the indentation in isl_printer_yaml_start_mapping,
734 * then decrease it again.
735 * If this is the outer mapping then print a newline.
737 __isl_give isl_printer *isl_printer_yaml_end_mapping(
738 __isl_take isl_printer *p)
740 enum isl_yaml_state state;
742 state = current_state(p);
743 p = pop_state(p);
744 if (!p)
745 return NULL;
746 if (p->yaml_style == ISL_YAML_STYLE_FLOW)
747 return p->ops->print_str(p, " }");
748 if (state == isl_yaml_mapping_first_key_start)
749 p = p->ops->print_str(p, "{}");
750 if (!p)
751 return NULL;
752 state = current_state(p);
753 if (state != isl_yaml_none && state != isl_yaml_sequence)
754 p = isl_printer_indent(p, -2);
755 if (state == isl_yaml_none)
756 p = p->ops->end_line(p);
757 return p;
760 /* Start a YAML sequence and push a new state to reflect that we
761 * are about to print the first element in a sequence.
763 * In flow style, print the opening bracket.
765 __isl_give isl_printer *isl_printer_yaml_start_sequence(
766 __isl_take isl_printer *p)
768 if (!p)
769 return NULL;
770 p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK);
771 p = push_state(p, isl_yaml_sequence_first_start);
772 if (!p)
773 return NULL;
774 if (p->yaml_style == ISL_YAML_STYLE_FLOW)
775 p = p->ops->print_str(p, "[ ");
776 return p;
779 /* Finish a YAML sequence and pop it from the state stack.
781 * In flow style, print the closing bracket.
783 * In block style, check if we are still in the
784 * isl_yaml_sequence_first_start state. If so, we have not printed
785 * anything yet, so print "[]" or " []" to indicate an empty sequence.
786 * We print the extra space when we instructed enter_state not
787 * to print a space at the end of the line.
788 * Otherwise, undo the increase in indentation performed by
789 * enter_state when moving away from the isl_yaml_sequence_first_start
790 * state.
791 * If this is the outer sequence then print a newline.
793 __isl_give isl_printer *isl_printer_yaml_end_sequence(
794 __isl_take isl_printer *p)
796 enum isl_yaml_state state, up;
798 state = current_state(p);
799 p = pop_state(p);
800 if (!p)
801 return NULL;
802 if (p->yaml_style == ISL_YAML_STYLE_FLOW)
803 return p->ops->print_str(p, " ]");
804 up = current_state(p);
805 if (state == isl_yaml_sequence_first_start) {
806 if (up == isl_yaml_mapping_val)
807 p = p->ops->print_str(p, " []");
808 else
809 p = p->ops->print_str(p, "[]");
810 } else {
811 p = isl_printer_indent(p, -2);
813 if (!p)
814 return NULL;
815 state = current_state(p);
816 if (state == isl_yaml_none)
817 p = p->ops->end_line(p);
818 return p;
821 /* Mark the fact that the current element is finished and that
822 * the next output belongs to the next element.
823 * In particular, if we are printing a key, then prepare for
824 * printing the subsequent value. If we are printing a value,
825 * prepare for printing the next key. If we are printing an
826 * element in a sequence, prepare for printing the next element.
828 __isl_give isl_printer *isl_printer_yaml_next(__isl_take isl_printer *p)
830 enum isl_yaml_state state;
832 if (!p)
833 return NULL;
834 if (p->yaml_depth < 1)
835 isl_die(isl_printer_get_ctx(p), isl_error_invalid,
836 "not in YAML construct", return isl_printer_free(p));
838 state = current_state(p);
839 if (state == isl_yaml_mapping_key)
840 state = isl_yaml_mapping_val_start;
841 else if (state == isl_yaml_mapping_val)
842 state = isl_yaml_mapping_key_start;
843 else if (state == isl_yaml_sequence)
844 state = isl_yaml_sequence_start;
845 p = update_state(p, state);
847 return p;