Home | History | Annotate | Line # | Download | only in dist
      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>
      6 
      7 static __isl_give isl_printer *file_start_line(__isl_take isl_printer *p)
      8 {
      9 	fprintf(p->file, "%s%*s%s", p->indent_prefix ? p->indent_prefix : "",
     10 				    p->indent, "", p->prefix ? p->prefix : "");
     11 	return p;
     12 }
     13 
     14 static __isl_give isl_printer *file_end_line(__isl_take isl_printer *p)
     15 {
     16 	fprintf(p->file, "%s\n", p->suffix ? p->suffix : "");
     17 	return p;
     18 }
     19 
     20 static __isl_give isl_printer *file_flush(__isl_take isl_printer *p)
     21 {
     22 	fflush(p->file);
     23 	return p;
     24 }
     25 
     26 static __isl_give isl_printer *file_print_str(__isl_take isl_printer *p,
     27 	const char *s)
     28 {
     29 	fprintf(p->file, "%s", s);
     30 	return p;
     31 }
     32 
     33 static __isl_give isl_printer *file_print_double(__isl_take isl_printer *p,
     34 	double d)
     35 {
     36 	fprintf(p->file, "%g", d);
     37 	return p;
     38 }
     39 
     40 static __isl_give isl_printer *file_print_int(__isl_take isl_printer *p, int i)
     41 {
     42 	fprintf(p->file, "%d", i);
     43 	return p;
     44 }
     45 
     46 static __isl_give isl_printer *file_print_isl_int(__isl_take isl_printer *p, isl_int i)
     47 {
     48 	isl_int_print(p->file, i, p->width);
     49 	return p;
     50 }
     51 
     52 static int grow_buf(__isl_keep isl_printer *p, int extra)
     53 {
     54 	int new_size;
     55 	char *new_buf;
     56 
     57 	if (p->buf_size == 0)
     58 		return -1;
     59 
     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;
     65 	}
     66 	p->buf = new_buf;
     67 	p->buf_size = new_size;
     68 
     69 	return 0;
     70 }
     71 
     72 static __isl_give isl_printer *str_print(__isl_take isl_printer *p,
     73 	const char *s, int len)
     74 {
     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;
     79 
     80 	p->buf[p->buf_n] = '\0';
     81 	return p;
     82 error:
     83 	isl_printer_free(p);
     84 	return NULL;
     85 }
     86 
     87 static __isl_give isl_printer *str_print_indent(__isl_take isl_printer *p,
     88 	int indent)
     89 {
     90 	int i;
     91 
     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 	p->buf[p->buf_n] = '\0';
     97 	return p;
     98 error:
     99 	isl_printer_free(p);
    100 	return NULL;
    101 }
    102 
    103 static __isl_give isl_printer *str_start_line(__isl_take isl_printer *p)
    104 {
    105 	if (p->indent_prefix)
    106 		p = str_print(p, p->indent_prefix, strlen(p->indent_prefix));
    107 	p = str_print_indent(p, p->indent);
    108 	if (p->prefix)
    109 		p = str_print(p, p->prefix, strlen(p->prefix));
    110 	return p;
    111 }
    112 
    113 static __isl_give isl_printer *str_end_line(__isl_take isl_printer *p)
    114 {
    115 	if (p->suffix)
    116 		p = str_print(p, p->suffix, strlen(p->suffix));
    117 	p = str_print(p, "\n", strlen("\n"));
    118 	return p;
    119 }
    120 
    121 static __isl_give isl_printer *str_flush(__isl_take isl_printer *p)
    122 {
    123 	p->buf_n = 0;
    124 	p->buf[p->buf_n] = '\0';
    125 	return p;
    126 }
    127 
    128 static __isl_give isl_printer *str_print_str(__isl_take isl_printer *p,
    129 	const char *s)
    130 {
    131 	return str_print(p, s, strlen(s));
    132 }
    133 
    134 static __isl_give isl_printer *str_print_double(__isl_take isl_printer *p,
    135 	double d)
    136 {
    137 	int left = p->buf_size - p->buf_n;
    138 	int need = snprintf(p->buf + p->buf_n, left, "%g", d);
    139 	if (need >= left) {
    140 		if (grow_buf(p, need))
    141 			goto error;
    142 		left = p->buf_size - p->buf_n;
    143 		need = snprintf(p->buf + p->buf_n, left, "%g", d);
    144 	}
    145 	p->buf_n += need;
    146 	return p;
    147 error:
    148 	isl_printer_free(p);
    149 	return NULL;
    150 }
    151 
    152 static __isl_give isl_printer *str_print_int(__isl_take isl_printer *p, int i)
    153 {
    154 	int left = p->buf_size - p->buf_n;
    155 	int need = snprintf(p->buf + p->buf_n, left, "%d", i);
    156 	if (need >= left) {
    157 		if (grow_buf(p, need))
    158 			goto error;
    159 		left = p->buf_size - p->buf_n;
    160 		need = snprintf(p->buf + p->buf_n, left, "%d", i);
    161 	}
    162 	p->buf_n += need;
    163 	return p;
    164 error:
    165 	isl_printer_free(p);
    166 	return NULL;
    167 }
    168 
    169 static __isl_give isl_printer *str_print_isl_int(__isl_take isl_printer *p,
    170 	isl_int i)
    171 {
    172 	char *s;
    173 	int len;
    174 
    175 	s = isl_int_get_str(i);
    176 	len = strlen(s);
    177 	if (len < p->width)
    178 		p = str_print_indent(p, p->width - len);
    179 	p = str_print(p, s, len);
    180 	isl_int_free_str(s);
    181 	return p;
    182 }
    183 
    184 struct isl_printer_ops {
    185 	__isl_give isl_printer *(*start_line)(__isl_take isl_printer *p);
    186 	__isl_give isl_printer *(*end_line)(__isl_take isl_printer *p);
    187 	__isl_give isl_printer *(*print_double)(__isl_take isl_printer *p,
    188 		double d);
    189 	__isl_give isl_printer *(*print_int)(__isl_take isl_printer *p, int i);
    190 	__isl_give isl_printer *(*print_isl_int)(__isl_take isl_printer *p,
    191 						isl_int i);
    192 	__isl_give isl_printer *(*print_str)(__isl_take isl_printer *p,
    193 						const char *s);
    194 	__isl_give isl_printer *(*flush)(__isl_take isl_printer *p);
    195 };
    196 
    197 static struct isl_printer_ops file_ops = {
    198 	file_start_line,
    199 	file_end_line,
    200 	file_print_double,
    201 	file_print_int,
    202 	file_print_isl_int,
    203 	file_print_str,
    204 	file_flush
    205 };
    206 
    207 static struct isl_printer_ops str_ops = {
    208 	str_start_line,
    209 	str_end_line,
    210 	str_print_double,
    211 	str_print_int,
    212 	str_print_isl_int,
    213 	str_print_str,
    214 	str_flush
    215 };
    216 
    217 __isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, FILE *file)
    218 {
    219 	struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer);
    220 	if (!p)
    221 		return NULL;
    222 	p->ctx = ctx;
    223 	isl_ctx_ref(p->ctx);
    224 	p->ops = &file_ops;
    225 	p->file = file;
    226 	p->buf = NULL;
    227 	p->buf_n = 0;
    228 	p->buf_size = 0;
    229 	p->indent = 0;
    230 	p->output_format = ISL_FORMAT_ISL;
    231 	p->indent_prefix = NULL;
    232 	p->prefix = NULL;
    233 	p->suffix = NULL;
    234 	p->width = 0;
    235 	p->yaml_style = ISL_YAML_STYLE_FLOW;
    236 
    237 	return p;
    238 }
    239 
    240 __isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx)
    241 {
    242 	struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer);
    243 	if (!p)
    244 		return NULL;
    245 	p->ctx = ctx;
    246 	isl_ctx_ref(p->ctx);
    247 	p->ops = &str_ops;
    248 	p->file = NULL;
    249 	p->buf = isl_alloc_array(ctx, char, 256);
    250 	if (!p->buf)
    251 		goto error;
    252 	p->buf_n = 0;
    253 	p->buf[0] = '\0';
    254 	p->buf_size = 256;
    255 	p->indent = 0;
    256 	p->output_format = ISL_FORMAT_ISL;
    257 	p->indent_prefix = NULL;
    258 	p->prefix = NULL;
    259 	p->suffix = NULL;
    260 	p->width = 0;
    261 	p->yaml_style = ISL_YAML_STYLE_FLOW;
    262 
    263 	return p;
    264 error:
    265 	isl_printer_free(p);
    266 	return NULL;
    267 }
    268 
    269 __isl_null isl_printer *isl_printer_free(__isl_take isl_printer *p)
    270 {
    271 	if (!p)
    272 		return NULL;
    273 	free(p->buf);
    274 	free(p->indent_prefix);
    275 	free(p->prefix);
    276 	free(p->suffix);
    277 	free(p->yaml_state);
    278 	isl_id_to_id_free(p->notes);
    279 	isl_ctx_deref(p->ctx);
    280 	free(p);
    281 
    282 	return NULL;
    283 }
    284 
    285 isl_ctx *isl_printer_get_ctx(__isl_keep isl_printer *printer)
    286 {
    287 	return printer ? printer->ctx : NULL;
    288 }
    289 
    290 FILE *isl_printer_get_file(__isl_keep isl_printer *printer)
    291 {
    292 	if (!printer)
    293 		return NULL;
    294 	if (!printer->file)
    295 		isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
    296 			"not a file printer", return NULL);
    297 	return printer->file;
    298 }
    299 
    300 __isl_give isl_printer *isl_printer_set_isl_int_width(__isl_take isl_printer *p,
    301 	int width)
    302 {
    303 	if (!p)
    304 		return NULL;
    305 
    306 	p->width = width;
    307 
    308 	return p;
    309 }
    310 
    311 __isl_give isl_printer *isl_printer_set_indent(__isl_take isl_printer *p,
    312 	int indent)
    313 {
    314 	if (!p)
    315 		return NULL;
    316 
    317 	p->indent = indent;
    318 
    319 	return p;
    320 }
    321 
    322 __isl_give isl_printer *isl_printer_indent(__isl_take isl_printer *p,
    323 	int indent)
    324 {
    325 	if (!p)
    326 		return NULL;
    327 
    328 	p->indent += indent;
    329 	if (p->indent < 0)
    330 		p->indent = 0;
    331 
    332 	return p;
    333 }
    334 
    335 /* Replace the indent prefix of "p" by "prefix".
    336  */
    337 __isl_give isl_printer *isl_printer_set_indent_prefix(__isl_take isl_printer *p,
    338 	const char *prefix)
    339 {
    340 	if (!p)
    341 		return NULL;
    342 
    343 	free(p->indent_prefix);
    344 	p->indent_prefix = prefix ? strdup(prefix) : NULL;
    345 
    346 	return p;
    347 }
    348 
    349 __isl_give isl_printer *isl_printer_set_prefix(__isl_take isl_printer *p,
    350 	const char *prefix)
    351 {
    352 	if (!p)
    353 		return NULL;
    354 
    355 	free(p->prefix);
    356 	p->prefix = prefix ? strdup(prefix) : NULL;
    357 
    358 	return p;
    359 }
    360 
    361 __isl_give isl_printer *isl_printer_set_suffix(__isl_take isl_printer *p,
    362 	const char *suffix)
    363 {
    364 	if (!p)
    365 		return NULL;
    366 
    367 	free(p->suffix);
    368 	p->suffix = suffix ? strdup(suffix) : NULL;
    369 
    370 	return p;
    371 }
    372 
    373 __isl_give isl_printer *isl_printer_set_output_format(__isl_take isl_printer *p,
    374 	int output_format)
    375 {
    376 	if (!p)
    377 		return NULL;
    378 
    379 	p->output_format = output_format;
    380 
    381 	return p;
    382 }
    383 
    384 int isl_printer_get_output_format(__isl_keep isl_printer *p)
    385 {
    386 	if (!p)
    387 		return -1;
    388 	return p->output_format;
    389 }
    390 
    391 /* Does "p" have a note with identifier "id"?
    392  */
    393 isl_bool isl_printer_has_note(__isl_keep isl_printer *p,
    394 	__isl_keep isl_id *id)
    395 {
    396 	if (!p || !id)
    397 		return isl_bool_error;
    398 	if (!p->notes)
    399 		return isl_bool_false;
    400 	return isl_id_to_id_has(p->notes, id);
    401 }
    402 
    403 /* Retrieve the note identified by "id" from "p".
    404  * The note is assumed to exist.
    405  */
    406 __isl_give isl_id *isl_printer_get_note(__isl_keep isl_printer *p,
    407 	__isl_take isl_id *id)
    408 {
    409 	isl_bool has_note;
    410 
    411 	has_note = isl_printer_has_note(p, id);
    412 	if (has_note < 0)
    413 		goto error;
    414 	if (!has_note)
    415 		isl_die(isl_printer_get_ctx(p), isl_error_invalid,
    416 			"no such note", goto error);
    417 
    418 	return isl_id_to_id_get(p->notes, id);
    419 error:
    420 	isl_id_free(id);
    421 	return NULL;
    422 }
    423 
    424 /* Associate "note" to the identifier "id" in "p",
    425  * replacing the previous note associated to the identifier, if any.
    426  */
    427 __isl_give isl_printer *isl_printer_set_note(__isl_take isl_printer *p,
    428 	__isl_take isl_id *id, __isl_take isl_id *note)
    429 {
    430 	if (!p || !id || !note)
    431 		goto error;
    432 	if (!p->notes) {
    433 		p->notes = isl_id_to_id_alloc(isl_printer_get_ctx(p), 1);
    434 		if (!p->notes)
    435 			goto error;
    436 	}
    437 	p->notes = isl_id_to_id_set(p->notes, id, note);
    438 	if (!p->notes)
    439 		return isl_printer_free(p);
    440 	return p;
    441 error:
    442 	isl_printer_free(p);
    443 	isl_id_free(id);
    444 	isl_id_free(note);
    445 	return NULL;
    446 }
    447 
    448 /* Keep track of whether the printing to "p" is being performed from
    449  * an isl_*_dump function as specified by "dump".
    450  */
    451 __isl_give isl_printer *isl_printer_set_dump(__isl_take isl_printer *p,
    452 	int dump)
    453 {
    454 	if (!p)
    455 		return NULL;
    456 
    457 	p->dump = dump;
    458 
    459 	return p;
    460 }
    461 
    462 /* Set the YAML style of "p" to "yaml_style" and return the updated printer.
    463  */
    464 __isl_give isl_printer *isl_printer_set_yaml_style(__isl_take isl_printer *p,
    465 	int yaml_style)
    466 {
    467 	if (!p)
    468 		return NULL;
    469 
    470 	p->yaml_style = yaml_style;
    471 
    472 	return p;
    473 }
    474 
    475 /* Return the YAML style of "p" or -1 on error.
    476  */
    477 int isl_printer_get_yaml_style(__isl_keep isl_printer *p)
    478 {
    479 	if (!p)
    480 		return -1;
    481 	return p->yaml_style;
    482 }
    483 
    484 /* Push "state" onto the stack of currently active YAML elements and
    485  * return the updated printer.
    486  */
    487 static __isl_give isl_printer *push_state(__isl_take isl_printer *p,
    488 	enum isl_yaml_state state)
    489 {
    490 	if (!p)
    491 		return NULL;
    492 
    493 	if (p->yaml_size < p->yaml_depth + 1) {
    494 		enum isl_yaml_state *state;
    495 		state = isl_realloc_array(p->ctx, p->yaml_state,
    496 					enum isl_yaml_state, p->yaml_depth + 1);
    497 		if (!state)
    498 			return isl_printer_free(p);
    499 		p->yaml_state = state;
    500 		p->yaml_size = p->yaml_depth + 1;
    501 	}
    502 
    503 	p->yaml_state[p->yaml_depth] = state;
    504 	p->yaml_depth++;
    505 
    506 	return p;
    507 }
    508 
    509 /* Remove the innermost active YAML element from the stack and
    510  * return the updated printer.
    511  */
    512 static __isl_give isl_printer *pop_state(__isl_take isl_printer *p)
    513 {
    514 	if (!p)
    515 		return NULL;
    516 	p->yaml_depth--;
    517 	return p;
    518 }
    519 
    520 /* Set the state of the innermost active YAML element to "state" and
    521  * return the updated printer.
    522  */
    523 static __isl_give isl_printer *update_state(__isl_take isl_printer *p,
    524 	enum isl_yaml_state state)
    525 {
    526 	if (!p)
    527 		return NULL;
    528 	if (p->yaml_depth < 1)
    529 		isl_die(isl_printer_get_ctx(p), isl_error_invalid,
    530 			"not in YAML construct", return isl_printer_free(p));
    531 
    532 	p->yaml_state[p->yaml_depth - 1] = state;
    533 
    534 	return p;
    535 }
    536 
    537 /* Return the state of the innermost active YAML element.
    538  * Return isl_yaml_none if we are not inside any YAML element.
    539  */
    540 static enum isl_yaml_state current_state(__isl_keep isl_printer *p)
    541 {
    542 	if (!p)
    543 		return isl_yaml_none;
    544 	if (p->yaml_depth < 1)
    545 		return isl_yaml_none;
    546 	return p->yaml_state[p->yaml_depth - 1];
    547 }
    548 
    549 /* If we are printing a YAML document and we are at the start of an element,
    550  * print whatever is needed before we can print the actual element and
    551  * keep track of the fact that we are now printing the element.
    552  * If "eol" is set, then whatever we print is going to be the last
    553  * thing that gets printed on this line.
    554  *
    555  * If we are about the print the first key of a mapping, then nothing
    556  * extra needs to be printed.  For any other key, however, we need
    557  * to either move to the next line (in block format) or print a comma
    558  * (in flow format).
    559  * Before printing a value in a mapping, we need to print a colon.
    560  *
    561  * For sequences, in flow format, we only need to print a comma
    562  * for each element except the first.
    563  * In block format, before the first element in the sequence,
    564  * we move to a new line, print a dash and increase the indentation.
    565  * Before any other element, we print a dash on a new line,
    566  * temporarily moving the indentation back.
    567  */
    568 static __isl_give isl_printer *enter_state(__isl_take isl_printer *p,
    569 	int eol)
    570 {
    571 	enum isl_yaml_state state;
    572 
    573 	if (!p)
    574 		return NULL;
    575 
    576 	state = current_state(p);
    577 	if (state == isl_yaml_mapping_val_start) {
    578 		if (eol)
    579 			p = p->ops->print_str(p, ":");
    580 		else
    581 			p = p->ops->print_str(p, ": ");
    582 		p = update_state(p, isl_yaml_mapping_val);
    583 	} else if (state == isl_yaml_mapping_first_key_start) {
    584 		p = update_state(p, isl_yaml_mapping_key);
    585 	} else if (state == isl_yaml_mapping_key_start) {
    586 		if (p->yaml_style == ISL_YAML_STYLE_FLOW)
    587 			p = p->ops->print_str(p, ", ");
    588 		else {
    589 			p = p->ops->end_line(p);
    590 			p = p->ops->start_line(p);
    591 		}
    592 		p = update_state(p, isl_yaml_mapping_key);
    593 	} else if (state == isl_yaml_sequence_first_start) {
    594 		if (p->yaml_style != ISL_YAML_STYLE_FLOW) {
    595 			p = p->ops->end_line(p);
    596 			p = p->ops->start_line(p);
    597 			p = p->ops->print_str(p, "- ");
    598 			p = isl_printer_indent(p, 2);
    599 		}
    600 		p = update_state(p, isl_yaml_sequence);
    601 	} else if (state == isl_yaml_sequence_start) {
    602 		if (p->yaml_style == ISL_YAML_STYLE_FLOW)
    603 			p = p->ops->print_str(p, ", ");
    604 		else {
    605 			p = p->ops->end_line(p);
    606 			p = isl_printer_indent(p, -2);
    607 			p = p->ops->start_line(p);
    608 			p = p->ops->print_str(p, "- ");
    609 			p = isl_printer_indent(p, 2);
    610 		}
    611 		p = update_state(p, isl_yaml_sequence);
    612 	}
    613 
    614 	return p;
    615 }
    616 
    617 __isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p,
    618 	const char *s)
    619 {
    620 	if (!p)
    621 		return NULL;
    622 	if (!s)
    623 		return isl_printer_free(p);
    624 	p = enter_state(p, 0);
    625 	if (!p)
    626 		return NULL;
    627 	return p->ops->print_str(p, s);
    628 }
    629 
    630 __isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p,
    631 	double d)
    632 {
    633 	p = enter_state(p, 0);
    634 	if (!p)
    635 		return NULL;
    636 
    637 	return p->ops->print_double(p, d);
    638 }
    639 
    640 __isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i)
    641 {
    642 	p = enter_state(p, 0);
    643 	if (!p)
    644 		return NULL;
    645 
    646 	return p->ops->print_int(p, i);
    647 }
    648 
    649 __isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p,
    650 	isl_int i)
    651 {
    652 	p = enter_state(p, 0);
    653 	if (!p)
    654 		return NULL;
    655 
    656 	return p->ops->print_isl_int(p, i);
    657 }
    658 
    659 __isl_give isl_printer *isl_printer_start_line(__isl_take isl_printer *p)
    660 {
    661 	if (!p)
    662 		return NULL;
    663 
    664 	return p->ops->start_line(p);
    665 }
    666 
    667 __isl_give isl_printer *isl_printer_end_line(__isl_take isl_printer *p)
    668 {
    669 	if (!p)
    670 		return NULL;
    671 
    672 	return p->ops->end_line(p);
    673 }
    674 
    675 /* Return a copy of the string constructed by the string printer "printer".
    676  */
    677 __isl_give char *isl_printer_get_str(__isl_keep isl_printer *printer)
    678 {
    679 	if (!printer)
    680 		return NULL;
    681 	if (printer->ops != &str_ops)
    682 		isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
    683 			"isl_printer_get_str can only be called on a string "
    684 			"printer", return NULL);
    685 	if (!printer->buf)
    686 		return NULL;
    687 	return strdup(printer->buf);
    688 }
    689 
    690 __isl_give isl_printer *isl_printer_flush(__isl_take isl_printer *p)
    691 {
    692 	if (!p)
    693 		return NULL;
    694 
    695 	return p->ops->flush(p);
    696 }
    697 
    698 /* Start a YAML mapping and push a new state to reflect that we
    699  * are about to print the first key in a mapping.
    700  *
    701  * In flow style, print the opening brace.
    702  * In block style, move to the next line with an increased indentation,
    703  * except if this is the outer mapping or if we are inside a sequence
    704  * (in which case we have already increased the indentation and we want
    705  * to print the first key on the same line as the dash).
    706  */
    707 __isl_give isl_printer *isl_printer_yaml_start_mapping(
    708 	__isl_take isl_printer *p)
    709 {
    710 	enum isl_yaml_state state;
    711 
    712 	if (!p)
    713 		return NULL;
    714 	p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK);
    715 	if (!p)
    716 		return NULL;
    717 	state = current_state(p);
    718 	if (p->yaml_style == ISL_YAML_STYLE_FLOW)
    719 		p = p->ops->print_str(p, "{ ");
    720 	else if (state != isl_yaml_none && state != isl_yaml_sequence) {
    721 		p = p->ops->end_line(p);
    722 		p = isl_printer_indent(p, 2);
    723 		p = p->ops->start_line(p);
    724 	}
    725 	p = push_state(p, isl_yaml_mapping_first_key_start);
    726 	return p;
    727 }
    728 
    729 /* Finish a YAML mapping and pop it from the state stack.
    730  *
    731  * In flow style, print the closing brace.
    732  *
    733  * In block style, first check if we are still in the
    734  * isl_yaml_mapping_first_key_start state.  If so, we have not printed
    735  * anything yet, so print "{}" to indicate an empty mapping.
    736  * If we increased the indentation in isl_printer_yaml_start_mapping,
    737  * then decrease it again.
    738  * If this is the outer mapping then print a newline.
    739  */
    740 __isl_give isl_printer *isl_printer_yaml_end_mapping(
    741 	__isl_take isl_printer *p)
    742 {
    743 	enum isl_yaml_state state;
    744 
    745 	state = current_state(p);
    746 	p = pop_state(p);
    747 	if (!p)
    748 		return NULL;
    749 	if (p->yaml_style == ISL_YAML_STYLE_FLOW)
    750 		return p->ops->print_str(p, " }");
    751 	if (state == isl_yaml_mapping_first_key_start)
    752 		p = p->ops->print_str(p, "{}");
    753 	if (!p)
    754 		return NULL;
    755 	state = current_state(p);
    756 	if (state != isl_yaml_none && state != isl_yaml_sequence)
    757 		p = isl_printer_indent(p, -2);
    758 	if (state == isl_yaml_none)
    759 		p = p->ops->end_line(p);
    760 	return p;
    761 }
    762 
    763 /* Start a YAML sequence and push a new state to reflect that we
    764  * are about to print the first element in a sequence.
    765  *
    766  * In flow style, print the opening bracket.
    767  */
    768 __isl_give isl_printer *isl_printer_yaml_start_sequence(
    769 	__isl_take isl_printer *p)
    770 {
    771 	if (!p)
    772 		return NULL;
    773 	p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK);
    774 	p = push_state(p, isl_yaml_sequence_first_start);
    775 	if (!p)
    776 		return NULL;
    777 	if (p->yaml_style == ISL_YAML_STYLE_FLOW)
    778 		p = p->ops->print_str(p, "[ ");
    779 	return p;
    780 }
    781 
    782 /* Finish a YAML sequence and pop it from the state stack.
    783  *
    784  * In flow style, print the closing bracket.
    785  *
    786  * In block style, check if we are still in the
    787  * isl_yaml_sequence_first_start state.  If so, we have not printed
    788  * anything yet, so print "[]" or " []" to indicate an empty sequence.
    789  * We print the extra space when we instructed enter_state not
    790  * to print a space at the end of the line.
    791  * Otherwise, undo the increase in indentation performed by
    792  * enter_state when moving away from the isl_yaml_sequence_first_start
    793  * state.
    794  * If this is the outer sequence then print a newline.
    795  */
    796 __isl_give isl_printer *isl_printer_yaml_end_sequence(
    797 	__isl_take isl_printer *p)
    798 {
    799 	enum isl_yaml_state state, up;
    800 
    801 	state = current_state(p);
    802 	p = pop_state(p);
    803 	if (!p)
    804 		return NULL;
    805 	if (p->yaml_style == ISL_YAML_STYLE_FLOW)
    806 		return p->ops->print_str(p, " ]");
    807 	up = current_state(p);
    808 	if (state == isl_yaml_sequence_first_start) {
    809 		if (up == isl_yaml_mapping_val)
    810 			p = p->ops->print_str(p, " []");
    811 		else
    812 			p = p->ops->print_str(p, "[]");
    813 	} else {
    814 		p = isl_printer_indent(p, -2);
    815 	}
    816 	if (!p)
    817 		return NULL;
    818 	state = current_state(p);
    819 	if (state == isl_yaml_none)
    820 		p = p->ops->end_line(p);
    821 	return p;
    822 }
    823 
    824 /* Mark the fact that the current element is finished and that
    825  * the next output belongs to the next element.
    826  * In particular, if we are printing a key, then prepare for
    827  * printing the subsequent value.  If we are printing a value,
    828  * prepare for printing the next key.  If we are printing an
    829  * element in a sequence, prepare for printing the next element.
    830  */
    831 __isl_give isl_printer *isl_printer_yaml_next(__isl_take isl_printer *p)
    832 {
    833 	enum isl_yaml_state state;
    834 
    835 	if (!p)
    836 		return NULL;
    837 	if (p->yaml_depth < 1)
    838 		isl_die(isl_printer_get_ctx(p), isl_error_invalid,
    839 			"not in YAML construct", return isl_printer_free(p));
    840 
    841 	state = current_state(p);
    842 	if (state == isl_yaml_mapping_key)
    843 		state = isl_yaml_mapping_val_start;
    844 	else if (state == isl_yaml_mapping_val)
    845 		state = isl_yaml_mapping_key_start;
    846 	else if (state == isl_yaml_sequence)
    847 		state = isl_yaml_sequence_start;
    848 	p = update_state(p, state);
    849 
    850 	return p;
    851 }
    852