2 * Copyright 2008-2009 Katholieke Universiteit Leuven
4 * Use of this software is governed by the MIT license
6 * Written by Sven Verdoolaege, K.U.Leuven, Departement
7 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
12 #include <isl_ctx_private.h>
13 #include <isl_stream_private.h>
16 #include <isl_val_private.h>
17 #include <isl_options_private.h>
21 enum isl_token_type type
;
24 static isl_bool
same_name(const void *entry
, const void *val
)
26 const struct isl_keyword
*keyword
= (const struct isl_keyword
*)entry
;
28 return isl_bool_ok(!strcmp(keyword
->name
, val
));
31 enum isl_token_type
isl_stream_register_keyword(__isl_keep isl_stream
*s
,
34 struct isl_hash_table_entry
*entry
;
35 struct isl_keyword
*keyword
;
39 s
->keywords
= isl_hash_table_alloc(s
->ctx
, 10);
41 return ISL_TOKEN_ERROR
;
42 s
->next_type
= ISL_TOKEN_LAST
;
45 name_hash
= isl_hash_string(isl_hash_init(), name
);
47 entry
= isl_hash_table_find(s
->ctx
, s
->keywords
, name_hash
,
50 return ISL_TOKEN_ERROR
;
52 keyword
= entry
->data
;
56 keyword
= isl_calloc_type(s
->ctx
, struct isl_keyword
);
58 return ISL_TOKEN_ERROR
;
59 keyword
->type
= s
->next_type
++;
60 keyword
->name
= strdup(name
);
63 return ISL_TOKEN_ERROR
;
65 entry
->data
= keyword
;
70 struct isl_token
*isl_token_new(isl_ctx
*ctx
,
71 int line
, int col
, unsigned on_new_line
)
73 struct isl_token
*tok
= isl_alloc_type(ctx
, struct isl_token
);
78 tok
->on_new_line
= on_new_line
;
84 /* Return the type of "tok".
86 int isl_token_get_type(struct isl_token
*tok
)
88 return tok
? tok
->type
: ISL_TOKEN_ERROR
;
91 /* Given a token of type ISL_TOKEN_VALUE, return the value it represents.
93 __isl_give isl_val
*isl_token_get_val(isl_ctx
*ctx
, struct isl_token
*tok
)
97 if (tok
->type
!= ISL_TOKEN_VALUE
)
98 isl_die(ctx
, isl_error_invalid
, "not a value token",
101 return isl_val_int_from_isl_int(ctx
, tok
->u
.v
);
104 /* Does the given token have a string representation?
106 isl_bool
isl_token_has_str(struct isl_token
*tok
)
109 return isl_bool_error
;
110 return isl_bool_ok(tok
->u
.s
!= NULL
);
113 /* Given a token with a string representation, return a copy of this string.
115 __isl_give
char *isl_token_get_str(isl_ctx
*ctx
, struct isl_token
*tok
)
120 isl_die(ctx
, isl_error_invalid
,
121 "token does not have a string representation",
124 return strdup(tok
->u
.s
);
127 void isl_token_free(struct isl_token
*tok
)
131 if (tok
->type
== ISL_TOKEN_VALUE
)
132 isl_int_clear(tok
->u
.v
);
133 else if (tok
->type
== ISL_TOKEN_MAP
)
134 isl_map_free(tok
->u
.map
);
135 else if (tok
->type
== ISL_TOKEN_AFF
)
136 isl_pw_aff_free(tok
->u
.pwaff
);
142 void isl_stream_error(__isl_keep isl_stream
*s
, struct isl_token
*tok
,
145 int line
= tok
? tok
->line
: s
->line
;
146 int col
= tok
? tok
->col
: s
->col
;
148 isl_ctx_set_full_error(s
->ctx
, isl_error_invalid
, "syntax error",
151 if (s
->ctx
->opt
->on_error
== ISL_ON_ERROR_CONTINUE
)
153 fprintf(stderr
, "syntax error (%d, %d): %s\n", line
, col
, msg
);
156 fprintf(stderr
, "got '%c'\n", tok
->type
);
157 else if (tok
->type
== ISL_TOKEN_IDENT
)
158 fprintf(stderr
, "got ident '%s'\n", tok
->u
.s
);
159 else if (tok
->is_keyword
)
160 fprintf(stderr
, "got keyword '%s'\n", tok
->u
.s
);
161 else if (tok
->type
== ISL_TOKEN_VALUE
) {
162 fprintf(stderr
, "got value '");
163 isl_int_print(stderr
, tok
->u
.v
, 0);
164 fprintf(stderr
, "'\n");
165 } else if (tok
->type
== ISL_TOKEN_MAP
) {
167 fprintf(stderr
, "got map '");
168 p
= isl_printer_to_file(s
->ctx
, stderr
);
169 p
= isl_printer_print_map(p
, tok
->u
.map
);
171 fprintf(stderr
, "'\n");
172 } else if (tok
->type
== ISL_TOKEN_AFF
) {
174 fprintf(stderr
, "got affine expression '");
175 p
= isl_printer_to_file(s
->ctx
, stderr
);
176 p
= isl_printer_print_pw_aff(p
, tok
->u
.pwaff
);
178 fprintf(stderr
, "'\n");
180 fprintf(stderr
, "got token '%s'\n", tok
->u
.s
);
182 fprintf(stderr
, "got token type %d\n", tok
->type
);
184 if (s
->ctx
->opt
->on_error
== ISL_ON_ERROR_ABORT
)
188 static __isl_give isl_stream
* isl_stream_new(struct isl_ctx
*ctx
)
191 isl_stream
*s
= isl_calloc_type(ctx
, struct isl_stream
);
205 for (i
= 0; i
< 5; ++i
)
210 s
->buffer
= isl_alloc_array(ctx
, char, s
->size
);
219 __isl_give isl_stream
* isl_stream_new_file(struct isl_ctx
*ctx
, FILE *file
)
221 isl_stream
*s
= isl_stream_new(ctx
);
228 __isl_give isl_stream
* isl_stream_new_str(struct isl_ctx
*ctx
, const char *str
)
233 s
= isl_stream_new(ctx
);
240 /* Read a character from the stream and advance s->line and s->col
241 * to point to the next character.
243 static int stream_getc(__isl_keep isl_stream
*s
)
249 return s
->c
= s
->un
[--s
->n_un
];
259 else if (c
== '\n') {
268 static void isl_stream_ungetc(__isl_keep isl_stream
*s
, int c
)
270 isl_assert(s
->ctx
, s
->n_un
< 5, return);
271 s
->un
[s
->n_un
++] = c
;
275 /* Read a character from the stream, skipping pairs of '\\' and '\n'.
276 * Set s->start_line and s->start_col to the line and column
277 * of the returned character.
279 static int isl_stream_getc(__isl_keep isl_stream
*s
)
284 s
->start_line
= s
->line
;
285 s
->start_col
= s
->col
;
292 isl_stream_ungetc(s
, c
);
297 static int isl_stream_push_char(__isl_keep isl_stream
*s
, int c
)
299 if (s
->len
>= s
->size
) {
301 s
->size
= (3*s
->size
)/2;
302 buffer
= isl_realloc_array(s
->ctx
, s
->buffer
, char, s
->size
);
307 s
->buffer
[s
->len
++] = c
;
311 void isl_stream_push_token(__isl_keep isl_stream
*s
, struct isl_token
*tok
)
313 isl_assert(s
->ctx
, s
->n_token
< 5, return);
314 s
->tokens
[s
->n_token
++] = tok
;
317 static enum isl_token_type
check_keywords(__isl_keep isl_stream
*s
)
319 struct isl_hash_table_entry
*entry
;
320 struct isl_keyword
*keyword
;
323 if (!strcasecmp(s
->buffer
, "exists"))
324 return ISL_TOKEN_EXISTS
;
325 if (!strcasecmp(s
->buffer
, "and"))
326 return ISL_TOKEN_AND
;
327 if (!strcasecmp(s
->buffer
, "or"))
329 if (!strcasecmp(s
->buffer
, "implies"))
330 return ISL_TOKEN_IMPLIES
;
331 if (!strcasecmp(s
->buffer
, "not"))
332 return ISL_TOKEN_NOT
;
333 if (!strcasecmp(s
->buffer
, "infty"))
334 return ISL_TOKEN_INFTY
;
335 if (!strcasecmp(s
->buffer
, "infinity"))
336 return ISL_TOKEN_INFTY
;
337 if (!strcasecmp(s
->buffer
, "NaN"))
338 return ISL_TOKEN_NAN
;
339 if (!strcasecmp(s
->buffer
, "min"))
340 return ISL_TOKEN_MIN
;
341 if (!strcasecmp(s
->buffer
, "max"))
342 return ISL_TOKEN_MAX
;
343 if (!strcasecmp(s
->buffer
, "rat"))
344 return ISL_TOKEN_RAT
;
345 if (!strcasecmp(s
->buffer
, "true"))
346 return ISL_TOKEN_TRUE
;
347 if (!strcasecmp(s
->buffer
, "false"))
348 return ISL_TOKEN_FALSE
;
349 if (!strcasecmp(s
->buffer
, "ceild"))
350 return ISL_TOKEN_CEILD
;
351 if (!strcasecmp(s
->buffer
, "floord"))
352 return ISL_TOKEN_FLOORD
;
353 if (!strcasecmp(s
->buffer
, "mod"))
354 return ISL_TOKEN_MOD
;
355 if (!strcasecmp(s
->buffer
, "ceil"))
356 return ISL_TOKEN_CEIL
;
357 if (!strcasecmp(s
->buffer
, "floor"))
358 return ISL_TOKEN_FLOOR
;
361 return ISL_TOKEN_IDENT
;
363 name_hash
= isl_hash_string(isl_hash_init(), s
->buffer
);
364 entry
= isl_hash_table_find(s
->ctx
, s
->keywords
, name_hash
, same_name
,
367 return ISL_TOKEN_ERROR
;
368 if (entry
!= isl_hash_table_entry_none
) {
369 keyword
= entry
->data
;
370 return keyword
->type
;
373 return ISL_TOKEN_IDENT
;
376 int isl_stream_skip_line(__isl_keep isl_stream
*s
)
380 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '\n')
384 return c
== -1 ? -1 : 0;
387 static struct isl_token
*next_token(__isl_keep isl_stream
*s
, int same_line
)
390 struct isl_token
*tok
= NULL
;
392 int old_line
= s
->last_line
;
395 if (same_line
&& s
->tokens
[s
->n_token
- 1]->on_new_line
)
397 return s
->tokens
[--s
->n_token
];
400 if (same_line
&& s
->c
== '\n')
405 /* skip spaces and comment lines */
406 while ((c
= isl_stream_getc(s
)) != -1) {
408 if (isl_stream_skip_line(s
) < 0)
413 } else if (!isspace(c
) || (same_line
&& c
== '\n'))
417 line
= s
->start_line
;
420 if (c
== -1 || (same_line
&& c
== '\n'))
440 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
443 tok
->type
= (enum isl_token_type
)c
;
448 if ((c
= isl_stream_getc(s
)) == '>') {
449 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
452 tok
->u
.s
= strdup("->");
453 tok
->type
= ISL_TOKEN_TO
;
457 isl_stream_ungetc(s
, c
);
458 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
461 tok
->type
= (enum isl_token_type
) '-';
465 int minus
= c
== '-';
466 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
469 tok
->type
= ISL_TOKEN_VALUE
;
470 isl_int_init(tok
->u
.v
);
471 if (isl_stream_push_char(s
, c
))
473 while ((c
= isl_stream_getc(s
)) != -1 && isdigit(c
))
474 if (isl_stream_push_char(s
, c
))
477 isl_stream_ungetc(s
, c
);
478 isl_stream_push_char(s
, '\0');
479 isl_int_read(tok
->u
.v
, s
->buffer
);
480 if (minus
&& isl_int_is_zero(tok
->u
.v
)) {
482 tok
->on_new_line
= 0;
483 isl_stream_push_token(s
, tok
);
484 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
487 tok
->type
= (enum isl_token_type
) '-';
491 if (isalpha(c
) || c
== '_') {
492 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
495 isl_stream_push_char(s
, c
);
496 while ((c
= isl_stream_getc(s
)) != -1 &&
497 (isalnum(c
) || c
== '_'))
498 isl_stream_push_char(s
, c
);
500 isl_stream_ungetc(s
, c
);
501 while ((c
= isl_stream_getc(s
)) != -1 && c
== '\'')
502 isl_stream_push_char(s
, c
);
504 isl_stream_ungetc(s
, c
);
505 isl_stream_push_char(s
, '\0');
506 tok
->type
= check_keywords(s
);
507 if (tok
->type
!= ISL_TOKEN_IDENT
)
509 tok
->u
.s
= strdup(s
->buffer
);
515 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
518 tok
->type
= ISL_TOKEN_STRING
;
520 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '"' && c
!= '\n')
521 isl_stream_push_char(s
, c
);
523 isl_stream_error(s
, NULL
, "unterminated string");
526 isl_stream_push_char(s
, '\0');
527 tok
->u
.s
= strdup(s
->buffer
);
532 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
535 if ((c
= isl_stream_getc(s
)) == '=') {
536 tok
->u
.s
= strdup("==");
537 tok
->type
= ISL_TOKEN_EQ_EQ
;
541 isl_stream_ungetc(s
, c
);
542 tok
->type
= (enum isl_token_type
) '=';
547 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
550 if ((c
= isl_stream_getc(s
)) == '=') {
551 tok
->u
.s
= strdup(":=");
552 tok
->type
= ISL_TOKEN_DEF
;
556 isl_stream_ungetc(s
, c
);
557 tok
->type
= (enum isl_token_type
) ':';
562 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
565 if ((c
= isl_stream_getc(s
)) == '=') {
566 tok
->u
.s
= strdup(">=");
567 tok
->type
= ISL_TOKEN_GE
;
569 } else if (c
== '>') {
570 if ((c
= isl_stream_getc(s
)) == '=') {
571 tok
->u
.s
= strdup(">>=");
572 tok
->type
= ISL_TOKEN_LEX_GE
;
575 tok
->u
.s
= strdup(">>");
576 tok
->type
= ISL_TOKEN_LEX_GT
;
578 tok
->u
.s
= strdup(">");
579 tok
->type
= ISL_TOKEN_GT
;
582 isl_stream_ungetc(s
, c
);
587 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
590 if ((c
= isl_stream_getc(s
)) == '=') {
591 tok
->u
.s
= strdup("<=");
592 tok
->type
= ISL_TOKEN_LE
;
594 } else if (c
== '<') {
595 if ((c
= isl_stream_getc(s
)) == '=') {
596 tok
->u
.s
= strdup("<<=");
597 tok
->type
= ISL_TOKEN_LEX_LE
;
600 tok
->u
.s
= strdup("<<");
601 tok
->type
= ISL_TOKEN_LEX_LT
;
603 tok
->u
.s
= strdup("<");
604 tok
->type
= ISL_TOKEN_LT
;
607 isl_stream_ungetc(s
, c
);
611 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
614 tok
->type
= ISL_TOKEN_AND
;
615 if ((c
= isl_stream_getc(s
)) != '&' && c
!= -1) {
616 tok
->u
.s
= strdup("&");
617 isl_stream_ungetc(s
, c
);
619 tok
->u
.s
= strdup("&&");
623 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
626 tok
->type
= ISL_TOKEN_OR
;
627 if ((c
= isl_stream_getc(s
)) != '|' && c
!= -1) {
628 tok
->u
.s
= strdup("|");
629 isl_stream_ungetc(s
, c
);
631 tok
->u
.s
= strdup("||");
635 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
638 if ((c
= isl_stream_getc(s
)) == '\\') {
639 tok
->u
.s
= strdup("/\\");
640 tok
->type
= ISL_TOKEN_AND
;
642 } else if (c
== '/') {
643 tok
->u
.s
= strdup("//");
644 tok
->type
= ISL_TOKEN_INT_DIV
;
647 tok
->type
= (enum isl_token_type
) '/';
650 isl_stream_ungetc(s
, c
);
654 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
657 if ((c
= isl_stream_getc(s
)) != '/' && c
!= -1) {
658 tok
->type
= (enum isl_token_type
) '\\';
659 isl_stream_ungetc(s
, c
);
661 tok
->u
.s
= strdup("\\/");
662 tok
->type
= ISL_TOKEN_OR
;
667 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
670 if ((c
= isl_stream_getc(s
)) == '=') {
671 tok
->u
.s
= strdup("!=");
672 tok
->type
= ISL_TOKEN_NE
;
675 tok
->type
= ISL_TOKEN_NOT
;
676 tok
->u
.s
= strdup("!");
679 isl_stream_ungetc(s
, c
);
683 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
686 tok
->type
= ISL_TOKEN_UNKNOWN
;
693 struct isl_token
*isl_stream_next_token(__isl_keep isl_stream
*s
)
695 return next_token(s
, 0);
698 struct isl_token
*isl_stream_next_token_on_same_line(__isl_keep isl_stream
*s
)
700 return next_token(s
, 1);
703 int isl_stream_eat_if_available(__isl_keep isl_stream
*s
, int type
)
705 struct isl_token
*tok
;
707 tok
= isl_stream_next_token(s
);
710 if (tok
->type
== type
) {
714 isl_stream_push_token(s
, tok
);
718 int isl_stream_next_token_is(__isl_keep isl_stream
*s
, int type
)
720 struct isl_token
*tok
;
723 tok
= isl_stream_next_token(s
);
726 r
= tok
->type
== type
;
727 isl_stream_push_token(s
, tok
);
731 char *isl_stream_read_ident_if_available(__isl_keep isl_stream
*s
)
733 struct isl_token
*tok
;
735 tok
= isl_stream_next_token(s
);
738 if (tok
->type
== ISL_TOKEN_IDENT
) {
739 char *ident
= strdup(tok
->u
.s
);
743 isl_stream_push_token(s
, tok
);
747 int isl_stream_eat(__isl_keep isl_stream
*s
, int type
)
749 struct isl_token
*tok
;
751 tok
= isl_stream_next_token(s
);
754 isl_stream_error(s
, NULL
, "unexpected EOF");
757 if (tok
->type
== type
) {
761 isl_stream_error(s
, tok
, "expecting other token");
766 int isl_stream_is_empty(__isl_keep isl_stream
*s
)
768 struct isl_token
*tok
;
770 tok
= isl_stream_next_token(s
);
775 isl_stream_push_token(s
, tok
);
779 static isl_stat
free_keyword(void **p
, void *user
)
781 struct isl_keyword
*keyword
= *p
;
789 void isl_stream_flush_tokens(__isl_keep isl_stream
*s
)
795 for (i
= 0; i
< s
->n_token
; ++i
)
796 isl_token_free(s
->tokens
[i
]);
800 isl_ctx
*isl_stream_get_ctx(__isl_keep isl_stream
*s
)
802 return s
? s
->ctx
: NULL
;
805 void isl_stream_free(__isl_take isl_stream
*s
)
810 if (s
->n_token
!= 0) {
811 struct isl_token
*tok
= isl_stream_next_token(s
);
812 isl_stream_error(s
, tok
, "unexpected token");
816 isl_hash_table_foreach(s
->ctx
, s
->keywords
, &free_keyword
, NULL
);
817 isl_hash_table_free(s
->ctx
, s
->keywords
);
820 free(s
->yaml_indent
);
821 isl_ctx_deref(s
->ctx
);
825 /* Push "state" onto the stack of currently active YAML elements.
826 * The caller is responsible for setting the corresponding indentation.
827 * Return 0 on success and -1 on failure.
829 static int push_state(__isl_keep isl_stream
*s
, enum isl_yaml_state state
)
831 if (s
->yaml_size
< s
->yaml_depth
+ 1) {
833 enum isl_yaml_state
*state
;
835 state
= isl_realloc_array(s
->ctx
, s
->yaml_state
,
836 enum isl_yaml_state
, s
->yaml_depth
+ 1);
839 s
->yaml_state
= state
;
841 indent
= isl_realloc_array(s
->ctx
, s
->yaml_indent
,
842 int, s
->yaml_depth
+ 1);
845 s
->yaml_indent
= indent
;
847 s
->yaml_size
= s
->yaml_depth
+ 1;
850 s
->yaml_state
[s
->yaml_depth
] = state
;
856 /* Remove the innermost active YAML element from the stack.
857 * Return isl_stat_ok on success and isl_stat_error on failure.
859 static isl_stat
pop_state(__isl_keep isl_stream
*s
)
862 return isl_stat_error
;
863 if (s
->yaml_depth
< 1)
864 isl_die(isl_stream_get_ctx(s
), isl_error_invalid
,
865 "not in YAML construct", return isl_stat_error
);
872 /* Set the state of the innermost active YAML element to "state".
873 * Return 0 on success and -1 on failure.
875 static int update_state(__isl_keep isl_stream
*s
, enum isl_yaml_state state
)
879 if (s
->yaml_depth
< 1)
880 isl_die(isl_stream_get_ctx(s
), isl_error_invalid
,
881 "not in YAML construct", return -1);
883 s
->yaml_state
[s
->yaml_depth
- 1] = state
;
888 /* Return the state of the innermost active YAML element.
889 * Return isl_yaml_none if we are not inside any YAML element.
891 static enum isl_yaml_state
current_state(__isl_keep isl_stream
*s
)
894 return isl_yaml_none
;
895 if (s
->yaml_depth
< 1)
896 return isl_yaml_none
;
897 return s
->yaml_state
[s
->yaml_depth
- 1];
900 /* Set the indentation of the innermost active YAML element to "indent".
901 * If "indent" is equal to ISL_YAML_INDENT_FLOW, then this means
902 * that the current element is in flow format.
904 static isl_stat
set_yaml_indent(__isl_keep isl_stream
*s
, int indent
)
906 if (s
->yaml_depth
< 1)
907 isl_die(s
->ctx
, isl_error_internal
,
908 "not in YAML element", return isl_stat_error
);
910 s
->yaml_indent
[s
->yaml_depth
- 1] = indent
;
915 /* Return the indentation of the innermost active YAML element
918 static int get_yaml_indent(__isl_keep isl_stream
*s
)
920 if (s
->yaml_depth
< 1)
921 isl_die(s
->ctx
, isl_error_internal
,
922 "not in YAML element", return -1);
924 return s
->yaml_indent
[s
->yaml_depth
- 1];
927 /* Move to the next state at the innermost level.
928 * Return isl_bool_true if successful.
929 * Return isl_bool_false if we are at the end of the innermost level.
930 * Return isl_bool_error on error.
932 * If we are in state isl_yaml_mapping_key_start, then we have just
933 * started a mapping and we are expecting a key. If the mapping started
934 * with a '{', then we check if the next token is a '}'. If so,
935 * then the mapping is empty and there is no next state at this level.
936 * Otherwise, we assume that there is at least one key (the one from
937 * which we derived the indentation in isl_stream_yaml_read_start_mapping.
939 * If we are in state isl_yaml_mapping_key, then the we expect a colon
940 * followed by a value, so there is always a next state unless
943 * If we are in state isl_yaml_mapping_val, then there may or may
944 * not be a subsequent key in the same mapping.
945 * In flow format, the next key is preceded by a comma.
946 * In block format, the next key has the same indentation as the first key.
947 * If the first token has a smaller indentation, then we have reached
948 * the end of the current mapping.
950 * If we are in state isl_yaml_sequence_start, then we have just
951 * started a sequence. If the sequence started with a '[',
952 * then we check if the next token is a ']'. If so, then the sequence
953 * is empty and there is no next state at this level.
954 * Otherwise, we assume that there is at least one element in the sequence
955 * (the one from which we derived the indentation in
956 * isl_stream_yaml_read_start_sequence.
958 * If we are in state isl_yaml_sequence, then there may or may
959 * not be a subsequent element in the same sequence.
960 * In flow format, the next element is preceded by a comma.
961 * In block format, the next element is introduced by a dash with
962 * the same indentation as that of the first element.
963 * If the first token is not a dash or if it has a smaller indentation,
964 * then we have reached the end of the current sequence.
966 isl_bool
isl_stream_yaml_next(__isl_keep isl_stream
*s
)
968 struct isl_token
*tok
;
969 enum isl_yaml_state state
;
972 state
= current_state(s
);
973 if (state
== isl_yaml_none
)
974 isl_die(s
->ctx
, isl_error_invalid
,
975 "not in YAML element", return isl_bool_error
);
977 case isl_yaml_mapping_key_start
:
978 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
&&
979 isl_stream_next_token_is(s
, '}'))
980 return isl_bool_false
;
981 if (update_state(s
, isl_yaml_mapping_key
) < 0)
982 return isl_bool_error
;
983 return isl_bool_true
;
984 case isl_yaml_mapping_key
:
985 tok
= isl_stream_next_token(s
);
988 isl_stream_error(s
, NULL
, "unexpected EOF");
989 return isl_bool_error
;
991 if (tok
->type
== ':') {
993 if (update_state(s
, isl_yaml_mapping_val
) < 0)
994 return isl_bool_error
;
995 return isl_bool_true
;
997 isl_stream_error(s
, tok
, "expecting ':'");
998 isl_stream_push_token(s
, tok
);
999 return isl_bool_error
;
1000 case isl_yaml_mapping_val
:
1001 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
) {
1002 if (!isl_stream_eat_if_available(s
, ','))
1003 return isl_bool_false
;
1004 if (update_state(s
, isl_yaml_mapping_key
) < 0)
1005 return isl_bool_error
;
1006 return isl_bool_true
;
1008 tok
= isl_stream_next_token(s
);
1010 return isl_bool_false
;
1011 indent
= tok
->col
- 1;
1012 isl_stream_push_token(s
, tok
);
1013 if (indent
< get_yaml_indent(s
))
1014 return isl_bool_false
;
1015 if (update_state(s
, isl_yaml_mapping_key
) < 0)
1016 return isl_bool_error
;
1017 return isl_bool_true
;
1018 case isl_yaml_sequence_start
:
1019 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
) {
1020 if (isl_stream_next_token_is(s
, ']'))
1021 return isl_bool_false
;
1022 if (update_state(s
, isl_yaml_sequence
) < 0)
1023 return isl_bool_error
;
1024 return isl_bool_true
;
1026 tok
= isl_stream_next_token(s
);
1029 isl_stream_error(s
, NULL
, "unexpected EOF");
1030 return isl_bool_error
;
1032 if (tok
->type
== '-') {
1033 isl_token_free(tok
);
1034 if (update_state(s
, isl_yaml_sequence
) < 0)
1035 return isl_bool_error
;
1036 return isl_bool_true
;
1038 isl_stream_error(s
, tok
, "expecting '-'");
1039 isl_stream_push_token(s
, tok
);
1040 return isl_bool_false
;
1041 case isl_yaml_sequence
:
1042 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
)
1043 return isl_bool_ok(isl_stream_eat_if_available(s
, ','));
1044 tok
= isl_stream_next_token(s
);
1046 return isl_bool_false
;
1047 indent
= tok
->col
- 1;
1048 if (indent
< get_yaml_indent(s
) || tok
->type
!= '-') {
1049 isl_stream_push_token(s
, tok
);
1050 return isl_bool_false
;
1052 isl_token_free(tok
);
1053 return isl_bool_true
;
1055 isl_die(s
->ctx
, isl_error_internal
,
1056 "unexpected state", return isl_bool_error
);
1060 /* Start reading a YAML mapping.
1061 * Return isl_stat_ok on success and isl_stat_error on error.
1063 * If the first token on the stream is a '{' then we remove this token
1064 * from the stream and keep track of the fact that the mapping
1065 * is given in flow format.
1066 * Otherwise, we assume the first token is the first key of the mapping and
1067 * keep track of its indentation, but keep the token on the stream.
1068 * In both cases, the next token we expect is the first key of the mapping.
1070 isl_stat
isl_stream_yaml_read_start_mapping(__isl_keep isl_stream
*s
)
1072 struct isl_token
*tok
;
1075 if (push_state(s
, isl_yaml_mapping_key_start
) < 0)
1076 return isl_stat_error
;
1078 tok
= isl_stream_next_token(s
);
1081 isl_stream_error(s
, NULL
, "unexpected EOF");
1082 return isl_stat_error
;
1084 if (isl_token_get_type(tok
) == '{') {
1085 isl_token_free(tok
);
1086 return set_yaml_indent(s
, ISL_YAML_INDENT_FLOW
);
1088 indent
= tok
->col
- 1;
1089 isl_stream_push_token(s
, tok
);
1091 return set_yaml_indent(s
, indent
);
1094 /* Finish reading a YAML mapping.
1095 * Return isl_stat_ok on success and isl_stat_error on error.
1097 * If the mapping started with a '{', then we expect a '}' to close
1099 * Otherwise, we double-check that the next token (if any)
1100 * has a smaller indentation than that of the current mapping.
1102 isl_stat
isl_stream_yaml_read_end_mapping(__isl_keep isl_stream
*s
)
1104 struct isl_token
*tok
;
1107 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
) {
1108 if (isl_stream_eat(s
, '}') < 0)
1109 return isl_stat_error
;
1110 return pop_state(s
);
1113 tok
= isl_stream_next_token(s
);
1115 return pop_state(s
);
1117 indent
= tok
->col
- 1;
1118 isl_stream_push_token(s
, tok
);
1120 if (indent
>= get_yaml_indent(s
))
1121 isl_die(isl_stream_get_ctx(s
), isl_error_invalid
,
1122 "mapping not finished", return isl_stat_error
);
1124 return pop_state(s
);
1127 /* Start reading a YAML sequence.
1128 * Return isl_stat_ok on success and isl_stat_error on error.
1130 * If the first token on the stream is a '[' then we remove this token
1131 * from the stream and keep track of the fact that the sequence
1132 * is given in flow format.
1133 * Otherwise, we assume the first token is the dash that introduces
1134 * the first element of the sequence and keep track of its indentation,
1135 * but keep the token on the stream.
1136 * In both cases, the next token we expect is the first element
1139 isl_stat
isl_stream_yaml_read_start_sequence(__isl_keep isl_stream
*s
)
1141 struct isl_token
*tok
;
1144 if (push_state(s
, isl_yaml_sequence_start
) < 0)
1145 return isl_stat_error
;
1147 tok
= isl_stream_next_token(s
);
1150 isl_stream_error(s
, NULL
, "unexpected EOF");
1151 return isl_stat_error
;
1153 if (isl_token_get_type(tok
) == '[') {
1154 isl_token_free(tok
);
1155 return set_yaml_indent(s
, ISL_YAML_INDENT_FLOW
);
1157 indent
= tok
->col
- 1;
1158 isl_stream_push_token(s
, tok
);
1160 return set_yaml_indent(s
, indent
);
1163 /* Finish reading a YAML sequence.
1164 * Return isl_stat_ok on success and isl_stat_error on error.
1166 * If the sequence started with a '[', then we expect a ']' to close
1168 * Otherwise, we double-check that the next token (if any)
1169 * is not a dash or that it has a smaller indentation than
1170 * that of the current sequence.
1172 isl_stat
isl_stream_yaml_read_end_sequence(__isl_keep isl_stream
*s
)
1174 struct isl_token
*tok
;
1178 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
) {
1179 if (isl_stream_eat(s
, ']') < 0)
1180 return isl_stat_error
;
1181 return pop_state(s
);
1184 tok
= isl_stream_next_token(s
);
1186 return pop_state(s
);
1188 indent
= tok
->col
- 1;
1189 dash
= tok
->type
== '-';
1190 isl_stream_push_token(s
, tok
);
1192 if (indent
>= get_yaml_indent(s
) && dash
)
1193 isl_die(isl_stream_get_ctx(s
), isl_error_invalid
,
1194 "sequence not finished", return isl_stat_error
);
1196 return pop_state(s
);