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
13 #include <isl_stream_private.h>
16 #include <isl_val_private.h>
20 enum isl_token_type type
;
23 static isl_bool
same_name(const void *entry
, const void *val
)
25 const struct isl_keyword
*keyword
= (const struct isl_keyword
*)entry
;
27 return isl_bool_ok(!strcmp(keyword
->name
, val
));
30 enum isl_token_type
isl_stream_register_keyword(__isl_keep isl_stream
*s
,
33 struct isl_hash_table_entry
*entry
;
34 struct isl_keyword
*keyword
;
38 s
->keywords
= isl_hash_table_alloc(s
->ctx
, 10);
40 return ISL_TOKEN_ERROR
;
41 s
->next_type
= ISL_TOKEN_LAST
;
44 name_hash
= isl_hash_string(isl_hash_init(), name
);
46 entry
= isl_hash_table_find(s
->ctx
, s
->keywords
, name_hash
,
49 return ISL_TOKEN_ERROR
;
51 keyword
= entry
->data
;
55 keyword
= isl_calloc_type(s
->ctx
, struct isl_keyword
);
57 return ISL_TOKEN_ERROR
;
58 keyword
->type
= s
->next_type
++;
59 keyword
->name
= strdup(name
);
62 return ISL_TOKEN_ERROR
;
64 entry
->data
= keyword
;
69 struct isl_token
*isl_token_new(isl_ctx
*ctx
,
70 int line
, int col
, unsigned on_new_line
)
72 struct isl_token
*tok
= isl_alloc_type(ctx
, struct isl_token
);
77 tok
->on_new_line
= on_new_line
;
83 /* Return the type of "tok".
85 int isl_token_get_type(struct isl_token
*tok
)
87 return tok
? tok
->type
: ISL_TOKEN_ERROR
;
90 /* Given a token of type ISL_TOKEN_VALUE, return the value it represents.
92 __isl_give isl_val
*isl_token_get_val(isl_ctx
*ctx
, struct isl_token
*tok
)
96 if (tok
->type
!= ISL_TOKEN_VALUE
)
97 isl_die(ctx
, isl_error_invalid
, "not a value token",
100 return isl_val_int_from_isl_int(ctx
, tok
->u
.v
);
103 /* Given a token with a string representation, return a copy of this string.
105 __isl_give
char *isl_token_get_str(isl_ctx
*ctx
, struct isl_token
*tok
)
110 isl_die(ctx
, isl_error_invalid
,
111 "token does not have a string representation",
114 return strdup(tok
->u
.s
);
117 void isl_token_free(struct isl_token
*tok
)
121 if (tok
->type
== ISL_TOKEN_VALUE
)
122 isl_int_clear(tok
->u
.v
);
123 else if (tok
->type
== ISL_TOKEN_MAP
)
124 isl_map_free(tok
->u
.map
);
125 else if (tok
->type
== ISL_TOKEN_AFF
)
126 isl_pw_aff_free(tok
->u
.pwaff
);
132 void isl_stream_error(__isl_keep isl_stream
*s
, struct isl_token
*tok
,
135 int line
= tok
? tok
->line
: s
->line
;
136 int col
= tok
? tok
->col
: s
->col
;
137 fprintf(stderr
, "syntax error (%d, %d): %s\n", line
, col
, msg
);
140 fprintf(stderr
, "got '%c'\n", tok
->type
);
141 else if (tok
->type
== ISL_TOKEN_IDENT
)
142 fprintf(stderr
, "got ident '%s'\n", tok
->u
.s
);
143 else if (tok
->is_keyword
)
144 fprintf(stderr
, "got keyword '%s'\n", tok
->u
.s
);
145 else if (tok
->type
== ISL_TOKEN_VALUE
) {
146 fprintf(stderr
, "got value '");
147 isl_int_print(stderr
, tok
->u
.v
, 0);
148 fprintf(stderr
, "'\n");
149 } else if (tok
->type
== ISL_TOKEN_MAP
) {
151 fprintf(stderr
, "got map '");
152 p
= isl_printer_to_file(s
->ctx
, stderr
);
153 p
= isl_printer_print_map(p
, tok
->u
.map
);
155 fprintf(stderr
, "'\n");
156 } else if (tok
->type
== ISL_TOKEN_AFF
) {
158 fprintf(stderr
, "got affine expression '");
159 p
= isl_printer_to_file(s
->ctx
, stderr
);
160 p
= isl_printer_print_pw_aff(p
, tok
->u
.pwaff
);
162 fprintf(stderr
, "'\n");
164 fprintf(stderr
, "got token '%s'\n", tok
->u
.s
);
166 fprintf(stderr
, "got token type %d\n", tok
->type
);
170 static __isl_give isl_stream
* isl_stream_new(struct isl_ctx
*ctx
)
173 isl_stream
*s
= isl_calloc_type(ctx
, struct isl_stream
);
187 for (i
= 0; i
< 5; ++i
)
192 s
->buffer
= isl_alloc_array(ctx
, char, s
->size
);
201 __isl_give isl_stream
* isl_stream_new_file(struct isl_ctx
*ctx
, FILE *file
)
203 isl_stream
*s
= isl_stream_new(ctx
);
210 __isl_give isl_stream
* isl_stream_new_str(struct isl_ctx
*ctx
, const char *str
)
215 s
= isl_stream_new(ctx
);
222 /* Read a character from the stream and advance s->line and s->col
223 * to point to the next character.
225 static int stream_getc(__isl_keep isl_stream
*s
)
231 return s
->c
= s
->un
[--s
->n_un
];
241 else if (c
== '\n') {
250 static void isl_stream_ungetc(__isl_keep isl_stream
*s
, int c
)
252 isl_assert(s
->ctx
, s
->n_un
< 5, return);
253 s
->un
[s
->n_un
++] = c
;
257 /* Read a character from the stream, skipping pairs of '\\' and '\n'.
258 * Set s->start_line and s->start_col to the line and column
259 * of the returned character.
261 static int isl_stream_getc(__isl_keep isl_stream
*s
)
266 s
->start_line
= s
->line
;
267 s
->start_col
= s
->col
;
274 isl_stream_ungetc(s
, c
);
279 static int isl_stream_push_char(__isl_keep isl_stream
*s
, int c
)
281 if (s
->len
>= s
->size
) {
283 s
->size
= (3*s
->size
)/2;
284 buffer
= isl_realloc_array(s
->ctx
, s
->buffer
, char, s
->size
);
289 s
->buffer
[s
->len
++] = c
;
293 void isl_stream_push_token(__isl_keep isl_stream
*s
, struct isl_token
*tok
)
295 isl_assert(s
->ctx
, s
->n_token
< 5, return);
296 s
->tokens
[s
->n_token
++] = tok
;
299 static enum isl_token_type
check_keywords(__isl_keep isl_stream
*s
)
301 struct isl_hash_table_entry
*entry
;
302 struct isl_keyword
*keyword
;
305 if (!strcasecmp(s
->buffer
, "exists"))
306 return ISL_TOKEN_EXISTS
;
307 if (!strcasecmp(s
->buffer
, "and"))
308 return ISL_TOKEN_AND
;
309 if (!strcasecmp(s
->buffer
, "or"))
311 if (!strcasecmp(s
->buffer
, "implies"))
312 return ISL_TOKEN_IMPLIES
;
313 if (!strcasecmp(s
->buffer
, "not"))
314 return ISL_TOKEN_NOT
;
315 if (!strcasecmp(s
->buffer
, "infty"))
316 return ISL_TOKEN_INFTY
;
317 if (!strcasecmp(s
->buffer
, "infinity"))
318 return ISL_TOKEN_INFTY
;
319 if (!strcasecmp(s
->buffer
, "NaN"))
320 return ISL_TOKEN_NAN
;
321 if (!strcasecmp(s
->buffer
, "min"))
322 return ISL_TOKEN_MIN
;
323 if (!strcasecmp(s
->buffer
, "max"))
324 return ISL_TOKEN_MAX
;
325 if (!strcasecmp(s
->buffer
, "rat"))
326 return ISL_TOKEN_RAT
;
327 if (!strcasecmp(s
->buffer
, "true"))
328 return ISL_TOKEN_TRUE
;
329 if (!strcasecmp(s
->buffer
, "false"))
330 return ISL_TOKEN_FALSE
;
331 if (!strcasecmp(s
->buffer
, "ceild"))
332 return ISL_TOKEN_CEILD
;
333 if (!strcasecmp(s
->buffer
, "floord"))
334 return ISL_TOKEN_FLOORD
;
335 if (!strcasecmp(s
->buffer
, "mod"))
336 return ISL_TOKEN_MOD
;
337 if (!strcasecmp(s
->buffer
, "ceil"))
338 return ISL_TOKEN_CEIL
;
339 if (!strcasecmp(s
->buffer
, "floor"))
340 return ISL_TOKEN_FLOOR
;
343 return ISL_TOKEN_IDENT
;
345 name_hash
= isl_hash_string(isl_hash_init(), s
->buffer
);
346 entry
= isl_hash_table_find(s
->ctx
, s
->keywords
, name_hash
, same_name
,
349 return ISL_TOKEN_ERROR
;
350 if (entry
!= isl_hash_table_entry_none
) {
351 keyword
= entry
->data
;
352 return keyword
->type
;
355 return ISL_TOKEN_IDENT
;
358 int isl_stream_skip_line(__isl_keep isl_stream
*s
)
362 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '\n')
366 return c
== -1 ? -1 : 0;
369 static struct isl_token
*next_token(__isl_keep isl_stream
*s
, int same_line
)
372 struct isl_token
*tok
= NULL
;
374 int old_line
= s
->last_line
;
377 if (same_line
&& s
->tokens
[s
->n_token
- 1]->on_new_line
)
379 return s
->tokens
[--s
->n_token
];
382 if (same_line
&& s
->c
== '\n')
387 /* skip spaces and comment lines */
388 while ((c
= isl_stream_getc(s
)) != -1) {
390 if (isl_stream_skip_line(s
) < 0)
395 } else if (!isspace(c
) || (same_line
&& c
== '\n'))
399 line
= s
->start_line
;
402 if (c
== -1 || (same_line
&& c
== '\n'))
422 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
425 tok
->type
= (enum isl_token_type
)c
;
430 if ((c
= isl_stream_getc(s
)) == '>') {
431 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
434 tok
->u
.s
= strdup("->");
435 tok
->type
= ISL_TOKEN_TO
;
439 isl_stream_ungetc(s
, c
);
441 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
444 tok
->type
= (enum isl_token_type
) '-';
448 if (c
== '-' || isdigit(c
)) {
449 int minus
= c
== '-';
450 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
453 tok
->type
= ISL_TOKEN_VALUE
;
454 isl_int_init(tok
->u
.v
);
455 if (isl_stream_push_char(s
, c
))
457 while ((c
= isl_stream_getc(s
)) != -1 && isdigit(c
))
458 if (isl_stream_push_char(s
, c
))
461 isl_stream_ungetc(s
, c
);
462 isl_stream_push_char(s
, '\0');
463 isl_int_read(tok
->u
.v
, s
->buffer
);
464 if (minus
&& isl_int_is_zero(tok
->u
.v
)) {
466 tok
->on_new_line
= 0;
467 isl_stream_push_token(s
, tok
);
468 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
471 tok
->type
= (enum isl_token_type
) '-';
475 if (isalpha(c
) || c
== '_') {
476 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
479 isl_stream_push_char(s
, c
);
480 while ((c
= isl_stream_getc(s
)) != -1 &&
481 (isalnum(c
) || c
== '_'))
482 isl_stream_push_char(s
, c
);
484 isl_stream_ungetc(s
, c
);
485 while ((c
= isl_stream_getc(s
)) != -1 && c
== '\'')
486 isl_stream_push_char(s
, c
);
488 isl_stream_ungetc(s
, c
);
489 isl_stream_push_char(s
, '\0');
490 tok
->type
= check_keywords(s
);
491 if (tok
->type
!= ISL_TOKEN_IDENT
)
493 tok
->u
.s
= strdup(s
->buffer
);
499 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
502 tok
->type
= ISL_TOKEN_STRING
;
504 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '"' && c
!= '\n')
505 isl_stream_push_char(s
, c
);
507 isl_stream_error(s
, NULL
, "unterminated string");
510 isl_stream_push_char(s
, '\0');
511 tok
->u
.s
= strdup(s
->buffer
);
516 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
519 if ((c
= isl_stream_getc(s
)) == '=') {
520 tok
->u
.s
= strdup("==");
521 tok
->type
= ISL_TOKEN_EQ_EQ
;
525 isl_stream_ungetc(s
, c
);
526 tok
->type
= (enum isl_token_type
) '=';
531 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
534 if ((c
= isl_stream_getc(s
)) == '=') {
535 tok
->u
.s
= strdup(":=");
536 tok
->type
= ISL_TOKEN_DEF
;
540 isl_stream_ungetc(s
, c
);
541 tok
->type
= (enum isl_token_type
) ':';
546 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
549 if ((c
= isl_stream_getc(s
)) == '=') {
550 tok
->u
.s
= strdup(">=");
551 tok
->type
= ISL_TOKEN_GE
;
553 } else if (c
== '>') {
554 if ((c
= isl_stream_getc(s
)) == '=') {
555 tok
->u
.s
= strdup(">>=");
556 tok
->type
= ISL_TOKEN_LEX_GE
;
559 tok
->u
.s
= strdup(">>");
560 tok
->type
= ISL_TOKEN_LEX_GT
;
562 tok
->u
.s
= strdup(">");
563 tok
->type
= ISL_TOKEN_GT
;
566 isl_stream_ungetc(s
, c
);
571 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
574 if ((c
= isl_stream_getc(s
)) == '=') {
575 tok
->u
.s
= strdup("<=");
576 tok
->type
= ISL_TOKEN_LE
;
578 } else if (c
== '<') {
579 if ((c
= isl_stream_getc(s
)) == '=') {
580 tok
->u
.s
= strdup("<<=");
581 tok
->type
= ISL_TOKEN_LEX_LE
;
584 tok
->u
.s
= strdup("<<");
585 tok
->type
= ISL_TOKEN_LEX_LT
;
587 tok
->u
.s
= strdup("<");
588 tok
->type
= ISL_TOKEN_LT
;
591 isl_stream_ungetc(s
, c
);
595 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
598 tok
->type
= ISL_TOKEN_AND
;
599 if ((c
= isl_stream_getc(s
)) != '&' && c
!= -1) {
600 tok
->u
.s
= strdup("&");
601 isl_stream_ungetc(s
, c
);
603 tok
->u
.s
= strdup("&&");
607 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
610 tok
->type
= ISL_TOKEN_OR
;
611 if ((c
= isl_stream_getc(s
)) != '|' && c
!= -1) {
612 tok
->u
.s
= strdup("|");
613 isl_stream_ungetc(s
, c
);
615 tok
->u
.s
= strdup("||");
619 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
622 if ((c
= isl_stream_getc(s
)) == '\\') {
623 tok
->u
.s
= strdup("/\\");
624 tok
->type
= ISL_TOKEN_AND
;
626 } else if (c
== '/') {
627 tok
->u
.s
= strdup("//");
628 tok
->type
= ISL_TOKEN_INT_DIV
;
631 tok
->type
= (enum isl_token_type
) '/';
634 isl_stream_ungetc(s
, c
);
638 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
641 if ((c
= isl_stream_getc(s
)) != '/' && c
!= -1) {
642 tok
->type
= (enum isl_token_type
) '\\';
643 isl_stream_ungetc(s
, c
);
645 tok
->u
.s
= strdup("\\/");
646 tok
->type
= ISL_TOKEN_OR
;
651 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
654 if ((c
= isl_stream_getc(s
)) == '=') {
655 tok
->u
.s
= strdup("!=");
656 tok
->type
= ISL_TOKEN_NE
;
659 tok
->type
= ISL_TOKEN_NOT
;
660 tok
->u
.s
= strdup("!");
663 isl_stream_ungetc(s
, c
);
667 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
670 tok
->type
= ISL_TOKEN_UNKNOWN
;
677 struct isl_token
*isl_stream_next_token(__isl_keep isl_stream
*s
)
679 return next_token(s
, 0);
682 struct isl_token
*isl_stream_next_token_on_same_line(__isl_keep isl_stream
*s
)
684 return next_token(s
, 1);
687 int isl_stream_eat_if_available(__isl_keep isl_stream
*s
, int type
)
689 struct isl_token
*tok
;
691 tok
= isl_stream_next_token(s
);
694 if (tok
->type
== type
) {
698 isl_stream_push_token(s
, tok
);
702 int isl_stream_next_token_is(__isl_keep isl_stream
*s
, int type
)
704 struct isl_token
*tok
;
707 tok
= isl_stream_next_token(s
);
710 r
= tok
->type
== type
;
711 isl_stream_push_token(s
, tok
);
715 char *isl_stream_read_ident_if_available(__isl_keep isl_stream
*s
)
717 struct isl_token
*tok
;
719 tok
= isl_stream_next_token(s
);
722 if (tok
->type
== ISL_TOKEN_IDENT
) {
723 char *ident
= strdup(tok
->u
.s
);
727 isl_stream_push_token(s
, tok
);
731 int isl_stream_eat(__isl_keep isl_stream
*s
, int type
)
733 struct isl_token
*tok
;
735 tok
= isl_stream_next_token(s
);
738 isl_stream_error(s
, NULL
, "unexpected EOF");
741 if (tok
->type
== type
) {
745 isl_stream_error(s
, tok
, "expecting other token");
746 isl_stream_push_token(s
, tok
);
750 int isl_stream_is_empty(__isl_keep isl_stream
*s
)
752 struct isl_token
*tok
;
754 tok
= isl_stream_next_token(s
);
759 isl_stream_push_token(s
, tok
);
763 static isl_stat
free_keyword(void **p
, void *user
)
765 struct isl_keyword
*keyword
= *p
;
773 void isl_stream_flush_tokens(__isl_keep isl_stream
*s
)
779 for (i
= 0; i
< s
->n_token
; ++i
)
780 isl_token_free(s
->tokens
[i
]);
784 isl_ctx
*isl_stream_get_ctx(__isl_keep isl_stream
*s
)
786 return s
? s
->ctx
: NULL
;
789 void isl_stream_free(__isl_take isl_stream
*s
)
794 if (s
->n_token
!= 0) {
795 struct isl_token
*tok
= isl_stream_next_token(s
);
796 isl_stream_error(s
, tok
, "unexpected token");
800 isl_hash_table_foreach(s
->ctx
, s
->keywords
, &free_keyword
, NULL
);
801 isl_hash_table_free(s
->ctx
, s
->keywords
);
804 free(s
->yaml_indent
);
805 isl_ctx_deref(s
->ctx
);
809 /* Push "state" onto the stack of currently active YAML elements.
810 * The caller is responsible for setting the corresponding indentation.
811 * Return 0 on success and -1 on failure.
813 static int push_state(__isl_keep isl_stream
*s
, enum isl_yaml_state state
)
815 if (s
->yaml_size
< s
->yaml_depth
+ 1) {
817 enum isl_yaml_state
*state
;
819 state
= isl_realloc_array(s
->ctx
, s
->yaml_state
,
820 enum isl_yaml_state
, s
->yaml_depth
+ 1);
823 s
->yaml_state
= state
;
825 indent
= isl_realloc_array(s
->ctx
, s
->yaml_indent
,
826 int, s
->yaml_depth
+ 1);
829 s
->yaml_indent
= indent
;
831 s
->yaml_size
= s
->yaml_depth
+ 1;
834 s
->yaml_state
[s
->yaml_depth
] = state
;
840 /* Remove the innermost active YAML element from the stack.
841 * Return 0 on success and -1 on failure.
843 static int pop_state(__isl_keep isl_stream
*s
)
847 if (s
->yaml_depth
< 1)
848 isl_die(isl_stream_get_ctx(s
), isl_error_invalid
,
849 "not in YAML construct", return -1);
856 /* Set the state of the innermost active YAML element to "state".
857 * Return 0 on success and -1 on failure.
859 static int update_state(__isl_keep isl_stream
*s
, enum isl_yaml_state state
)
863 if (s
->yaml_depth
< 1)
864 isl_die(isl_stream_get_ctx(s
), isl_error_invalid
,
865 "not in YAML construct", return -1);
867 s
->yaml_state
[s
->yaml_depth
- 1] = state
;
872 /* Return the state of the innermost active YAML element.
873 * Return isl_yaml_none if we are not inside any YAML element.
875 static enum isl_yaml_state
current_state(__isl_keep isl_stream
*s
)
878 return isl_yaml_none
;
879 if (s
->yaml_depth
< 1)
880 return isl_yaml_none
;
881 return s
->yaml_state
[s
->yaml_depth
- 1];
884 /* Set the indentation of the innermost active YAML element to "indent".
885 * If "indent" is equal to ISL_YAML_INDENT_FLOW, then this means
886 * that the current elemient is in flow format.
888 static int set_yaml_indent(__isl_keep isl_stream
*s
, int indent
)
890 if (s
->yaml_depth
< 1)
891 isl_die(s
->ctx
, isl_error_internal
,
892 "not in YAML element", return -1);
894 s
->yaml_indent
[s
->yaml_depth
- 1] = indent
;
899 /* Return the indentation of the innermost active YAML element
902 static int get_yaml_indent(__isl_keep isl_stream
*s
)
904 if (s
->yaml_depth
< 1)
905 isl_die(s
->ctx
, isl_error_internal
,
906 "not in YAML element", return -1);
908 return s
->yaml_indent
[s
->yaml_depth
- 1];
911 /* Move to the next state at the innermost level.
912 * Return 1 if successful.
913 * Return 0 if we are at the end of the innermost level.
914 * Return -1 on error.
916 * If we are in state isl_yaml_mapping_key_start, then we have just
917 * started a mapping and we are expecting a key. If the mapping started
918 * with a '{', then we check if the next token is a '}'. If so,
919 * then the mapping is empty and there is no next state at this level.
920 * Otherwise, we assume that there is at least one key (the one from
921 * which we derived the indentation in isl_stream_yaml_read_start_mapping.
923 * If we are in state isl_yaml_mapping_key, then the we expect a colon
924 * followed by a value, so there is always a next state unless
927 * If we are in state isl_yaml_mapping_val, then there may or may
928 * not be a subsequent key in the same mapping.
929 * In flow format, the next key is preceded by a comma.
930 * In block format, the next key has the same indentation as the first key.
931 * If the first token has a smaller indentation, then we have reached
932 * the end of the current mapping.
934 * If we are in state isl_yaml_sequence_start, then we have just
935 * started a sequence. If the sequence started with a '[',
936 * then we check if the next token is a ']'. If so, then the sequence
937 * is empty and there is no next state at this level.
938 * Otherwise, we assume that there is at least one element in the sequence
939 * (the one from which we derived the indentation in
940 * isl_stream_yaml_read_start_sequence.
942 * If we are in state isl_yaml_sequence, then there may or may
943 * not be a subsequent element in the same sequence.
944 * In flow format, the next element is preceded by a comma.
945 * In block format, the next element is introduced by a dash with
946 * the same indentation as that of the first element.
947 * If the first token is not a dash or if it has a smaller indentation,
948 * then we have reached the end of the current sequence.
950 int isl_stream_yaml_next(__isl_keep isl_stream
*s
)
952 struct isl_token
*tok
;
953 enum isl_yaml_state state
;
956 state
= current_state(s
);
957 if (state
== isl_yaml_none
)
958 isl_die(s
->ctx
, isl_error_invalid
,
959 "not in YAML element", return -1);
961 case isl_yaml_mapping_key_start
:
962 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
&&
963 isl_stream_next_token_is(s
, '}'))
965 if (update_state(s
, isl_yaml_mapping_key
) < 0)
968 case isl_yaml_mapping_key
:
969 tok
= isl_stream_next_token(s
);
972 isl_stream_error(s
, NULL
, "unexpected EOF");
975 if (tok
->type
== ':') {
977 if (update_state(s
, isl_yaml_mapping_val
) < 0)
981 isl_stream_error(s
, tok
, "expecting ':'");
982 isl_stream_push_token(s
, tok
);
984 case isl_yaml_mapping_val
:
985 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
) {
986 if (!isl_stream_eat_if_available(s
, ','))
988 if (update_state(s
, isl_yaml_mapping_key
) < 0)
992 tok
= isl_stream_next_token(s
);
995 indent
= tok
->col
- 1;
996 isl_stream_push_token(s
, tok
);
997 if (indent
< get_yaml_indent(s
))
999 if (update_state(s
, isl_yaml_mapping_key
) < 0)
1002 case isl_yaml_sequence_start
:
1003 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
) {
1004 if (isl_stream_next_token_is(s
, ']'))
1006 if (update_state(s
, isl_yaml_sequence
) < 0)
1010 tok
= isl_stream_next_token(s
);
1013 isl_stream_error(s
, NULL
, "unexpected EOF");
1016 if (tok
->type
== '-') {
1017 isl_token_free(tok
);
1018 if (update_state(s
, isl_yaml_sequence
) < 0)
1022 isl_stream_error(s
, tok
, "expecting '-'");
1023 isl_stream_push_token(s
, tok
);
1025 case isl_yaml_sequence
:
1026 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
)
1027 return isl_stream_eat_if_available(s
, ',');
1028 tok
= isl_stream_next_token(s
);
1031 indent
= tok
->col
- 1;
1032 if (indent
< get_yaml_indent(s
) || tok
->type
!= '-') {
1033 isl_stream_push_token(s
, tok
);
1036 isl_token_free(tok
);
1039 isl_die(s
->ctx
, isl_error_internal
,
1040 "unexpected state", return 0);
1044 /* Start reading a YAML mapping.
1045 * Return 0 on success and -1 on error.
1047 * If the first token on the stream is a '{' then we remove this token
1048 * from the stream and keep track of the fact that the mapping
1049 * is given in flow format.
1050 * Otherwise, we assume the first token is the first key of the mapping and
1051 * keep track of its indentation, but keep the token on the stream.
1052 * In both cases, the next token we expect is the first key of the mapping.
1054 int isl_stream_yaml_read_start_mapping(__isl_keep isl_stream
*s
)
1056 struct isl_token
*tok
;
1059 if (push_state(s
, isl_yaml_mapping_key_start
) < 0)
1062 tok
= isl_stream_next_token(s
);
1065 isl_stream_error(s
, NULL
, "unexpected EOF");
1068 if (isl_token_get_type(tok
) == '{') {
1069 isl_token_free(tok
);
1070 return set_yaml_indent(s
, ISL_YAML_INDENT_FLOW
);
1072 indent
= tok
->col
- 1;
1073 isl_stream_push_token(s
, tok
);
1075 return set_yaml_indent(s
, indent
);
1078 /* Finish reading a YAML mapping.
1079 * Return 0 on success and -1 on error.
1081 * If the mapping started with a '{', then we expect a '}' to close
1083 * Otherwise, we double-check that the next token (if any)
1084 * has a smaller indentation than that of the current mapping.
1086 int isl_stream_yaml_read_end_mapping(__isl_keep isl_stream
*s
)
1088 struct isl_token
*tok
;
1091 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
) {
1092 if (isl_stream_eat(s
, '}') < 0)
1094 return pop_state(s
);
1097 tok
= isl_stream_next_token(s
);
1099 return pop_state(s
);
1101 indent
= tok
->col
- 1;
1102 isl_stream_push_token(s
, tok
);
1104 if (indent
>= get_yaml_indent(s
))
1105 isl_die(isl_stream_get_ctx(s
), isl_error_invalid
,
1106 "mapping not finished", return -1);
1108 return pop_state(s
);
1111 /* Start reading a YAML sequence.
1112 * Return 0 on success and -1 on error.
1114 * If the first token on the stream is a '[' then we remove this token
1115 * from the stream and keep track of the fact that the sequence
1116 * is given in flow format.
1117 * Otherwise, we assume the first token is the dash that introduces
1118 * the first element of the sequence and keep track of its indentation,
1119 * but keep the token on the stream.
1120 * In both cases, the next token we expect is the first element
1123 int isl_stream_yaml_read_start_sequence(__isl_keep isl_stream
*s
)
1125 struct isl_token
*tok
;
1128 if (push_state(s
, isl_yaml_sequence_start
) < 0)
1131 tok
= isl_stream_next_token(s
);
1134 isl_stream_error(s
, NULL
, "unexpected EOF");
1137 if (isl_token_get_type(tok
) == '[') {
1138 isl_token_free(tok
);
1139 return set_yaml_indent(s
, ISL_YAML_INDENT_FLOW
);
1141 indent
= tok
->col
- 1;
1142 isl_stream_push_token(s
, tok
);
1144 return set_yaml_indent(s
, indent
);
1147 /* Finish reading a YAML sequence.
1148 * Return 0 on success and -1 on error.
1150 * If the sequence started with a '[', then we expect a ']' to close
1152 * Otherwise, we double-check that the next token (if any)
1153 * is not a dash or that it has a smaller indentation than
1154 * that of the current sequence.
1156 int isl_stream_yaml_read_end_sequence(__isl_keep isl_stream
*s
)
1158 struct isl_token
*tok
;
1162 if (get_yaml_indent(s
) == ISL_YAML_INDENT_FLOW
) {
1163 if (isl_stream_eat(s
, ']') < 0)
1165 return pop_state(s
);
1168 tok
= isl_stream_next_token(s
);
1170 return pop_state(s
);
1172 indent
= tok
->col
- 1;
1173 dash
= tok
->type
== '-';
1174 isl_stream_push_token(s
, tok
);
1176 if (indent
>= get_yaml_indent(s
) && dash
)
1177 isl_die(isl_stream_get_ctx(s
), isl_error_invalid
,
1178 "sequence not finished", return -1);
1180 return pop_state(s
);