1 1.1 mrg /* 2 1.1 mrg * Copyright 2008-2009 Katholieke Universiteit Leuven 3 1.1 mrg * 4 1.1 mrg * Use of this software is governed by the MIT license 5 1.1 mrg * 6 1.1 mrg * Written by Sven Verdoolaege, K.U.Leuven, Departement 7 1.1 mrg * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium 8 1.1 mrg */ 9 1.1 mrg 10 1.1 mrg #include <ctype.h> 11 1.1 mrg #include <string.h> 12 1.1 mrg #include <isl_ctx_private.h> 13 1.1 mrg #include <isl_stream_private.h> 14 1.1 mrg #include <isl/map.h> 15 1.1 mrg #include <isl/aff.h> 16 1.1 mrg #include <isl_val_private.h> 17 1.1 mrg #include <isl_options_private.h> 18 1.1 mrg 19 1.1 mrg struct isl_keyword { 20 1.1 mrg char *name; 21 1.1 mrg enum isl_token_type type; 22 1.1 mrg }; 23 1.1 mrg 24 1.1 mrg static isl_bool same_name(const void *entry, const void *val) 25 1.1 mrg { 26 1.1 mrg const struct isl_keyword *keyword = (const struct isl_keyword *)entry; 27 1.1 mrg 28 1.1 mrg return isl_bool_ok(!strcmp(keyword->name, val)); 29 1.1 mrg } 30 1.1 mrg 31 1.1 mrg enum isl_token_type isl_stream_register_keyword(__isl_keep isl_stream *s, 32 1.1 mrg const char *name) 33 1.1 mrg { 34 1.1 mrg struct isl_hash_table_entry *entry; 35 1.1 mrg struct isl_keyword *keyword; 36 1.1 mrg uint32_t name_hash; 37 1.1 mrg 38 1.1 mrg if (!s->keywords) { 39 1.1 mrg s->keywords = isl_hash_table_alloc(s->ctx, 10); 40 1.1 mrg if (!s->keywords) 41 1.1 mrg return ISL_TOKEN_ERROR; 42 1.1 mrg s->next_type = ISL_TOKEN_LAST; 43 1.1 mrg } 44 1.1 mrg 45 1.1 mrg name_hash = isl_hash_string(isl_hash_init(), name); 46 1.1 mrg 47 1.1 mrg entry = isl_hash_table_find(s->ctx, s->keywords, name_hash, 48 1.1 mrg same_name, name, 1); 49 1.1 mrg if (!entry) 50 1.1 mrg return ISL_TOKEN_ERROR; 51 1.1 mrg if (entry->data) { 52 1.1 mrg keyword = entry->data; 53 1.1 mrg return keyword->type; 54 1.1 mrg } 55 1.1 mrg 56 1.1 mrg keyword = isl_calloc_type(s->ctx, struct isl_keyword); 57 1.1 mrg if (!keyword) 58 1.1 mrg return ISL_TOKEN_ERROR; 59 1.1 mrg keyword->type = s->next_type++; 60 1.1 mrg keyword->name = strdup(name); 61 1.1 mrg if (!keyword->name) { 62 1.1 mrg free(keyword); 63 1.1 mrg return ISL_TOKEN_ERROR; 64 1.1 mrg } 65 1.1 mrg entry->data = keyword; 66 1.1 mrg 67 1.1 mrg return keyword->type; 68 1.1 mrg } 69 1.1 mrg 70 1.1 mrg struct isl_token *isl_token_new(isl_ctx *ctx, 71 1.1 mrg int line, int col, unsigned on_new_line) 72 1.1 mrg { 73 1.1 mrg struct isl_token *tok = isl_alloc_type(ctx, struct isl_token); 74 1.1 mrg if (!tok) 75 1.1 mrg return NULL; 76 1.1 mrg tok->line = line; 77 1.1 mrg tok->col = col; 78 1.1 mrg tok->on_new_line = on_new_line; 79 1.1 mrg tok->is_keyword = 0; 80 1.1 mrg tok->u.s = NULL; 81 1.1 mrg return tok; 82 1.1 mrg } 83 1.1 mrg 84 1.1 mrg /* Return the type of "tok". 85 1.1 mrg */ 86 1.1 mrg int isl_token_get_type(struct isl_token *tok) 87 1.1 mrg { 88 1.1 mrg return tok ? tok->type : ISL_TOKEN_ERROR; 89 1.1 mrg } 90 1.1 mrg 91 1.1 mrg /* Given a token of type ISL_TOKEN_VALUE, return the value it represents. 92 1.1 mrg */ 93 1.1 mrg __isl_give isl_val *isl_token_get_val(isl_ctx *ctx, struct isl_token *tok) 94 1.1 mrg { 95 1.1 mrg if (!tok) 96 1.1 mrg return NULL; 97 1.1 mrg if (tok->type != ISL_TOKEN_VALUE) 98 1.1 mrg isl_die(ctx, isl_error_invalid, "not a value token", 99 1.1 mrg return NULL); 100 1.1 mrg 101 1.1 mrg return isl_val_int_from_isl_int(ctx, tok->u.v); 102 1.1 mrg } 103 1.1 mrg 104 1.1 mrg /* Does the given token have a string representation? 105 1.1 mrg */ 106 1.1 mrg isl_bool isl_token_has_str(struct isl_token *tok) 107 1.1 mrg { 108 1.1 mrg if (!tok) 109 1.1 mrg return isl_bool_error; 110 1.1 mrg return isl_bool_ok(tok->u.s != NULL); 111 1.1 mrg } 112 1.1 mrg 113 1.1 mrg /* Given a token with a string representation, return a copy of this string. 114 1.1 mrg */ 115 1.1 mrg __isl_give char *isl_token_get_str(isl_ctx *ctx, struct isl_token *tok) 116 1.1 mrg { 117 1.1 mrg if (!tok) 118 1.1 mrg return NULL; 119 1.1 mrg if (!tok->u.s) 120 1.1 mrg isl_die(ctx, isl_error_invalid, 121 1.1 mrg "token does not have a string representation", 122 1.1 mrg return NULL); 123 1.1 mrg 124 1.1 mrg return strdup(tok->u.s); 125 1.1 mrg } 126 1.1 mrg 127 1.1 mrg void isl_token_free(struct isl_token *tok) 128 1.1 mrg { 129 1.1 mrg if (!tok) 130 1.1 mrg return; 131 1.1 mrg if (tok->type == ISL_TOKEN_VALUE) 132 1.1 mrg isl_int_clear(tok->u.v); 133 1.1 mrg else if (tok->type == ISL_TOKEN_MAP) 134 1.1 mrg isl_map_free(tok->u.map); 135 1.1 mrg else if (tok->type == ISL_TOKEN_AFF) 136 1.1 mrg isl_pw_aff_free(tok->u.pwaff); 137 1.1 mrg else 138 1.1 mrg free(tok->u.s); 139 1.1 mrg free(tok); 140 1.1 mrg } 141 1.1 mrg 142 1.1 mrg void isl_stream_error(__isl_keep isl_stream *s, struct isl_token *tok, 143 1.1 mrg char *msg) 144 1.1 mrg { 145 1.1 mrg int line = tok ? tok->line : s->line; 146 1.1 mrg int col = tok ? tok->col : s->col; 147 1.1 mrg 148 1.1 mrg isl_ctx_set_full_error(s->ctx, isl_error_invalid, "syntax error", 149 1.1 mrg __FILE__, __LINE__); 150 1.1 mrg 151 1.1 mrg if (s->ctx->opt->on_error == ISL_ON_ERROR_CONTINUE) 152 1.1 mrg return; 153 1.1 mrg fprintf(stderr, "syntax error (%d, %d): %s\n", line, col, msg); 154 1.1 mrg if (tok) { 155 1.1 mrg if (tok->type < 256) 156 1.1 mrg fprintf(stderr, "got '%c'\n", tok->type); 157 1.1 mrg else if (tok->type == ISL_TOKEN_IDENT) 158 1.1 mrg fprintf(stderr, "got ident '%s'\n", tok->u.s); 159 1.1 mrg else if (tok->is_keyword) 160 1.1 mrg fprintf(stderr, "got keyword '%s'\n", tok->u.s); 161 1.1 mrg else if (tok->type == ISL_TOKEN_VALUE) { 162 1.1 mrg fprintf(stderr, "got value '"); 163 1.1 mrg isl_int_print(stderr, tok->u.v, 0); 164 1.1 mrg fprintf(stderr, "'\n"); 165 1.1 mrg } else if (tok->type == ISL_TOKEN_MAP) { 166 1.1 mrg isl_printer *p; 167 1.1 mrg fprintf(stderr, "got map '"); 168 1.1 mrg p = isl_printer_to_file(s->ctx, stderr); 169 1.1 mrg p = isl_printer_print_map(p, tok->u.map); 170 1.1 mrg isl_printer_free(p); 171 1.1 mrg fprintf(stderr, "'\n"); 172 1.1 mrg } else if (tok->type == ISL_TOKEN_AFF) { 173 1.1 mrg isl_printer *p; 174 1.1 mrg fprintf(stderr, "got affine expression '"); 175 1.1 mrg p = isl_printer_to_file(s->ctx, stderr); 176 1.1 mrg p = isl_printer_print_pw_aff(p, tok->u.pwaff); 177 1.1 mrg isl_printer_free(p); 178 1.1 mrg fprintf(stderr, "'\n"); 179 1.1 mrg } else if (tok->u.s) 180 1.1 mrg fprintf(stderr, "got token '%s'\n", tok->u.s); 181 1.1 mrg else 182 1.1 mrg fprintf(stderr, "got token type %d\n", tok->type); 183 1.1 mrg } 184 1.1 mrg if (s->ctx->opt->on_error == ISL_ON_ERROR_ABORT) 185 1.1 mrg abort(); 186 1.1 mrg } 187 1.1 mrg 188 1.1 mrg static __isl_give isl_stream* isl_stream_new(struct isl_ctx *ctx) 189 1.1 mrg { 190 1.1 mrg int i; 191 1.1 mrg isl_stream *s = isl_calloc_type(ctx, struct isl_stream); 192 1.1 mrg if (!s) 193 1.1 mrg return NULL; 194 1.1 mrg s->ctx = ctx; 195 1.1 mrg isl_ctx_ref(s->ctx); 196 1.1 mrg s->file = NULL; 197 1.1 mrg s->str = NULL; 198 1.1 mrg s->len = 0; 199 1.1 mrg s->line = 1; 200 1.1 mrg s->col = 1; 201 1.1 mrg s->eof = 0; 202 1.1 mrg s->last_line = 0; 203 1.1 mrg s->c = -1; 204 1.1 mrg s->n_un = 0; 205 1.1 mrg for (i = 0; i < 5; ++i) 206 1.1 mrg s->tokens[i] = NULL; 207 1.1 mrg s->n_token = 0; 208 1.1 mrg s->keywords = NULL; 209 1.1 mrg s->size = 256; 210 1.1 mrg s->buffer = isl_alloc_array(ctx, char, s->size); 211 1.1 mrg if (!s->buffer) 212 1.1 mrg goto error; 213 1.1 mrg return s; 214 1.1 mrg error: 215 1.1 mrg isl_stream_free(s); 216 1.1 mrg return NULL; 217 1.1 mrg } 218 1.1 mrg 219 1.1 mrg __isl_give isl_stream* isl_stream_new_file(struct isl_ctx *ctx, FILE *file) 220 1.1 mrg { 221 1.1 mrg isl_stream *s = isl_stream_new(ctx); 222 1.1 mrg if (!s) 223 1.1 mrg return NULL; 224 1.1 mrg s->file = file; 225 1.1 mrg return s; 226 1.1 mrg } 227 1.1 mrg 228 1.1 mrg __isl_give isl_stream* isl_stream_new_str(struct isl_ctx *ctx, const char *str) 229 1.1 mrg { 230 1.1 mrg isl_stream *s; 231 1.1 mrg if (!str) 232 1.1 mrg return NULL; 233 1.1 mrg s = isl_stream_new(ctx); 234 1.1 mrg if (!s) 235 1.1 mrg return NULL; 236 1.1 mrg s->str = str; 237 1.1 mrg return s; 238 1.1 mrg } 239 1.1 mrg 240 1.1 mrg /* Read a character from the stream and advance s->line and s->col 241 1.1 mrg * to point to the next character. 242 1.1 mrg */ 243 1.1 mrg static int stream_getc(__isl_keep isl_stream *s) 244 1.1 mrg { 245 1.1 mrg int c; 246 1.1 mrg if (s->eof) 247 1.1 mrg return -1; 248 1.1 mrg if (s->n_un) 249 1.1 mrg return s->c = s->un[--s->n_un]; 250 1.1 mrg if (s->file) 251 1.1 mrg c = fgetc(s->file); 252 1.1 mrg else { 253 1.1 mrg c = *s->str++; 254 1.1 mrg if (c == '\0') 255 1.1 mrg c = -1; 256 1.1 mrg } 257 1.1 mrg if (c == -1) 258 1.1 mrg s->eof = 1; 259 1.1 mrg else if (c == '\n') { 260 1.1 mrg s->line++; 261 1.1 mrg s->col = 1; 262 1.1 mrg } else 263 1.1 mrg s->col++; 264 1.1 mrg s->c = c; 265 1.1 mrg return c; 266 1.1 mrg } 267 1.1 mrg 268 1.1 mrg static void isl_stream_ungetc(__isl_keep isl_stream *s, int c) 269 1.1 mrg { 270 1.1 mrg isl_assert(s->ctx, s->n_un < 5, return); 271 1.1 mrg s->un[s->n_un++] = c; 272 1.1 mrg s->c = -1; 273 1.1 mrg } 274 1.1 mrg 275 1.1 mrg /* Read a character from the stream, skipping pairs of '\\' and '\n'. 276 1.1 mrg * Set s->start_line and s->start_col to the line and column 277 1.1 mrg * of the returned character. 278 1.1 mrg */ 279 1.1 mrg static int isl_stream_getc(__isl_keep isl_stream *s) 280 1.1 mrg { 281 1.1 mrg int c; 282 1.1 mrg 283 1.1 mrg do { 284 1.1 mrg s->start_line = s->line; 285 1.1 mrg s->start_col = s->col; 286 1.1 mrg c = stream_getc(s); 287 1.1 mrg if (c != '\\') 288 1.1 mrg return c; 289 1.1 mrg c = stream_getc(s); 290 1.1 mrg } while (c == '\n'); 291 1.1 mrg 292 1.1 mrg isl_stream_ungetc(s, c); 293 1.1 mrg 294 1.1 mrg return '\\'; 295 1.1 mrg } 296 1.1 mrg 297 1.1 mrg static int isl_stream_push_char(__isl_keep isl_stream *s, int c) 298 1.1 mrg { 299 1.1 mrg if (s->len >= s->size) { 300 1.1 mrg char *buffer; 301 1.1 mrg s->size = (3*s->size)/2; 302 1.1 mrg buffer = isl_realloc_array(s->ctx, s->buffer, char, s->size); 303 1.1 mrg if (!buffer) 304 1.1 mrg return -1; 305 1.1 mrg s->buffer = buffer; 306 1.1 mrg } 307 1.1 mrg s->buffer[s->len++] = c; 308 1.1 mrg return 0; 309 1.1 mrg } 310 1.1 mrg 311 1.1 mrg void isl_stream_push_token(__isl_keep isl_stream *s, struct isl_token *tok) 312 1.1 mrg { 313 1.1 mrg isl_assert(s->ctx, s->n_token < 5, return); 314 1.1 mrg s->tokens[s->n_token++] = tok; 315 1.1 mrg } 316 1.1 mrg 317 1.1 mrg static enum isl_token_type check_keywords(__isl_keep isl_stream *s) 318 1.1 mrg { 319 1.1 mrg struct isl_hash_table_entry *entry; 320 1.1 mrg struct isl_keyword *keyword; 321 1.1 mrg uint32_t name_hash; 322 1.1 mrg 323 1.1 mrg if (!strcasecmp(s->buffer, "exists")) 324 1.1 mrg return ISL_TOKEN_EXISTS; 325 1.1 mrg if (!strcasecmp(s->buffer, "and")) 326 1.1 mrg return ISL_TOKEN_AND; 327 1.1 mrg if (!strcasecmp(s->buffer, "or")) 328 1.1 mrg return ISL_TOKEN_OR; 329 1.1 mrg if (!strcasecmp(s->buffer, "implies")) 330 1.1 mrg return ISL_TOKEN_IMPLIES; 331 1.1 mrg if (!strcasecmp(s->buffer, "not")) 332 1.1 mrg return ISL_TOKEN_NOT; 333 1.1 mrg if (!strcasecmp(s->buffer, "infty")) 334 1.1 mrg return ISL_TOKEN_INFTY; 335 1.1 mrg if (!strcasecmp(s->buffer, "infinity")) 336 1.1 mrg return ISL_TOKEN_INFTY; 337 1.1 mrg if (!strcasecmp(s->buffer, "NaN")) 338 1.1 mrg return ISL_TOKEN_NAN; 339 1.1 mrg if (!strcasecmp(s->buffer, "min")) 340 1.1 mrg return ISL_TOKEN_MIN; 341 1.1 mrg if (!strcasecmp(s->buffer, "max")) 342 1.1 mrg return ISL_TOKEN_MAX; 343 1.1 mrg if (!strcasecmp(s->buffer, "rat")) 344 1.1 mrg return ISL_TOKEN_RAT; 345 1.1 mrg if (!strcasecmp(s->buffer, "true")) 346 1.1 mrg return ISL_TOKEN_TRUE; 347 1.1 mrg if (!strcasecmp(s->buffer, "false")) 348 1.1 mrg return ISL_TOKEN_FALSE; 349 1.1 mrg if (!strcasecmp(s->buffer, "ceild")) 350 1.1 mrg return ISL_TOKEN_CEILD; 351 1.1 mrg if (!strcasecmp(s->buffer, "floord")) 352 1.1 mrg return ISL_TOKEN_FLOORD; 353 1.1 mrg if (!strcasecmp(s->buffer, "mod")) 354 1.1 mrg return ISL_TOKEN_MOD; 355 1.1 mrg if (!strcasecmp(s->buffer, "ceil")) 356 1.1 mrg return ISL_TOKEN_CEIL; 357 1.1 mrg if (!strcasecmp(s->buffer, "floor")) 358 1.1 mrg return ISL_TOKEN_FLOOR; 359 1.1 mrg 360 1.1 mrg if (!s->keywords) 361 1.1 mrg return ISL_TOKEN_IDENT; 362 1.1 mrg 363 1.1 mrg name_hash = isl_hash_string(isl_hash_init(), s->buffer); 364 1.1 mrg entry = isl_hash_table_find(s->ctx, s->keywords, name_hash, same_name, 365 1.1 mrg s->buffer, 0); 366 1.1 mrg if (!entry) 367 1.1 mrg return ISL_TOKEN_ERROR; 368 1.1 mrg if (entry != isl_hash_table_entry_none) { 369 1.1 mrg keyword = entry->data; 370 1.1 mrg return keyword->type; 371 1.1 mrg } 372 1.1 mrg 373 1.1 mrg return ISL_TOKEN_IDENT; 374 1.1 mrg } 375 1.1 mrg 376 1.1 mrg int isl_stream_skip_line(__isl_keep isl_stream *s) 377 1.1 mrg { 378 1.1 mrg int c; 379 1.1 mrg 380 1.1 mrg while ((c = isl_stream_getc(s)) != -1 && c != '\n') 381 1.1 mrg /* nothing */ 382 1.1 mrg ; 383 1.1 mrg 384 1.1 mrg return c == -1 ? -1 : 0; 385 1.1 mrg } 386 1.1 mrg 387 1.1 mrg static struct isl_token *next_token(__isl_keep isl_stream *s, int same_line) 388 1.1 mrg { 389 1.1 mrg int c; 390 1.1 mrg struct isl_token *tok = NULL; 391 1.1 mrg int line, col; 392 1.1 mrg int old_line = s->last_line; 393 1.1 mrg 394 1.1 mrg if (s->n_token) { 395 1.1 mrg if (same_line && s->tokens[s->n_token - 1]->on_new_line) 396 1.1 mrg return NULL; 397 1.1 mrg return s->tokens[--s->n_token]; 398 1.1 mrg } 399 1.1 mrg 400 1.1 mrg if (same_line && s->c == '\n') 401 1.1 mrg return NULL; 402 1.1 mrg 403 1.1 mrg s->len = 0; 404 1.1 mrg 405 1.1 mrg /* skip spaces and comment lines */ 406 1.1 mrg while ((c = isl_stream_getc(s)) != -1) { 407 1.1 mrg if (c == '#') { 408 1.1 mrg if (isl_stream_skip_line(s) < 0) 409 1.1 mrg break; 410 1.1 mrg c = '\n'; 411 1.1 mrg if (same_line) 412 1.1 mrg break; 413 1.1 mrg } else if (!isspace(c) || (same_line && c == '\n')) 414 1.1 mrg break; 415 1.1 mrg } 416 1.1 mrg 417 1.1 mrg line = s->start_line; 418 1.1 mrg col = s->start_col; 419 1.1 mrg 420 1.1 mrg if (c == -1 || (same_line && c == '\n')) 421 1.1 mrg return NULL; 422 1.1 mrg s->last_line = line; 423 1.1 mrg 424 1.1 mrg if (c == '(' || 425 1.1 mrg c == ')' || 426 1.1 mrg c == '+' || 427 1.1 mrg c == '*' || 428 1.1 mrg c == '%' || 429 1.1 mrg c == '?' || 430 1.1 mrg c == '^' || 431 1.1 mrg c == '@' || 432 1.1 mrg c == '$' || 433 1.1 mrg c == ',' || 434 1.1 mrg c == '.' || 435 1.1 mrg c == ';' || 436 1.1 mrg c == '[' || 437 1.1 mrg c == ']' || 438 1.1 mrg c == '{' || 439 1.1 mrg c == '}') { 440 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 441 1.1 mrg if (!tok) 442 1.1 mrg return NULL; 443 1.1 mrg tok->type = (enum isl_token_type)c; 444 1.1 mrg return tok; 445 1.1 mrg } 446 1.1 mrg if (c == '-') { 447 1.1 mrg int c; 448 1.1 mrg if ((c = isl_stream_getc(s)) == '>') { 449 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 450 1.1 mrg if (!tok) 451 1.1 mrg return NULL; 452 1.1 mrg tok->u.s = strdup("->"); 453 1.1 mrg tok->type = ISL_TOKEN_TO; 454 1.1 mrg return tok; 455 1.1 mrg } 456 1.1 mrg if (c != -1) 457 1.1 mrg isl_stream_ungetc(s, c); 458 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 459 1.1 mrg if (!tok) 460 1.1 mrg return NULL; 461 1.1 mrg tok->type = (enum isl_token_type) '-'; 462 1.1 mrg return tok; 463 1.1 mrg } 464 1.1 mrg if (isdigit(c)) { 465 1.1 mrg int minus = c == '-'; 466 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 467 1.1 mrg if (!tok) 468 1.1 mrg return NULL; 469 1.1 mrg tok->type = ISL_TOKEN_VALUE; 470 1.1 mrg isl_int_init(tok->u.v); 471 1.1 mrg if (isl_stream_push_char(s, c)) 472 1.1 mrg goto error; 473 1.1 mrg while ((c = isl_stream_getc(s)) != -1 && isdigit(c)) 474 1.1 mrg if (isl_stream_push_char(s, c)) 475 1.1 mrg goto error; 476 1.1 mrg if (c != -1) 477 1.1 mrg isl_stream_ungetc(s, c); 478 1.1 mrg isl_stream_push_char(s, '\0'); 479 1.1 mrg isl_int_read(tok->u.v, s->buffer); 480 1.1 mrg if (minus && isl_int_is_zero(tok->u.v)) { 481 1.1 mrg tok->col++; 482 1.1 mrg tok->on_new_line = 0; 483 1.1 mrg isl_stream_push_token(s, tok); 484 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 485 1.1 mrg if (!tok) 486 1.1 mrg return NULL; 487 1.1 mrg tok->type = (enum isl_token_type) '-'; 488 1.1 mrg } 489 1.1 mrg return tok; 490 1.1 mrg } 491 1.1 mrg if (isalpha(c) || c == '_') { 492 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 493 1.1 mrg if (!tok) 494 1.1 mrg return NULL; 495 1.1 mrg isl_stream_push_char(s, c); 496 1.1 mrg while ((c = isl_stream_getc(s)) != -1 && 497 1.1 mrg (isalnum(c) || c == '_')) 498 1.1 mrg isl_stream_push_char(s, c); 499 1.1 mrg if (c != -1) 500 1.1 mrg isl_stream_ungetc(s, c); 501 1.1 mrg while ((c = isl_stream_getc(s)) != -1 && c == '\'') 502 1.1 mrg isl_stream_push_char(s, c); 503 1.1 mrg if (c != -1) 504 1.1 mrg isl_stream_ungetc(s, c); 505 1.1 mrg isl_stream_push_char(s, '\0'); 506 1.1 mrg tok->type = check_keywords(s); 507 1.1 mrg if (tok->type != ISL_TOKEN_IDENT) 508 1.1 mrg tok->is_keyword = 1; 509 1.1 mrg tok->u.s = strdup(s->buffer); 510 1.1 mrg if (!tok->u.s) 511 1.1 mrg goto error; 512 1.1 mrg return tok; 513 1.1 mrg } 514 1.1 mrg if (c == '"') { 515 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 516 1.1 mrg if (!tok) 517 1.1 mrg return NULL; 518 1.1 mrg tok->type = ISL_TOKEN_STRING; 519 1.1 mrg tok->u.s = NULL; 520 1.1 mrg while ((c = isl_stream_getc(s)) != -1 && c != '"' && c != '\n') 521 1.1 mrg isl_stream_push_char(s, c); 522 1.1 mrg if (c != '"') { 523 1.1 mrg isl_stream_error(s, NULL, "unterminated string"); 524 1.1 mrg goto error; 525 1.1 mrg } 526 1.1 mrg isl_stream_push_char(s, '\0'); 527 1.1 mrg tok->u.s = strdup(s->buffer); 528 1.1 mrg return tok; 529 1.1 mrg } 530 1.1 mrg if (c == '=') { 531 1.1 mrg int c; 532 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 533 1.1 mrg if (!tok) 534 1.1 mrg return NULL; 535 1.1 mrg if ((c = isl_stream_getc(s)) == '=') { 536 1.1 mrg tok->u.s = strdup("=="); 537 1.1 mrg tok->type = ISL_TOKEN_EQ_EQ; 538 1.1 mrg return tok; 539 1.1 mrg } 540 1.1 mrg if (c != -1) 541 1.1 mrg isl_stream_ungetc(s, c); 542 1.1 mrg tok->type = (enum isl_token_type) '='; 543 1.1 mrg return tok; 544 1.1 mrg } 545 1.1 mrg if (c == ':') { 546 1.1 mrg int c; 547 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 548 1.1 mrg if (!tok) 549 1.1 mrg return NULL; 550 1.1 mrg if ((c = isl_stream_getc(s)) == '=') { 551 1.1 mrg tok->u.s = strdup(":="); 552 1.1 mrg tok->type = ISL_TOKEN_DEF; 553 1.1 mrg return tok; 554 1.1 mrg } 555 1.1 mrg if (c != -1) 556 1.1 mrg isl_stream_ungetc(s, c); 557 1.1 mrg tok->type = (enum isl_token_type) ':'; 558 1.1 mrg return tok; 559 1.1 mrg } 560 1.1 mrg if (c == '>') { 561 1.1 mrg int c; 562 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 563 1.1 mrg if (!tok) 564 1.1 mrg return NULL; 565 1.1 mrg if ((c = isl_stream_getc(s)) == '=') { 566 1.1 mrg tok->u.s = strdup(">="); 567 1.1 mrg tok->type = ISL_TOKEN_GE; 568 1.1 mrg return tok; 569 1.1 mrg } else if (c == '>') { 570 1.1 mrg if ((c = isl_stream_getc(s)) == '=') { 571 1.1 mrg tok->u.s = strdup(">>="); 572 1.1 mrg tok->type = ISL_TOKEN_LEX_GE; 573 1.1 mrg return tok; 574 1.1 mrg } 575 1.1 mrg tok->u.s = strdup(">>"); 576 1.1 mrg tok->type = ISL_TOKEN_LEX_GT; 577 1.1 mrg } else { 578 1.1 mrg tok->u.s = strdup(">"); 579 1.1 mrg tok->type = ISL_TOKEN_GT; 580 1.1 mrg } 581 1.1 mrg if (c != -1) 582 1.1 mrg isl_stream_ungetc(s, c); 583 1.1 mrg return tok; 584 1.1 mrg } 585 1.1 mrg if (c == '<') { 586 1.1 mrg int c; 587 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 588 1.1 mrg if (!tok) 589 1.1 mrg return NULL; 590 1.1 mrg if ((c = isl_stream_getc(s)) == '=') { 591 1.1 mrg tok->u.s = strdup("<="); 592 1.1 mrg tok->type = ISL_TOKEN_LE; 593 1.1 mrg return tok; 594 1.1 mrg } else if (c == '<') { 595 1.1 mrg if ((c = isl_stream_getc(s)) == '=') { 596 1.1 mrg tok->u.s = strdup("<<="); 597 1.1 mrg tok->type = ISL_TOKEN_LEX_LE; 598 1.1 mrg return tok; 599 1.1 mrg } 600 1.1 mrg tok->u.s = strdup("<<"); 601 1.1 mrg tok->type = ISL_TOKEN_LEX_LT; 602 1.1 mrg } else { 603 1.1 mrg tok->u.s = strdup("<"); 604 1.1 mrg tok->type = ISL_TOKEN_LT; 605 1.1 mrg } 606 1.1 mrg if (c != -1) 607 1.1 mrg isl_stream_ungetc(s, c); 608 1.1 mrg return tok; 609 1.1 mrg } 610 1.1 mrg if (c == '&') { 611 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 612 1.1 mrg if (!tok) 613 1.1 mrg return NULL; 614 1.1 mrg tok->type = ISL_TOKEN_AND; 615 1.1 mrg if ((c = isl_stream_getc(s)) != '&' && c != -1) { 616 1.1 mrg tok->u.s = strdup("&"); 617 1.1 mrg isl_stream_ungetc(s, c); 618 1.1 mrg } else 619 1.1 mrg tok->u.s = strdup("&&"); 620 1.1 mrg return tok; 621 1.1 mrg } 622 1.1 mrg if (c == '|') { 623 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 624 1.1 mrg if (!tok) 625 1.1 mrg return NULL; 626 1.1 mrg tok->type = ISL_TOKEN_OR; 627 1.1 mrg if ((c = isl_stream_getc(s)) != '|' && c != -1) { 628 1.1 mrg tok->u.s = strdup("|"); 629 1.1 mrg isl_stream_ungetc(s, c); 630 1.1 mrg } else 631 1.1 mrg tok->u.s = strdup("||"); 632 1.1 mrg return tok; 633 1.1 mrg } 634 1.1 mrg if (c == '/') { 635 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 636 1.1 mrg if (!tok) 637 1.1 mrg return NULL; 638 1.1 mrg if ((c = isl_stream_getc(s)) == '\\') { 639 1.1 mrg tok->u.s = strdup("/\\"); 640 1.1 mrg tok->type = ISL_TOKEN_AND; 641 1.1 mrg return tok; 642 1.1 mrg } else if (c == '/') { 643 1.1 mrg tok->u.s = strdup("//"); 644 1.1 mrg tok->type = ISL_TOKEN_INT_DIV; 645 1.1 mrg return tok; 646 1.1 mrg } else { 647 1.1 mrg tok->type = (enum isl_token_type) '/'; 648 1.1 mrg } 649 1.1 mrg if (c != -1) 650 1.1 mrg isl_stream_ungetc(s, c); 651 1.1 mrg return tok; 652 1.1 mrg } 653 1.1 mrg if (c == '\\') { 654 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 655 1.1 mrg if (!tok) 656 1.1 mrg return NULL; 657 1.1 mrg if ((c = isl_stream_getc(s)) != '/' && c != -1) { 658 1.1 mrg tok->type = (enum isl_token_type) '\\'; 659 1.1 mrg isl_stream_ungetc(s, c); 660 1.1 mrg } else { 661 1.1 mrg tok->u.s = strdup("\\/"); 662 1.1 mrg tok->type = ISL_TOKEN_OR; 663 1.1 mrg } 664 1.1 mrg return tok; 665 1.1 mrg } 666 1.1 mrg if (c == '!') { 667 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 668 1.1 mrg if (!tok) 669 1.1 mrg return NULL; 670 1.1 mrg if ((c = isl_stream_getc(s)) == '=') { 671 1.1 mrg tok->u.s = strdup("!="); 672 1.1 mrg tok->type = ISL_TOKEN_NE; 673 1.1 mrg return tok; 674 1.1 mrg } else { 675 1.1 mrg tok->type = ISL_TOKEN_NOT; 676 1.1 mrg tok->u.s = strdup("!"); 677 1.1 mrg } 678 1.1 mrg if (c != -1) 679 1.1 mrg isl_stream_ungetc(s, c); 680 1.1 mrg return tok; 681 1.1 mrg } 682 1.1 mrg 683 1.1 mrg tok = isl_token_new(s->ctx, line, col, old_line != line); 684 1.1 mrg if (!tok) 685 1.1 mrg return NULL; 686 1.1 mrg tok->type = ISL_TOKEN_UNKNOWN; 687 1.1 mrg return tok; 688 1.1 mrg error: 689 1.1 mrg isl_token_free(tok); 690 1.1 mrg return NULL; 691 1.1 mrg } 692 1.1 mrg 693 1.1 mrg struct isl_token *isl_stream_next_token(__isl_keep isl_stream *s) 694 1.1 mrg { 695 1.1 mrg return next_token(s, 0); 696 1.1 mrg } 697 1.1 mrg 698 1.1 mrg struct isl_token *isl_stream_next_token_on_same_line(__isl_keep isl_stream *s) 699 1.1 mrg { 700 1.1 mrg return next_token(s, 1); 701 1.1 mrg } 702 1.1 mrg 703 1.1 mrg int isl_stream_eat_if_available(__isl_keep isl_stream *s, int type) 704 1.1 mrg { 705 1.1 mrg struct isl_token *tok; 706 1.1 mrg 707 1.1 mrg tok = isl_stream_next_token(s); 708 1.1 mrg if (!tok) 709 1.1 mrg return 0; 710 1.1 mrg if (tok->type == type) { 711 1.1 mrg isl_token_free(tok); 712 1.1 mrg return 1; 713 1.1 mrg } 714 1.1 mrg isl_stream_push_token(s, tok); 715 1.1 mrg return 0; 716 1.1 mrg } 717 1.1 mrg 718 1.1 mrg int isl_stream_next_token_is(__isl_keep isl_stream *s, int type) 719 1.1 mrg { 720 1.1 mrg struct isl_token *tok; 721 1.1 mrg int r; 722 1.1 mrg 723 1.1 mrg tok = isl_stream_next_token(s); 724 1.1 mrg if (!tok) 725 1.1 mrg return 0; 726 1.1 mrg r = tok->type == type; 727 1.1 mrg isl_stream_push_token(s, tok); 728 1.1 mrg return r; 729 1.1 mrg } 730 1.1 mrg 731 1.1 mrg char *isl_stream_read_ident_if_available(__isl_keep isl_stream *s) 732 1.1 mrg { 733 1.1 mrg struct isl_token *tok; 734 1.1 mrg 735 1.1 mrg tok = isl_stream_next_token(s); 736 1.1 mrg if (!tok) 737 1.1 mrg return NULL; 738 1.1 mrg if (tok->type == ISL_TOKEN_IDENT) { 739 1.1 mrg char *ident = strdup(tok->u.s); 740 1.1 mrg isl_token_free(tok); 741 1.1 mrg return ident; 742 1.1 mrg } 743 1.1 mrg isl_stream_push_token(s, tok); 744 1.1 mrg return NULL; 745 1.1 mrg } 746 1.1 mrg 747 1.1 mrg int isl_stream_eat(__isl_keep isl_stream *s, int type) 748 1.1 mrg { 749 1.1 mrg struct isl_token *tok; 750 1.1 mrg 751 1.1 mrg tok = isl_stream_next_token(s); 752 1.1 mrg if (!tok) { 753 1.1 mrg if (s->eof) 754 1.1 mrg isl_stream_error(s, NULL, "unexpected EOF"); 755 1.1 mrg return -1; 756 1.1 mrg } 757 1.1 mrg if (tok->type == type) { 758 1.1 mrg isl_token_free(tok); 759 1.1 mrg return 0; 760 1.1 mrg } 761 1.1 mrg isl_stream_error(s, tok, "expecting other token"); 762 1.1 mrg isl_token_free(tok); 763 1.1 mrg return -1; 764 1.1 mrg } 765 1.1 mrg 766 1.1 mrg int isl_stream_is_empty(__isl_keep isl_stream *s) 767 1.1 mrg { 768 1.1 mrg struct isl_token *tok; 769 1.1 mrg 770 1.1 mrg tok = isl_stream_next_token(s); 771 1.1 mrg 772 1.1 mrg if (!tok) 773 1.1 mrg return 1; 774 1.1 mrg 775 1.1 mrg isl_stream_push_token(s, tok); 776 1.1 mrg return 0; 777 1.1 mrg } 778 1.1 mrg 779 1.1 mrg static isl_stat free_keyword(void **p, void *user) 780 1.1 mrg { 781 1.1 mrg struct isl_keyword *keyword = *p; 782 1.1 mrg 783 1.1 mrg free(keyword->name); 784 1.1 mrg free(keyword); 785 1.1 mrg 786 1.1 mrg return isl_stat_ok; 787 1.1 mrg } 788 1.1 mrg 789 1.1 mrg void isl_stream_flush_tokens(__isl_keep isl_stream *s) 790 1.1 mrg { 791 1.1 mrg int i; 792 1.1 mrg 793 1.1 mrg if (!s) 794 1.1 mrg return; 795 1.1 mrg for (i = 0; i < s->n_token; ++i) 796 1.1 mrg isl_token_free(s->tokens[i]); 797 1.1 mrg s->n_token = 0; 798 1.1 mrg } 799 1.1 mrg 800 1.1 mrg isl_ctx *isl_stream_get_ctx(__isl_keep isl_stream *s) 801 1.1 mrg { 802 1.1 mrg return s ? s->ctx : NULL; 803 1.1 mrg } 804 1.1 mrg 805 1.1 mrg void isl_stream_free(__isl_take isl_stream *s) 806 1.1 mrg { 807 1.1 mrg if (!s) 808 1.1 mrg return; 809 1.1 mrg free(s->buffer); 810 1.1 mrg if (s->n_token != 0) { 811 1.1 mrg struct isl_token *tok = isl_stream_next_token(s); 812 1.1 mrg isl_stream_error(s, tok, "unexpected token"); 813 1.1 mrg isl_token_free(tok); 814 1.1 mrg } 815 1.1 mrg if (s->keywords) { 816 1.1 mrg isl_hash_table_foreach(s->ctx, s->keywords, &free_keyword, NULL); 817 1.1 mrg isl_hash_table_free(s->ctx, s->keywords); 818 1.1 mrg } 819 1.1 mrg free(s->yaml_state); 820 1.1 mrg free(s->yaml_indent); 821 1.1 mrg isl_ctx_deref(s->ctx); 822 1.1 mrg free(s); 823 1.1 mrg } 824 1.1 mrg 825 1.1 mrg /* Push "state" onto the stack of currently active YAML elements. 826 1.1 mrg * The caller is responsible for setting the corresponding indentation. 827 1.1 mrg * Return 0 on success and -1 on failure. 828 1.1 mrg */ 829 1.1 mrg static int push_state(__isl_keep isl_stream *s, enum isl_yaml_state state) 830 1.1 mrg { 831 1.1 mrg if (s->yaml_size < s->yaml_depth + 1) { 832 1.1 mrg int *indent; 833 1.1 mrg enum isl_yaml_state *state; 834 1.1 mrg 835 1.1 mrg state = isl_realloc_array(s->ctx, s->yaml_state, 836 1.1 mrg enum isl_yaml_state, s->yaml_depth + 1); 837 1.1 mrg if (!state) 838 1.1 mrg return -1; 839 1.1 mrg s->yaml_state = state; 840 1.1 mrg 841 1.1 mrg indent = isl_realloc_array(s->ctx, s->yaml_indent, 842 1.1 mrg int, s->yaml_depth + 1); 843 1.1 mrg if (!indent) 844 1.1 mrg return -1; 845 1.1 mrg s->yaml_indent = indent; 846 1.1 mrg 847 1.1 mrg s->yaml_size = s->yaml_depth + 1; 848 1.1 mrg } 849 1.1 mrg 850 1.1 mrg s->yaml_state[s->yaml_depth] = state; 851 1.1 mrg s->yaml_depth++; 852 1.1 mrg 853 1.1 mrg return 0; 854 1.1 mrg } 855 1.1 mrg 856 1.1 mrg /* Remove the innermost active YAML element from the stack. 857 1.1 mrg * Return isl_stat_ok on success and isl_stat_error on failure. 858 1.1 mrg */ 859 1.1 mrg static isl_stat pop_state(__isl_keep isl_stream *s) 860 1.1 mrg { 861 1.1 mrg if (!s) 862 1.1 mrg return isl_stat_error; 863 1.1 mrg if (s->yaml_depth < 1) 864 1.1 mrg isl_die(isl_stream_get_ctx(s), isl_error_invalid, 865 1.1 mrg "not in YAML construct", return isl_stat_error); 866 1.1 mrg 867 1.1 mrg s->yaml_depth--; 868 1.1 mrg 869 1.1 mrg return isl_stat_ok; 870 1.1 mrg } 871 1.1 mrg 872 1.1 mrg /* Set the state of the innermost active YAML element to "state". 873 1.1 mrg * Return 0 on success and -1 on failure. 874 1.1 mrg */ 875 1.1 mrg static int update_state(__isl_keep isl_stream *s, enum isl_yaml_state state) 876 1.1 mrg { 877 1.1 mrg if (!s) 878 1.1 mrg return -1; 879 1.1 mrg if (s->yaml_depth < 1) 880 1.1 mrg isl_die(isl_stream_get_ctx(s), isl_error_invalid, 881 1.1 mrg "not in YAML construct", return -1); 882 1.1 mrg 883 1.1 mrg s->yaml_state[s->yaml_depth - 1] = state; 884 1.1 mrg 885 1.1 mrg return 0; 886 1.1 mrg } 887 1.1 mrg 888 1.1 mrg /* Return the state of the innermost active YAML element. 889 1.1 mrg * Return isl_yaml_none if we are not inside any YAML element. 890 1.1 mrg */ 891 1.1 mrg static enum isl_yaml_state current_state(__isl_keep isl_stream *s) 892 1.1 mrg { 893 1.1 mrg if (!s) 894 1.1 mrg return isl_yaml_none; 895 1.1 mrg if (s->yaml_depth < 1) 896 1.1 mrg return isl_yaml_none; 897 1.1 mrg return s->yaml_state[s->yaml_depth - 1]; 898 1.1 mrg } 899 1.1 mrg 900 1.1 mrg /* Set the indentation of the innermost active YAML element to "indent". 901 1.1 mrg * If "indent" is equal to ISL_YAML_INDENT_FLOW, then this means 902 1.1 mrg * that the current element is in flow format. 903 1.1 mrg */ 904 1.1 mrg static isl_stat set_yaml_indent(__isl_keep isl_stream *s, int indent) 905 1.1 mrg { 906 1.1 mrg if (s->yaml_depth < 1) 907 1.1 mrg isl_die(s->ctx, isl_error_internal, 908 1.1 mrg "not in YAML element", return isl_stat_error); 909 1.1 mrg 910 1.1 mrg s->yaml_indent[s->yaml_depth - 1] = indent; 911 1.1 mrg 912 1.1 mrg return isl_stat_ok; 913 1.1 mrg } 914 1.1 mrg 915 1.1 mrg /* Return the indentation of the innermost active YAML element 916 1.1 mrg * of -1 on error. 917 1.1 mrg */ 918 1.1 mrg static int get_yaml_indent(__isl_keep isl_stream *s) 919 1.1 mrg { 920 1.1 mrg if (s->yaml_depth < 1) 921 1.1 mrg isl_die(s->ctx, isl_error_internal, 922 1.1 mrg "not in YAML element", return -1); 923 1.1 mrg 924 1.1 mrg return s->yaml_indent[s->yaml_depth - 1]; 925 1.1 mrg } 926 1.1 mrg 927 1.1 mrg /* Move to the next state at the innermost level. 928 1.1 mrg * Return isl_bool_true if successful. 929 1.1 mrg * Return isl_bool_false if we are at the end of the innermost level. 930 1.1 mrg * Return isl_bool_error on error. 931 1.1 mrg * 932 1.1 mrg * If we are in state isl_yaml_mapping_key_start, then we have just 933 1.1 mrg * started a mapping and we are expecting a key. If the mapping started 934 1.1 mrg * with a '{', then we check if the next token is a '}'. If so, 935 1.1 mrg * then the mapping is empty and there is no next state at this level. 936 1.1 mrg * Otherwise, we assume that there is at least one key (the one from 937 1.1 mrg * which we derived the indentation in isl_stream_yaml_read_start_mapping. 938 1.1 mrg * 939 1.1 mrg * If we are in state isl_yaml_mapping_key, then the we expect a colon 940 1.1 mrg * followed by a value, so there is always a next state unless 941 1.1 mrg * some error occurs. 942 1.1 mrg * 943 1.1 mrg * If we are in state isl_yaml_mapping_val, then there may or may 944 1.1 mrg * not be a subsequent key in the same mapping. 945 1.1 mrg * In flow format, the next key is preceded by a comma. 946 1.1 mrg * In block format, the next key has the same indentation as the first key. 947 1.1 mrg * If the first token has a smaller indentation, then we have reached 948 1.1 mrg * the end of the current mapping. 949 1.1 mrg * 950 1.1 mrg * If we are in state isl_yaml_sequence_start, then we have just 951 1.1 mrg * started a sequence. If the sequence started with a '[', 952 1.1 mrg * then we check if the next token is a ']'. If so, then the sequence 953 1.1 mrg * is empty and there is no next state at this level. 954 1.1 mrg * Otherwise, we assume that there is at least one element in the sequence 955 1.1 mrg * (the one from which we derived the indentation in 956 1.1 mrg * isl_stream_yaml_read_start_sequence. 957 1.1 mrg * 958 1.1 mrg * If we are in state isl_yaml_sequence, then there may or may 959 1.1 mrg * not be a subsequent element in the same sequence. 960 1.1 mrg * In flow format, the next element is preceded by a comma. 961 1.1 mrg * In block format, the next element is introduced by a dash with 962 1.1 mrg * the same indentation as that of the first element. 963 1.1 mrg * If the first token is not a dash or if it has a smaller indentation, 964 1.1 mrg * then we have reached the end of the current sequence. 965 1.1 mrg */ 966 1.1 mrg isl_bool isl_stream_yaml_next(__isl_keep isl_stream *s) 967 1.1 mrg { 968 1.1 mrg struct isl_token *tok; 969 1.1 mrg enum isl_yaml_state state; 970 1.1 mrg int indent; 971 1.1 mrg 972 1.1 mrg state = current_state(s); 973 1.1 mrg if (state == isl_yaml_none) 974 1.1 mrg isl_die(s->ctx, isl_error_invalid, 975 1.1 mrg "not in YAML element", return isl_bool_error); 976 1.1 mrg switch (state) { 977 1.1 mrg case isl_yaml_mapping_key_start: 978 1.1 mrg if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW && 979 1.1 mrg isl_stream_next_token_is(s, '}')) 980 1.1 mrg return isl_bool_false; 981 1.1 mrg if (update_state(s, isl_yaml_mapping_key) < 0) 982 1.1 mrg return isl_bool_error; 983 1.1 mrg return isl_bool_true; 984 1.1 mrg case isl_yaml_mapping_key: 985 1.1 mrg tok = isl_stream_next_token(s); 986 1.1 mrg if (!tok) { 987 1.1 mrg if (s->eof) 988 1.1 mrg isl_stream_error(s, NULL, "unexpected EOF"); 989 1.1 mrg return isl_bool_error; 990 1.1 mrg } 991 1.1 mrg if (tok->type == ':') { 992 1.1 mrg isl_token_free(tok); 993 1.1 mrg if (update_state(s, isl_yaml_mapping_val) < 0) 994 1.1 mrg return isl_bool_error; 995 1.1 mrg return isl_bool_true; 996 1.1 mrg } 997 1.1 mrg isl_stream_error(s, tok, "expecting ':'"); 998 1.1 mrg isl_stream_push_token(s, tok); 999 1.1 mrg return isl_bool_error; 1000 1.1 mrg case isl_yaml_mapping_val: 1001 1.1 mrg if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { 1002 1.1 mrg if (!isl_stream_eat_if_available(s, ',')) 1003 1.1 mrg return isl_bool_false; 1004 1.1 mrg if (update_state(s, isl_yaml_mapping_key) < 0) 1005 1.1 mrg return isl_bool_error; 1006 1.1 mrg return isl_bool_true; 1007 1.1 mrg } 1008 1.1 mrg tok = isl_stream_next_token(s); 1009 1.1 mrg if (!tok) 1010 1.1 mrg return isl_bool_false; 1011 1.1 mrg indent = tok->col - 1; 1012 1.1 mrg isl_stream_push_token(s, tok); 1013 1.1 mrg if (indent < get_yaml_indent(s)) 1014 1.1 mrg return isl_bool_false; 1015 1.1 mrg if (update_state(s, isl_yaml_mapping_key) < 0) 1016 1.1 mrg return isl_bool_error; 1017 1.1 mrg return isl_bool_true; 1018 1.1 mrg case isl_yaml_sequence_start: 1019 1.1 mrg if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { 1020 1.1 mrg if (isl_stream_next_token_is(s, ']')) 1021 1.1 mrg return isl_bool_false; 1022 1.1 mrg if (update_state(s, isl_yaml_sequence) < 0) 1023 1.1 mrg return isl_bool_error; 1024 1.1 mrg return isl_bool_true; 1025 1.1 mrg } 1026 1.1 mrg tok = isl_stream_next_token(s); 1027 1.1 mrg if (!tok) { 1028 1.1 mrg if (s->eof) 1029 1.1 mrg isl_stream_error(s, NULL, "unexpected EOF"); 1030 1.1 mrg return isl_bool_error; 1031 1.1 mrg } 1032 1.1 mrg if (tok->type == '-') { 1033 1.1 mrg isl_token_free(tok); 1034 1.1 mrg if (update_state(s, isl_yaml_sequence) < 0) 1035 1.1 mrg return isl_bool_error; 1036 1.1 mrg return isl_bool_true; 1037 1.1 mrg } 1038 1.1 mrg isl_stream_error(s, tok, "expecting '-'"); 1039 1.1 mrg isl_stream_push_token(s, tok); 1040 1.1 mrg return isl_bool_false; 1041 1.1 mrg case isl_yaml_sequence: 1042 1.1 mrg if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) 1043 1.1 mrg return isl_bool_ok(isl_stream_eat_if_available(s, ',')); 1044 1.1 mrg tok = isl_stream_next_token(s); 1045 1.1 mrg if (!tok) 1046 1.1 mrg return isl_bool_false; 1047 1.1 mrg indent = tok->col - 1; 1048 1.1 mrg if (indent < get_yaml_indent(s) || tok->type != '-') { 1049 1.1 mrg isl_stream_push_token(s, tok); 1050 1.1 mrg return isl_bool_false; 1051 1.1 mrg } 1052 1.1 mrg isl_token_free(tok); 1053 1.1 mrg return isl_bool_true; 1054 1.1 mrg default: 1055 1.1 mrg isl_die(s->ctx, isl_error_internal, 1056 1.1 mrg "unexpected state", return isl_bool_error); 1057 1.1 mrg } 1058 1.1 mrg } 1059 1.1 mrg 1060 1.1 mrg /* Start reading a YAML mapping. 1061 1.1 mrg * Return isl_stat_ok on success and isl_stat_error on error. 1062 1.1 mrg * 1063 1.1 mrg * If the first token on the stream is a '{' then we remove this token 1064 1.1 mrg * from the stream and keep track of the fact that the mapping 1065 1.1 mrg * is given in flow format. 1066 1.1 mrg * Otherwise, we assume the first token is the first key of the mapping and 1067 1.1 mrg * keep track of its indentation, but keep the token on the stream. 1068 1.1 mrg * In both cases, the next token we expect is the first key of the mapping. 1069 1.1 mrg */ 1070 1.1 mrg isl_stat isl_stream_yaml_read_start_mapping(__isl_keep isl_stream *s) 1071 1.1 mrg { 1072 1.1 mrg struct isl_token *tok; 1073 1.1 mrg int indent; 1074 1.1 mrg 1075 1.1 mrg if (push_state(s, isl_yaml_mapping_key_start) < 0) 1076 1.1 mrg return isl_stat_error; 1077 1.1 mrg 1078 1.1 mrg tok = isl_stream_next_token(s); 1079 1.1 mrg if (!tok) { 1080 1.1 mrg if (s->eof) 1081 1.1 mrg isl_stream_error(s, NULL, "unexpected EOF"); 1082 1.1 mrg return isl_stat_error; 1083 1.1 mrg } 1084 1.1 mrg if (isl_token_get_type(tok) == '{') { 1085 1.1 mrg isl_token_free(tok); 1086 1.1 mrg return set_yaml_indent(s, ISL_YAML_INDENT_FLOW); 1087 1.1 mrg } 1088 1.1 mrg indent = tok->col - 1; 1089 1.1 mrg isl_stream_push_token(s, tok); 1090 1.1 mrg 1091 1.1 mrg return set_yaml_indent(s, indent); 1092 1.1 mrg } 1093 1.1 mrg 1094 1.1 mrg /* Finish reading a YAML mapping. 1095 1.1 mrg * Return isl_stat_ok on success and isl_stat_error on error. 1096 1.1 mrg * 1097 1.1 mrg * If the mapping started with a '{', then we expect a '}' to close 1098 1.1 mrg * the mapping. 1099 1.1 mrg * Otherwise, we double-check that the next token (if any) 1100 1.1 mrg * has a smaller indentation than that of the current mapping. 1101 1.1 mrg */ 1102 1.1 mrg isl_stat isl_stream_yaml_read_end_mapping(__isl_keep isl_stream *s) 1103 1.1 mrg { 1104 1.1 mrg struct isl_token *tok; 1105 1.1 mrg int indent; 1106 1.1 mrg 1107 1.1 mrg if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { 1108 1.1 mrg if (isl_stream_eat(s, '}') < 0) 1109 1.1 mrg return isl_stat_error; 1110 1.1 mrg return pop_state(s); 1111 1.1 mrg } 1112 1.1 mrg 1113 1.1 mrg tok = isl_stream_next_token(s); 1114 1.1 mrg if (!tok) 1115 1.1 mrg return pop_state(s); 1116 1.1 mrg 1117 1.1 mrg indent = tok->col - 1; 1118 1.1 mrg isl_stream_push_token(s, tok); 1119 1.1 mrg 1120 1.1 mrg if (indent >= get_yaml_indent(s)) 1121 1.1 mrg isl_die(isl_stream_get_ctx(s), isl_error_invalid, 1122 1.1 mrg "mapping not finished", return isl_stat_error); 1123 1.1 mrg 1124 1.1 mrg return pop_state(s); 1125 1.1 mrg } 1126 1.1 mrg 1127 1.1 mrg /* Start reading a YAML sequence. 1128 1.1 mrg * Return isl_stat_ok on success and isl_stat_error on error. 1129 1.1 mrg * 1130 1.1 mrg * If the first token on the stream is a '[' then we remove this token 1131 1.1 mrg * from the stream and keep track of the fact that the sequence 1132 1.1 mrg * is given in flow format. 1133 1.1 mrg * Otherwise, we assume the first token is the dash that introduces 1134 1.1 mrg * the first element of the sequence and keep track of its indentation, 1135 1.1 mrg * but keep the token on the stream. 1136 1.1 mrg * In both cases, the next token we expect is the first element 1137 1.1 mrg * of the sequence. 1138 1.1 mrg */ 1139 1.1 mrg isl_stat isl_stream_yaml_read_start_sequence(__isl_keep isl_stream *s) 1140 1.1 mrg { 1141 1.1 mrg struct isl_token *tok; 1142 1.1 mrg int indent; 1143 1.1 mrg 1144 1.1 mrg if (push_state(s, isl_yaml_sequence_start) < 0) 1145 1.1 mrg return isl_stat_error; 1146 1.1 mrg 1147 1.1 mrg tok = isl_stream_next_token(s); 1148 1.1 mrg if (!tok) { 1149 1.1 mrg if (s->eof) 1150 1.1 mrg isl_stream_error(s, NULL, "unexpected EOF"); 1151 1.1 mrg return isl_stat_error; 1152 1.1 mrg } 1153 1.1 mrg if (isl_token_get_type(tok) == '[') { 1154 1.1 mrg isl_token_free(tok); 1155 1.1 mrg return set_yaml_indent(s, ISL_YAML_INDENT_FLOW); 1156 1.1 mrg } 1157 1.1 mrg indent = tok->col - 1; 1158 1.1 mrg isl_stream_push_token(s, tok); 1159 1.1 mrg 1160 1.1 mrg return set_yaml_indent(s, indent); 1161 1.1 mrg } 1162 1.1 mrg 1163 1.1 mrg /* Finish reading a YAML sequence. 1164 1.1 mrg * Return isl_stat_ok on success and isl_stat_error on error. 1165 1.1 mrg * 1166 1.1 mrg * If the sequence started with a '[', then we expect a ']' to close 1167 1.1 mrg * the sequence. 1168 1.1 mrg * Otherwise, we double-check that the next token (if any) 1169 1.1 mrg * is not a dash or that it has a smaller indentation than 1170 1.1 mrg * that of the current sequence. 1171 1.1 mrg */ 1172 1.1 mrg isl_stat isl_stream_yaml_read_end_sequence(__isl_keep isl_stream *s) 1173 1.1 mrg { 1174 1.1 mrg struct isl_token *tok; 1175 1.1 mrg int indent; 1176 1.1 mrg int dash; 1177 1.1 mrg 1178 1.1 mrg if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { 1179 1.1 mrg if (isl_stream_eat(s, ']') < 0) 1180 1.1 mrg return isl_stat_error; 1181 1.1 mrg return pop_state(s); 1182 1.1 mrg } 1183 1.1 mrg 1184 1.1 mrg tok = isl_stream_next_token(s); 1185 1.1 mrg if (!tok) 1186 1.1 mrg return pop_state(s); 1187 1.1 mrg 1188 1.1 mrg indent = tok->col - 1; 1189 1.1 mrg dash = tok->type == '-'; 1190 1.1 mrg isl_stream_push_token(s, tok); 1191 1.1 mrg 1192 1.1 mrg if (indent >= get_yaml_indent(s) && dash) 1193 1.1 mrg isl_die(isl_stream_get_ctx(s), isl_error_invalid, 1194 1.1 mrg "sequence not finished", return isl_stat_error); 1195 1.1 mrg 1196 1.1 mrg return pop_state(s); 1197 1.1 mrg } 1198