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
: "");
14 static __isl_give isl_printer
*file_end_line(__isl_take isl_printer
*p
)
16 fprintf(p
->file
, "%s\n", p
->suffix
? p
->suffix
: "");
20 static __isl_give isl_printer
*file_flush(__isl_take isl_printer
*p
)
26 static __isl_give isl_printer
*file_print_str(__isl_take isl_printer
*p
,
29 fprintf(p
->file
, "%s", s
);
33 static __isl_give isl_printer
*file_print_double(__isl_take isl_printer
*p
,
36 fprintf(p
->file
, "%g", d
);
40 static __isl_give isl_printer
*file_print_int(__isl_take isl_printer
*p
, int i
)
42 fprintf(p
->file
, "%d", i
);
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
);
52 static int grow_buf(__isl_keep isl_printer
*p
, int extra
)
60 new_size
= ((p
->buf_n
+ extra
+ 1) * 3) / 2;
61 new_buf
= isl_realloc_array(p
->ctx
, p
->buf
, char, new_size
);
67 p
->buf_size
= new_size
;
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
))
77 memcpy(p
->buf
+ p
->buf_n
, s
, len
);
80 p
->buf
[p
->buf_n
] = '\0';
87 static __isl_give isl_printer
*str_print_indent(__isl_take isl_printer
*p
,
92 if (p
->buf_n
+ indent
+ 1 >= p
->buf_size
&& grow_buf(p
, indent
))
94 for (i
= 0; i
< indent
; ++i
)
95 p
->buf
[p
->buf_n
++] = ' ';
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
);
108 p
= str_print(p
, p
->prefix
, strlen(p
->prefix
));
112 static __isl_give isl_printer
*str_end_line(__isl_take isl_printer
*p
)
115 p
= str_print(p
, p
->suffix
, strlen(p
->suffix
));
116 p
= str_print(p
, "\n", strlen("\n"));
120 static __isl_give isl_printer
*str_flush(__isl_take isl_printer
*p
)
123 p
->buf
[p
->buf_n
] = '\0';
127 static __isl_give isl_printer
*str_print_str(__isl_take isl_printer
*p
,
130 return str_print(p
, s
, strlen(s
));
133 static __isl_give isl_printer
*str_print_double(__isl_take isl_printer
*p
,
136 int left
= p
->buf_size
- p
->buf_n
;
137 int need
= snprintf(p
->buf
+ p
->buf_n
, left
, "%g", d
);
139 if (grow_buf(p
, need
))
141 left
= p
->buf_size
- p
->buf_n
;
142 need
= snprintf(p
->buf
+ p
->buf_n
, left
, "%g", d
);
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
);
156 if (grow_buf(p
, need
))
158 left
= p
->buf_size
- p
->buf_n
;
159 need
= snprintf(p
->buf
+ p
->buf_n
, left
, "%d", i
);
168 static __isl_give isl_printer
*str_print_isl_int(__isl_take isl_printer
*p
,
174 s
= isl_int_get_str(i
);
177 p
= str_print_indent(p
, p
->width
- len
);
178 p
= str_print(p
, s
, len
);
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
,
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
,
191 __isl_give isl_printer
*(*print_str
)(__isl_take isl_printer
*p
,
193 __isl_give isl_printer
*(*flush
)(__isl_take isl_printer
*p
);
196 static struct isl_printer_ops file_ops
= {
206 static struct isl_printer_ops str_ops
= {
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
);
229 p
->output_format
= ISL_FORMAT_ISL
;
230 p
->indent_prefix
= NULL
;
234 p
->yaml_style
= ISL_YAML_STYLE_FLOW
;
239 __isl_give isl_printer
*isl_printer_to_str(isl_ctx
*ctx
)
241 struct isl_printer
*p
= isl_calloc_type(ctx
, struct isl_printer
);
248 p
->buf
= isl_alloc_array(ctx
, char, 256);
255 p
->output_format
= ISL_FORMAT_ISL
;
256 p
->indent_prefix
= NULL
;
260 p
->yaml_style
= ISL_YAML_STYLE_FLOW
;
268 __isl_null isl_printer
*isl_printer_free(__isl_take isl_printer
*p
)
273 free(p
->indent_prefix
);
277 isl_id_to_id_free(p
->notes
);
278 isl_ctx_deref(p
->ctx
);
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
)
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
,
310 __isl_give isl_printer
*isl_printer_set_indent(__isl_take isl_printer
*p
,
321 __isl_give isl_printer
*isl_printer_indent(__isl_take isl_printer
*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
,
342 free(p
->indent_prefix
);
343 p
->indent_prefix
= prefix
? strdup(prefix
) : NULL
;
348 __isl_give isl_printer
*isl_printer_set_prefix(__isl_take isl_printer
*p
,
355 p
->prefix
= prefix
? strdup(prefix
) : NULL
;
360 __isl_give isl_printer
*isl_printer_set_suffix(__isl_take isl_printer
*p
,
367 p
->suffix
= suffix
? strdup(suffix
) : NULL
;
372 __isl_give isl_printer
*isl_printer_set_output_format(__isl_take isl_printer
*p
,
378 p
->output_format
= output_format
;
383 int isl_printer_get_output_format(__isl_keep isl_printer
*p
)
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
)
396 return isl_bool_error
;
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
)
410 has_note
= isl_printer_has_note(p
, id
);
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
);
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
)
432 p
->notes
= isl_id_to_id_alloc(isl_printer_get_ctx(p
), 1);
436 p
->notes
= isl_id_to_id_set(p
->notes
, id
, note
);
438 return isl_printer_free(p
);
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
,
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
,
469 p
->yaml_style
= yaml_style
;
474 /* Return the YAML style of "p" or -1 on error.
476 int isl_printer_get_yaml_style(__isl_keep isl_printer
*p
)
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
)
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);
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
;
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
)
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
)
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
;
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
)
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
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
,
570 enum isl_yaml_state state
;
575 state
= current_state(p
);
576 if (state
== isl_yaml_mapping_val_start
) {
578 p
= p
->ops
->print_str(p
, ":");
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
, ", ");
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
, ", ");
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
);
616 __isl_give isl_printer
*isl_printer_print_str(__isl_take isl_printer
*p
,
622 return isl_printer_free(p
);
623 p
= enter_state(p
, 0);
626 return p
->ops
->print_str(p
, s
);
629 __isl_give isl_printer
*isl_printer_print_double(__isl_take isl_printer
*p
,
632 p
= enter_state(p
, 0);
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);
645 return p
->ops
->print_int(p
, i
);
648 __isl_give isl_printer
*isl_printer_print_isl_int(__isl_take isl_printer
*p
,
651 p
= enter_state(p
, 0);
655 return p
->ops
->print_isl_int(p
, i
);
658 __isl_give isl_printer
*isl_printer_start_line(__isl_take isl_printer
*p
)
663 return p
->ops
->start_line(p
);
666 __isl_give isl_printer
*isl_printer_end_line(__isl_take isl_printer
*p
)
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
)
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
);
686 return strdup(printer
->buf
);
689 __isl_give isl_printer
*isl_printer_flush(__isl_take isl_printer
*p
)
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
;
713 p
= enter_state(p
, p
->yaml_style
== ISL_YAML_STYLE_BLOCK
);
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
);
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
);
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
, "{}");
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
);
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
)
772 p
= enter_state(p
, p
->yaml_style
== ISL_YAML_STYLE_BLOCK
);
773 p
= push_state(p
, isl_yaml_sequence_first_start
);
776 if (p
->yaml_style
== ISL_YAML_STYLE_FLOW
)
777 p
= p
->ops
->print_str(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
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
);
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
, " []");
811 p
= p
->ops
->print_str(p
, "[]");
813 p
= isl_printer_indent(p
, -2);
817 state
= current_state(p
);
818 if (state
== isl_yaml_none
)
819 p
= p
->ops
->end_line(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
;
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
);