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 /* Given a token with a string representation, return a copy of this string.
106 __isl_give
char *isl_token_get_str(isl_ctx
*ctx
, struct isl_token
*tok
)
111 isl_die(ctx
, isl_error_invalid
,
112 "token does not have a string representation",
115 return strdup(tok
->u
.s
);
118 void isl_token_free(struct isl_token
*tok
)
122 if (tok
->type
== ISL_TOKEN_VALUE
)
123 isl_int_clear(tok
->u
.v
);
124 else if (tok
->type
== ISL_TOKEN_MAP
)
125 isl_map_free(tok
->u
.map
);
126 else if (tok
->type
== ISL_TOKEN_AFF
)
127 isl_pw_aff_free(tok
->u
.pwaff
);
133 void isl_stream_error(__isl_keep isl_stream
*s
, struct isl_token
*tok
,
136 int line
= tok
? tok
->line
: s
->line
;
137 int col
= tok
? tok
->col
: s
->col
;
139 isl_ctx_set_full_error(s
->ctx
, isl_error_invalid
, "syntax error",
142 if (s
->ctx
->opt
->on_error
== ISL_ON_ERROR_CONTINUE
)
144 fprintf(stderr
, "syntax error (%d, %d): %s\n", line
, col
, msg
);
147 fprintf(stderr
, "got '%c'\n", tok
->type
);
148 else if (tok
->type
== ISL_TOKEN_IDENT
)
149 fprintf(stderr
, "got ident '%s'\n", tok
->u
.s
);
150 else if (tok
->is_keyword
)
151 fprintf(stderr
, "got keyword '%s'\n", tok
->u
.s
);
152 else if (tok
->type
== ISL_TOKEN_VALUE
) {
153 fprintf(stderr
, "got value '");
154 isl_int_print(stderr
, tok
->u
.v
, 0);
155 fprintf(stderr
, "'\n");
156 } else if (tok
->type
== ISL_TOKEN_MAP
) {
158 fprintf(stderr
, "got map '");
159 p
= isl_printer_to_file(s
->ctx
, stderr
);
160 p
= isl_printer_print_map(p
, tok
->u
.map
);
162 fprintf(stderr
, "'\n");
163 } else if (tok
->type
== ISL_TOKEN_AFF
) {
165 fprintf(stderr
, "got affine expression '");
166 p
= isl_printer_to_file(s
->ctx
, stderr
);
167 p
= isl_printer_print_pw_aff(p
, tok
->u
.pwaff
);
169 fprintf(stderr
, "'\n");
171 fprintf(stderr
, "got token '%s'\n", tok
->u
.s
);
173 fprintf(stderr
, "got token type %d\n", tok
->type
);
175 if (s
->ctx
->opt
->on_error
== ISL_ON_ERROR_ABORT
)
179 static __isl_give isl_stream
* isl_stream_new(struct isl_ctx
*ctx
)
182 isl_stream
*s
= isl_calloc_type(ctx
, struct isl_stream
);
196 for (i
= 0; i
< 5; ++i
)
201 s
->buffer
= isl_alloc_array(ctx
, char, s
->size
);
210 __isl_give isl_stream
* isl_stream_new_file(struct isl_ctx
*ctx
, FILE *file
)
212 isl_stream
*s
= isl_stream_new(ctx
);
219 __isl_give isl_stream
* isl_stream_new_str(struct isl_ctx
*ctx
, const char *str
)
224 s
= isl_stream_new(ctx
);
231 /* Read a character from the stream and advance s->line and s->col
232 * to point to the next character.
234 static int stream_getc(__isl_keep isl_stream
*s
)
240 return s
->c
= s
->un
[--s
->n_un
];
250 else if (c
== '\n') {
259 static void isl_stream_ungetc(__isl_keep isl_stream
*s
, int c
)
261 isl_assert(s
->ctx
, s
->n_un
< 5, return);
262 s
->un
[s
->n_un
++] = c
;
266 /* Read a character from the stream, skipping pairs of '\\' and '\n'.
267 * Set s->start_line and s->start_col to the line and column
268 * of the returned character.
270 static int isl_stream_getc(__isl_keep isl_stream
*s
)
275 s
->start_line
= s
->line
;
276 s
->start_col
= s
->col
;
283 isl_stream_ungetc(s
, c
);
288 static int isl_stream_push_char(__isl_keep isl_stream
*s
, int c
)
290 if (s
->len
>= s
->size
) {
292 s
->size
= (3*s
->size
)/2;
293 buffer
= isl_realloc_array(s
->ctx
, s
->buffer
, char, s
->size
);
298 s
->buffer
[s
->len
++] = c
;
302 void isl_stream_push_token(__isl_keep isl_stream
*s
, struct isl_token
*tok
)
304 isl_assert(s
->ctx
, s
->n_token
< 5, return);
305 s
->tokens
[s
->n_token
++] = tok
;
308 static enum isl_token_type
check_keywords(__isl_keep isl_stream
*s
)
310 struct isl_hash_table_entry
*entry
;
311 struct isl_keyword
*keyword
;
314 if (!strcasecmp(s
->buffer
, "exists"))
315 return ISL_TOKEN_EXISTS
;
316 if (!strcasecmp(s
->buffer
, "and"))
317 return ISL_TOKEN_AND
;
318 if (!strcasecmp(s
->buffer
, "or"))
320 if (!strcasecmp(s
->buffer
, "implies"))
321 return ISL_TOKEN_IMPLIES
;
322 if (!strcasecmp(s
->buffer
, "not"))
323 return ISL_TOKEN_NOT
;
324 if (!strcasecmp(s
->buffer
, "infty"))
325 return ISL_TOKEN_INFTY
;
326 if (!strcasecmp(s
->buffer
, "infinity"))
327 return ISL_TOKEN_INFTY
;
328 if (!strcasecmp(s
->buffer
, "NaN"))
329 return ISL_TOKEN_NAN
;
330 if (!strcasecmp(s
->buffer
, "min"))
331 return ISL_TOKEN_MIN
;
332 if (!strcasecmp(s
->buffer
, "max"))
333 return ISL_TOKEN_MAX
;
334 if (!strcasecmp(s
->buffer
, "rat"))
335 return ISL_TOKEN_RAT
;
336 if (!strcasecmp(s
->buffer
, "true"))
337 return ISL_TOKEN_TRUE
;
338 if (!strcasecmp(s
->buffer
, "false"))
339 return ISL_TOKEN_FALSE
;
340 if (!strcasecmp(s
->buffer
, "ceild"))
341 return ISL_TOKEN_CEILD
;
342 if (!strcasecmp(s
->buffer
, "floord"))
343 return ISL_TOKEN_FLOORD
;
344 if (!strcasecmp(s
->buffer
, "mod"))
345 return ISL_TOKEN_MOD
;
346 if (!strcasecmp(s
->buffer
, "ceil"))
347 return ISL_TOKEN_CEIL
;
348 if (!strcasecmp(s
->buffer
, "floor"))
349 return ISL_TOKEN_FLOOR
;
352 return ISL_TOKEN_IDENT
;
354 name_hash
= isl_hash_string(isl_hash_init(), s
->buffer
);
355 entry
= isl_hash_table_find(s
->ctx
, s
->keywords
, name_hash
, same_name
,
358 return ISL_TOKEN_ERROR
;
359 if (entry
!= isl_hash_table_entry_none
) {
360 keyword
= entry
->data
;
361 return keyword
->type
;
364 return ISL_TOKEN_IDENT
;
367 int isl_stream_skip_line(__isl_keep isl_stream
*s
)
371 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '\n')
375 return c
== -1 ? -1 : 0;
378 static struct isl_token
*next_token(__isl_keep isl_stream
*s
, int same_line
)
381 struct isl_token
*tok
= NULL
;
383 int old_line
= s
->last_line
;
386 if (same_line
&& s
->tokens
[s
->n_token
- 1]->on_new_line
)
388 return s
->tokens
[--s
->n_token
];
391 if (same_line
&& s
->c
== '\n')
396 /* skip spaces and comment lines */
397 while ((c
= isl_stream_getc(s
)) != -1) {
399 if (isl_stream_skip_line(s
) < 0)
404 } else if (!isspace(c
) || (same_line
&& c
== '\n'))
408 line
= s
->start_line
;
411 if (c
== -1 || (same_line
&& c
== '\n'))
431 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
434 tok
->type
= (enum isl_token_type
)c
;
439 if ((c
= isl_stream_getc(s
)) == '>') {
440 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
443 tok
->u
.s
= strdup("->");
444 tok
->type
= ISL_TOKEN_TO
;
448 isl_stream_ungetc(s
, c
);
450 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
453 tok
->type
= (enum isl_token_type
) '-';
457 if (c
== '-' || isdigit(c
)) {
458 int minus
= c
== '-';
459 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
462 tok
->type
= ISL_TOKEN_VALUE
;
463 isl_int_init(tok
->u
.v
);
464 if (isl_stream_push_char(s
, c
))
466 while ((c
= isl_stream_getc(s
)) != -1 && isdigit(c
))
467 if (isl_stream_push_char(s
, c
))
470 isl_stream_ungetc(s
, c
);
471 isl_stream_push_char(s
, '\0');
472 isl_int_read(tok
->u
.v
, s
->buffer
);
473 if (minus
&& isl_int_is_zero(tok
->u
.v
)) {
475 tok
->on_new_line
= 0;
476 isl_stream_push_token(s
, tok
);
477 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
480 tok
->type
= (enum isl_token_type
) '-';
484 if (isalpha(c
) || c
== '_') {
485 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
488 isl_stream_push_char(s
, c
);
489 while ((c
= isl_stream_getc(s
)) != -1 &&
490 (isalnum(c
) || c
== '_'))
491 isl_stream_push_char(s
, c
);
493 isl_stream_ungetc(s
, c
);
494 while ((c
= isl_stream_getc(s
)) != -1 && c
== '\'')
495 isl_stream_push_char(s
, c
);
497 isl_stream_ungetc(s
, c
);
498 isl_stream_push_char(s
, '\0');
499 tok
->type
= check_keywords(s
);
500 if (tok
->type
!= ISL_TOKEN_IDENT
)
502 tok
->u
.s
= strdup(s
->buffer
);
508 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
511 tok
->type
= ISL_TOKEN_STRING
;
513 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '"' && c
!= '\n')
514 isl_stream_push_char(s
, c
);
516 isl_stream_error(s
, NULL
, "unterminated string");
519 isl_stream_push_char(s
, '\0');
520 tok
->u
.s
= strdup(s
->buffer
);
525 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
528 if ((c
= isl_stream_getc(s
)) == '=') {
529 tok
->u
.s
= strdup("==");
530 tok
->type
= ISL_TOKEN_EQ_EQ
;
534 isl_stream_ungetc(s
, c
);
535 tok
->type
= (enum isl_token_type
) '=';
540 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
543 if ((c
= isl_stream_getc(s
)) == '=') {
544 tok
->u
.s
= strdup(":=");
545 tok
->type
= ISL_TOKEN_DEF
;
549 isl_stream_ungetc(s
, c
);
550 tok
->type
= (enum isl_token_type
) ':';
555 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
558 if ((c
= isl_stream_getc(s
)) == '=') {
559 tok
->u
.s
= strdup(">=");
560 tok
->type
= ISL_TOKEN_GE
;
562 } else if (c
== '>') {
563 if ((c
= isl_stream_getc(s
)) == '=') {
564 tok
->u
.s
= strdup(">>=");
565 tok
->type
= ISL_TOKEN_LEX_GE
;
568 tok
->u
.s
= strdup(">>");
569 tok
->type
= ISL_TOKEN_LEX_GT
;
571 tok
->u
.s
= strdup(">");
572 tok
->type
= ISL_TOKEN_GT
;
575 isl_stream_ungetc(s
, c
);
580 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
583 if ((c
= isl_stream_getc(s
)) == '=') {
584 tok
->u
.s
= strdup("<=");
585 tok
->type
= ISL_TOKEN_LE
;
587 } else if (c
== '<') {
588 if ((c
= isl_stream_getc(s
)) == '=') {
589 tok
->u
.s
= strdup("<<=");
590 tok
->type
= ISL_TOKEN_LEX_LE
;
593 tok
->u
.s
= strdup("<<");
594 tok
->type
= ISL_TOKEN_LEX_LT
;
596 tok
->u
.s
= strdup("<");
597 tok
->type
= ISL_TOKEN_LT
;
600 isl_stream_ungetc(s
, c
);
604 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
607 tok
->type
= ISL_TOKEN_AND
;
608 if ((c
= isl_stream_getc(s
)) != '&' && c
!= -1) {
609 tok
->u
.s
= strdup("&");
610 isl_stream_ungetc(s
, c
);
612 tok
->u
.s
= strdup("&&");
616 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
619 tok
->type
= ISL_TOKEN_OR
;
620 if ((c
= isl_stream_getc(s
)) != '|' && c
!= -1) {
621 tok
->u
.s
= strdup("|");
622 isl_stream_ungetc(s
, c
);
624 tok
->u
.s
= strdup("||");
628 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
631 if ((c
= isl_stream_getc(s
)) == '\\') {
632 tok
->u
.s
= strdup("/\\");
633 tok
->type
= ISL_TOKEN_AND
;
635 } else if (c
== '/') {
636 tok
->u
.s
= strdup("//");
637 tok
->type
= ISL_TOKEN_INT_DIV
;
640 tok
->type
= (enum isl_token_type
) '/';
643 isl_stream_ungetc(s
, c
);
647 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
650 if ((c
= isl_stream_getc(s
)) != '/' && c
!= -1) {
651 tok
->type
= (enum isl_token_type
) '\\';
652 isl_stream_ungetc(s
, c
);
654 tok
->u
.s
= strdup("\\/");
655 tok
->type
= ISL_TOKEN_OR
;
660 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
663 if ((c
= isl_stream_getc(s
)) == '=') {
664 tok
->u
.s
= strdup("!=");
665 tok
->type
= ISL_TOKEN_NE
;
668 tok
->type
= ISL_TOKEN_NOT
;
669 tok
->u
.s
= strdup("!");
672 isl_stream_ungetc(s
, c
);
676 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
679 tok
->type
= ISL_TOKEN_UNKNOWN
;
686 struct isl_token
*isl_stream_next_token(__isl_keep isl_stream
*s
)
688 return next_token(s
, 0);
691 struct isl_token
*isl_stream_next_token_on_same_line(__isl_keep isl_stream
*s
)
693 return next_token(s
, 1);
696 int isl_stream_eat_if_available(__isl_keep isl_stream
*s
, int type
)
698 struct isl_token
*tok
;
700 tok
= isl_stream_next_token(s
);
703 if (tok
->type
== type
) {
707 isl_stream_push_token(s
, tok
);
711 int isl_stream_next_token_is(__isl_keep isl_stream
*s
, int type
)
713 struct isl_token
*tok
;
716 tok
= isl_stream_next_token(s
);
719 r
= tok
->type
== type
;
720 isl_stream_push_token(s
, tok
);
724 char *isl_stream_read_ident_if_available(__isl_keep isl_stream
*s
)
726 struct isl_token
*tok
;
728 tok
= isl_stream_next_token(s
);
731 if (tok
->type
== ISL_TOKEN_IDENT
) {
732 char *ident
= strdup(tok
->u
.s
);
736 isl_stream_push_token(s
, tok
);
740 int isl_stream_eat(__isl_keep isl_stream
*s
, int type
)
742 struct isl_token
*tok
;
744 tok
= isl_stream_next_token(s
);
747 isl_stream_error(s
, NULL
, "unexpected EOF");
750 if (tok
->type
== type
) {
754 isl_stream_error(s
, tok
, "expecting other token");
755 isl_stream_push_token(s
, tok
);
759 int isl_stream_is_empty(__isl_keep isl_stream
*s
)
761 struct isl_token
*tok
;
763 tok
= isl_stream_next_token(s
);
768 isl_stream_push_token(s
, tok
);
772 static isl_stat
free_keyword(void **p
, void *user
)
774 struct isl_keyword
*keyword
= *p
;
782 void isl_stream_flush_tokens(__isl_keep isl_stream
*s
)
788 for (i
= 0; i
< s
->n_token
; ++i
)
789 isl_token_free(s
->tokens
[i
]);
793 isl_ctx
*isl_stream_get_ctx(__isl_keep isl_stream
*s
)
795 return s
? s
->ctx
: NULL
;
798 void isl_stream_free(__isl_take isl_stream
*s
)
803 if (s
->n_token
!= 0) {
804 struct isl_token
*tok
= isl_stream_next_token(s
);
805 isl_stream_error(s
, tok
, "unexpected token");
809 isl_hash_table_foreach(s
->ctx
, s
->keywords
, &free_keyword
, NULL
);
810 isl_hash_table_free(s
->ctx
, s
->keywords
);
813 free(s
->yaml_indent
);
814 isl_ctx_deref(s
->ctx
);
818 /* Push "state" onto the stack of currently active YAML elements.
819 * The caller is responsible for setting the corresponding indentation.
820 * Return 0 on success and -1 on failure.
822 static int push_state(__isl_keep isl_stream
*s
, enum isl_yaml_state state
)
824 if (s
->yaml_size
< s
->yaml_depth
+ 1) {
826 enum isl_yaml_state
*state
;
828 state
= isl_realloc_array(s
->ctx
, s
->yaml_state
,
829 enum isl_yaml_state
, s
->yaml_depth
+ 1);
832 s
->yaml_state
= state
;
834 indent
= isl_realloc_array(s
->ctx
, s
->yaml_indent
,
835 int, s
->yaml_depth
+ 1);
838 s
->yaml_indent
= indent
;
840 s
->yaml_size
= s
->yaml_depth
+ 1;
843 s
->yaml_state
[s
->yaml_depth
] = state
;
849 /* Remove the innermost active YAML element from the stack.
850 * Return 0 on success and -1 on failure.
852 static int pop_state(__isl_keep isl_stream
*s
)
856 if (s
->yaml_depth
< 1)
857 isl_die(isl_stream_get_ctx(s
), isl_error_invalid
,
858 "not in YAML construct", return -1);
865 /* Set the state of the innermost active YAML element to "state".
866 * Return 0 on success and -1 on failure.
868 static int update_state(__isl_keep isl_stream
*s
, enum isl_yaml_state state
)
872 if (s
->yaml_depth
< 1)
873 isl_die(isl_stream_get_ctx(s
), isl_error_invalid
,
874 "not in YAML construct", return -1);
876 s
->yaml_state
[s
->yaml_depth
- 1] = state
;
881 /* Return the state of the innermost active YAML element.
882 * Return isl_yaml_none if we are not inside any YAML element.
884 static enum isl_yaml_state
current_state(__isl_keep isl_stream
*s
)
887 return isl_yaml_none
;
888 if (s
->yaml_depth
< 1)
889 return isl_yaml_none
;
890 return s
->yaml_state
[s
->yaml_depth
- 1];
893 /* Set the indentation of the innermost active YAML element to "indent".
894 * If "indent" is equal to ISL_YAML_INDENT_FLOW, then this means
895 * that the current elemient is in flow format.
897 static int set_yaml_indent(__isl_keep isl_stream
*s
, int indent
)
899 if (s
->yaml_depth
< 1)
900 isl_die(s
->ctx
, isl_error_internal
,
901 "not in YAML element", return -1);
903 s
->yaml_indent
[s
->yaml_depth
- 1] = indent
;
908 /* Return the indentation of the innermost active YAML element
911 static int get_yaml_indent(__isl_keep isl_stream
*s
)
913 if (s
->yaml_depth
< 1)
914 isl_die(s
->ctx
, isl_error_internal
,
915 "not in YAML element", return -1);
917 return s
->yaml_indent
[s
->yaml_depth
- 1];
920 /* Move to the next state at the innermost level.
921 * Return 1 if successful.
922 * Return 0 if we are at the end of the innermost level.
923 * Return -1 on error.
925 * If we are in state isl_yaml_mapping_key_start, then we have just
926 * started a mapping and we are expecting a key. If the mapping started
927 * with a '{', then we check if the next token is a '}'. If so,
928 * then the mapping is empty and there is no next state at this level.
929 * Otherwise, we assume that there is at least one key (the one from
930 * which we derived the indentation in isl_stream_yaml_read_start_mapping.
932 * If we are in state isl_yaml_mapping_key, then the we expect a colon
933 * followed by a value, so there is always a next state unless
936 * If we are in state isl_yaml_mapping_val, then there may or may
937 * not be a subsequent key in the same mapping.
938 * In flow format, the next key is preceded by a comma.
939 * In block format, the next key has the same indentation as the first key.
940 * If the first token has a smaller indentation, then we have reached
941 * the end of the current mapping.
943 * If we are in state isl_yaml_sequence_start, then we have just
944 * started a sequence. If the sequence started with a '[',
945 * then we check if the next token is a ']'. If so, then the sequence
946 * is empty and there is no next state at this level.
947 * Otherwise, we assume that there is at least one element in the sequence
948 * (the one from which we derived the indentation in
949 * isl_stream_yaml_read_start_sequence.
951 * If we are in state isl_yaml_sequence, then there may or may
952 * not be a subsequent element in the same sequence.
953 * In flow format, the next element is preceded by a comma.
954 * In block format, the next element is introduced by a dash with
955 * the same indentation as that of the first element.
956 * If the first token is not a dash or if it has a smaller indentation,
957 * then we have reached the end of the current sequence.
959 int isl_stream_yaml_next(__isl_keep isl_stream
*s
)
961 struct isl_token
*tok
;
962 enum isl_yaml_state state
;
965 state
= current_state(s
);
966 if (state
== isl_yaml_none
)
967 isl_die(s
->ctx
, isl_error_invalid
,
968 "not in YAML element", return -1);
970 case isl_yaml_mapping_key_start
:
971 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
&&
972 isl_stream_next_token_is(s
, '}'))
974 if (update_state(s
, isl_yaml_mapping_key
) < 0)
977 case isl_yaml_mapping_key
:
978 tok
= isl_stream_next_token(s
);
981 isl_stream_error(s
, NULL
, "unexpected EOF");
984 if (tok
->type
== ':') {
986 if (update_state(s
, isl_yaml_mapping_val
) < 0)
990 isl_stream_error(s
, tok
, "expecting ':'");
991 isl_stream_push_token(s
, tok
);
993 case isl_yaml_mapping_val
:
994 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
) {
995 if (!isl_stream_eat_if_available(s
, ','))
997 if (update_state(s
, isl_yaml_mapping_key
) < 0)
1001 tok
= isl_stream_next_token(s
);
1004 indent
= tok
->col
- 1;
1005 isl_stream_push_token(s
, tok
);
1006 if (indent
< get_yaml_indent(s
))
1008 if (update_state(s
, isl_yaml_mapping_key
) < 0)
1011 case isl_yaml_sequence_start
:
1012 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
) {
1013 if (isl_stream_next_token_is(s
, ']'))
1015 if (update_state(s
, isl_yaml_sequence
) < 0)
1019 tok
= isl_stream_next_token(s
);
1022 isl_stream_error(s
, NULL
, "unexpected EOF");
1025 if (tok
->type
== '-') {
1026 isl_token_free(tok
);
1027 if (update_state(s
, isl_yaml_sequence
) < 0)
1031 isl_stream_error(s
, tok
, "expecting '-'");
1032 isl_stream_push_token(s
, tok
);
1034 case isl_yaml_sequence
:
1035 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
)
1036 return isl_stream_eat_if_available(s
, ',');
1037 tok
= isl_stream_next_token(s
);
1040 indent
= tok
->col
- 1;
1041 if (indent
< get_yaml_indent(s
) || tok
->type
!= '-') {
1042 isl_stream_push_token(s
, tok
);
1045 isl_token_free(tok
);
1048 isl_die(s
->ctx
, isl_error_internal
,
1049 "unexpected state", return 0);
1053 /* Start reading a YAML mapping.
1054 * Return 0 on success and -1 on error.
1056 * If the first token on the stream is a '{' then we remove this token
1057 * from the stream and keep track of the fact that the mapping
1058 * is given in flow format.
1059 * Otherwise, we assume the first token is the first key of the mapping and
1060 * keep track of its indentation, but keep the token on the stream.
1061 * In both cases, the next token we expect is the first key of the mapping.
1063 int isl_stream_yaml_read_start_mapping(__isl_keep isl_stream
*s
)
1065 struct isl_token
*tok
;
1068 if (push_state(s
, isl_yaml_mapping_key_start
) < 0)
1071 tok
= isl_stream_next_token(s
);
1074 isl_stream_error(s
, NULL
, "unexpected EOF");
1077 if (isl_token_get_type(tok
) == '{') {
1078 isl_token_free(tok
);
1079 return set_yaml_indent(s
, ISL_YAML_INDENT_FLOW
);
1081 indent
= tok
->col
- 1;
1082 isl_stream_push_token(s
, tok
);
1084 return set_yaml_indent(s
, indent
);
1087 /* Finish reading a YAML mapping.
1088 * Return 0 on success and -1 on error.
1090 * If the mapping started with a '{', then we expect a '}' to close
1092 * Otherwise, we double-check that the next token (if any)
1093 * has a smaller indentation than that of the current mapping.
1095 int isl_stream_yaml_read_end_mapping(__isl_keep isl_stream
*s
)
1097 struct isl_token
*tok
;
1100 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
) {
1101 if (isl_stream_eat(s
, '}') < 0)
1103 return pop_state(s
);
1106 tok
= isl_stream_next_token(s
);
1108 return pop_state(s
);
1110 indent
= tok
->col
- 1;
1111 isl_stream_push_token(s
, tok
);
1113 if (indent
>= get_yaml_indent(s
))
1114 isl_die(isl_stream_get_ctx(s
), isl_error_invalid
,
1115 "mapping not finished", return -1);
1117 return pop_state(s
);
1120 /* Start reading a YAML sequence.
1121 * Return 0 on success and -1 on error.
1123 * If the first token on the stream is a '[' then we remove this token
1124 * from the stream and keep track of the fact that the sequence
1125 * is given in flow format.
1126 * Otherwise, we assume the first token is the dash that introduces
1127 * the first element of the sequence and keep track of its indentation,
1128 * but keep the token on the stream.
1129 * In both cases, the next token we expect is the first element
1132 int isl_stream_yaml_read_start_sequence(__isl_keep isl_stream
*s
)
1134 struct isl_token
*tok
;
1137 if (push_state(s
, isl_yaml_sequence_start
) < 0)
1140 tok
= isl_stream_next_token(s
);
1143 isl_stream_error(s
, NULL
, "unexpected EOF");
1146 if (isl_token_get_type(tok
) == '[') {
1147 isl_token_free(tok
);
1148 return set_yaml_indent(s
, ISL_YAML_INDENT_FLOW
);
1150 indent
= tok
->col
- 1;
1151 isl_stream_push_token(s
, tok
);
1153 return set_yaml_indent(s
, indent
);
1156 /* Finish reading a YAML sequence.
1157 * Return 0 on success and -1 on error.
1159 * If the sequence started with a '[', then we expect a ']' to close
1161 * Otherwise, we double-check that the next token (if any)
1162 * is not a dash or that it has a smaller indentation than
1163 * that of the current sequence.
1165 int isl_stream_yaml_read_end_sequence(__isl_keep isl_stream
*s
)
1167 struct isl_token
*tok
;
1171 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
) {
1172 if (isl_stream_eat(s
, ']') < 0)
1174 return pop_state(s
);
1177 tok
= isl_stream_next_token(s
);
1179 return pop_state(s
);
1181 indent
= tok
->col
- 1;
1182 dash
= tok
->type
== '-';
1183 isl_stream_push_token(s
, tok
);
1185 if (indent
>= get_yaml_indent(s
) && dash
)
1186 isl_die(isl_stream_get_ctx(s
), isl_error_invalid
,
1187 "sequence not finished", return -1);
1189 return pop_state(s
);