7ead4116ed5b2cc2a18a5cfea02318addab88135
[platform/upstream/isl.git] / isl_stream.c
1 /*
2  * Copyright 2008-2009 Katholieke Universiteit Leuven
3  *
4  * Use of this software is governed by the MIT license
5  *
6  * Written by Sven Verdoolaege, K.U.Leuven, Departement
7  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
8  */
9
10 #include <ctype.h>
11 #include <string.h>
12 #include <strings.h>
13 #include <isl/ctx.h>
14 #include <isl_stream_private.h>
15 #include <isl/map.h>
16 #include <isl/aff.h>
17 #include <isl_val_private.h>
18
19 struct isl_keyword {
20         char                    *name;
21         enum isl_token_type     type;
22 };
23
24 static int same_name(const void *entry, const void *val)
25 {
26         const struct isl_keyword *keyword = (const struct isl_keyword *)entry;
27
28         return !strcmp(keyword->name, val);
29 }
30
31 enum isl_token_type isl_stream_register_keyword(struct isl_stream *s,
32         const char *name)
33 {
34         struct isl_hash_table_entry *entry;
35         struct isl_keyword *keyword;
36         uint32_t name_hash;
37
38         if (!s->keywords) {
39                 s->keywords = isl_hash_table_alloc(s->ctx, 10);
40                 if (!s->keywords)
41                         return ISL_TOKEN_ERROR;
42                 s->next_type = ISL_TOKEN_LAST;
43         }
44
45         name_hash = isl_hash_string(isl_hash_init(), name);
46
47         entry = isl_hash_table_find(s->ctx, s->keywords, name_hash,
48                                         same_name, name, 1);
49         if (!entry)
50                 return ISL_TOKEN_ERROR;
51         if (entry->data) {
52                 keyword = entry->data;
53                 return keyword->type;
54         }
55
56         keyword = isl_calloc_type(s->ctx, struct isl_keyword);
57         if (!keyword)
58                 return ISL_TOKEN_ERROR;
59         keyword->type = s->next_type++;
60         keyword->name = strdup(name);
61         if (!keyword->name) {
62                 free(keyword);
63                 return ISL_TOKEN_ERROR;
64         }
65         entry->data = keyword;
66
67         return keyword->type;
68 }
69
70 struct isl_token *isl_token_new(isl_ctx *ctx,
71         int line, int col, unsigned on_new_line)
72 {
73         struct isl_token *tok = isl_alloc_type(ctx, struct isl_token);
74         if (!tok)
75                 return NULL;
76         tok->line = line;
77         tok->col = col;
78         tok->on_new_line = on_new_line;
79         tok->is_keyword = 0;
80         tok->u.s = NULL;
81         return tok;
82 }
83
84 /* Given a token of type ISL_TOKEN_VALUE, return the value it represents.
85  */
86 __isl_give isl_val *isl_token_get_val(isl_ctx *ctx, struct isl_token *tok)
87 {
88         if (!tok)
89                 return NULL;
90         if (tok->type != ISL_TOKEN_VALUE)
91                 isl_die(ctx, isl_error_invalid, "not a value token",
92                         return NULL);
93
94         return isl_val_int_from_isl_int(ctx, tok->u.v);
95 }
96
97 void isl_token_free(struct isl_token *tok)
98 {
99         if (!tok)
100                 return;
101         if (tok->type == ISL_TOKEN_VALUE)
102                 isl_int_clear(tok->u.v);
103         else if (tok->type == ISL_TOKEN_MAP)
104                 isl_map_free(tok->u.map);
105         else if (tok->type == ISL_TOKEN_AFF)
106                 isl_pw_aff_free(tok->u.pwaff);
107         else
108                 free(tok->u.s);
109         free(tok);
110 }
111
112 void isl_stream_error(struct isl_stream *s, struct isl_token *tok, char *msg)
113 {
114         int line = tok ? tok->line : s->line;
115         int col = tok ? tok->col : s->col;
116         fprintf(stderr, "syntax error (%d, %d): %s\n", line, col, msg);
117         if (tok) {
118                 if (tok->type < 256)
119                         fprintf(stderr, "got '%c'\n", tok->type);
120                 else if (tok->type == ISL_TOKEN_IDENT)
121                         fprintf(stderr, "got ident '%s'\n", tok->u.s);
122                 else if (tok->is_keyword)
123                         fprintf(stderr, "got keyword '%s'\n", tok->u.s);
124                 else if (tok->type == ISL_TOKEN_VALUE) {
125                         fprintf(stderr, "got value '");
126                         isl_int_print(stderr, tok->u.v, 0);
127                         fprintf(stderr, "'\n");
128                 } else if (tok->type == ISL_TOKEN_MAP) {
129                         isl_printer *p;
130                         fprintf(stderr, "got map '");
131                         p = isl_printer_to_file(s->ctx, stderr);
132                         p = isl_printer_print_map(p, tok->u.map);
133                         isl_printer_free(p);
134                         fprintf(stderr, "'\n");
135                 } else if (tok->type == ISL_TOKEN_AFF) {
136                         isl_printer *p;
137                         fprintf(stderr, "got affine expression '");
138                         p = isl_printer_to_file(s->ctx, stderr);
139                         p = isl_printer_print_pw_aff(p, tok->u.pwaff);
140                         isl_printer_free(p);
141                         fprintf(stderr, "'\n");
142                 } else if (tok->u.s)
143                         fprintf(stderr, "got token '%s'\n", tok->u.s);
144                 else
145                         fprintf(stderr, "got token type %d\n", tok->type);
146         }
147 }
148
149 static struct isl_stream* isl_stream_new(struct isl_ctx *ctx)
150 {
151         int i;
152         struct isl_stream *s = isl_alloc_type(ctx, struct isl_stream);
153         if (!s)
154                 return NULL;
155         s->ctx = ctx;
156         isl_ctx_ref(s->ctx);
157         s->file = NULL;
158         s->str = NULL;
159         s->len = 0;
160         s->line = 1;
161         s->col = 0;
162         s->eof = 0;
163         s->c = -1;
164         s->n_un = 0;
165         for (i = 0; i < 5; ++i)
166                 s->tokens[i] = NULL;
167         s->n_token = 0;
168         s->keywords = NULL;
169         s->size = 256;
170         s->buffer = isl_alloc_array(ctx, char, s->size);
171         if (!s->buffer)
172                 goto error;
173         return s;
174 error:
175         isl_stream_free(s);
176         return NULL;
177 }
178
179 struct isl_stream* isl_stream_new_file(struct isl_ctx *ctx, FILE *file)
180 {
181         struct isl_stream *s = isl_stream_new(ctx);
182         if (!s)
183                 return NULL;
184         s->file = file;
185         return s;
186 }
187
188 struct isl_stream* isl_stream_new_str(struct isl_ctx *ctx, const char *str)
189 {
190         struct isl_stream *s;
191         if (!str)
192                 return NULL;
193         s = isl_stream_new(ctx);
194         if (!s)
195                 return NULL;
196         s->str = str;
197         return s;
198 }
199
200 static int stream_getc(struct isl_stream *s)
201 {
202         int c;
203         if (s->eof)
204                 return -1;
205         if (s->n_un)
206                 return s->c = s->un[--s->n_un];
207         if (s->file)
208                 c = fgetc(s->file);
209         else {
210                 c = *s->str++;
211                 if (c == '\0')
212                         c = -1;
213         }
214         if (c == -1)
215                 s->eof = 1;
216         if (!s->eof) {
217                 if (s->c == '\n') {
218                         s->line++;
219                         s->col = 0;
220                 } else
221                         s->col++;
222         }
223         s->c = c;
224         return c;
225 }
226
227 static void isl_stream_ungetc(struct isl_stream *s, int c)
228 {
229         isl_assert(s->ctx, s->n_un < 5, return);
230         s->un[s->n_un++] = c;
231         s->c = -1;
232 }
233
234 static int isl_stream_getc(struct isl_stream *s)
235 {
236         int c;
237
238         do {
239                 c = stream_getc(s);
240                 if (c != '\\')
241                         return c;
242                 c = stream_getc(s);
243         } while (c == '\n');
244
245         isl_stream_ungetc(s, c);
246
247         return '\\';
248 }
249
250 static int isl_stream_push_char(struct isl_stream *s, int c)
251 {
252         if (s->len >= s->size) {
253                 char *buffer;
254                 s->size = (3*s->size)/2;
255                 buffer = isl_realloc_array(s->ctx, s->buffer, char, s->size);
256                 if (!buffer)
257                         return -1;
258                 s->buffer = buffer;
259         }
260         s->buffer[s->len++] = c;
261         return 0;
262 }
263
264 void isl_stream_push_token(struct isl_stream *s, struct isl_token *tok)
265 {
266         isl_assert(s->ctx, s->n_token < 5, return);
267         s->tokens[s->n_token++] = tok;
268 }
269
270 static enum isl_token_type check_keywords(struct isl_stream *s)
271 {
272         struct isl_hash_table_entry *entry;
273         struct isl_keyword *keyword;
274         uint32_t name_hash;
275
276         if (!strcasecmp(s->buffer, "exists"))
277                 return ISL_TOKEN_EXISTS;
278         if (!strcasecmp(s->buffer, "and"))
279                 return ISL_TOKEN_AND;
280         if (!strcasecmp(s->buffer, "or"))
281                 return ISL_TOKEN_OR;
282         if (!strcasecmp(s->buffer, "not"))
283                 return ISL_TOKEN_NOT;
284         if (!strcasecmp(s->buffer, "infty"))
285                 return ISL_TOKEN_INFTY;
286         if (!strcasecmp(s->buffer, "infinity"))
287                 return ISL_TOKEN_INFTY;
288         if (!strcasecmp(s->buffer, "NaN"))
289                 return ISL_TOKEN_NAN;
290         if (!strcasecmp(s->buffer, "min"))
291                 return ISL_TOKEN_MIN;
292         if (!strcasecmp(s->buffer, "max"))
293                 return ISL_TOKEN_MAX;
294         if (!strcasecmp(s->buffer, "rat"))
295                 return ISL_TOKEN_RAT;
296         if (!strcasecmp(s->buffer, "true"))
297                 return ISL_TOKEN_TRUE;
298         if (!strcasecmp(s->buffer, "false"))
299                 return ISL_TOKEN_FALSE;
300         if (!strcasecmp(s->buffer, "ceild"))
301                 return ISL_TOKEN_CEILD;
302         if (!strcasecmp(s->buffer, "floord"))
303                 return ISL_TOKEN_FLOORD;
304         if (!strcasecmp(s->buffer, "mod"))
305                 return ISL_TOKEN_MOD;
306
307         if (!s->keywords)
308                 return ISL_TOKEN_IDENT;
309
310         name_hash = isl_hash_string(isl_hash_init(), s->buffer);
311         entry = isl_hash_table_find(s->ctx, s->keywords, name_hash, same_name,
312                                         s->buffer, 0);
313         if (entry) {
314                 keyword = entry->data;
315                 return keyword->type;
316         }
317
318         return ISL_TOKEN_IDENT;
319 }
320
321 int isl_stream_skip_line(struct isl_stream *s)
322 {
323         int c;
324
325         while ((c = isl_stream_getc(s)) != -1 && c != '\n')
326                 /* nothing */
327                 ;
328
329         return c == -1 ? -1 : 0;
330 }
331
332 static struct isl_token *next_token(struct isl_stream *s, int same_line)
333 {
334         int c;
335         struct isl_token *tok = NULL;
336         int line, col;
337         int old_line = s->line;
338
339         if (s->n_token) {
340                 if (same_line && s->tokens[s->n_token - 1]->on_new_line)
341                         return NULL;
342                 return s->tokens[--s->n_token];
343         }
344
345         if (same_line && s->c == '\n')
346                 return NULL;
347
348         s->len = 0;
349
350         /* skip spaces and comment lines */
351         while ((c = isl_stream_getc(s)) != -1) {
352                 if (c == '#') {
353                         if (isl_stream_skip_line(s) < 0)
354                                 break;
355                         c = '\n';
356                         if (same_line)
357                                 break;
358                 } else if (!isspace(c) || (same_line && c == '\n'))
359                         break;
360         }
361
362         line = s->line;
363         col = s->col;
364
365         if (c == -1 || (same_line && c == '\n'))
366                 return NULL;
367         if (c == '(' ||
368             c == ')' ||
369             c == '+' ||
370             c == '*' ||
371             c == '%' ||
372             c == '?' ||
373             c == '^' ||
374             c == '@' ||
375             c == '$' ||
376             c == ',' ||
377             c == '.' ||
378             c == ';' ||
379             c == '[' ||
380             c == ']' ||
381             c == '{' ||
382             c == '}') {
383                 tok = isl_token_new(s->ctx, line, col, old_line != line);
384                 if (!tok)
385                         return NULL;
386                 tok->type = (enum isl_token_type)c;
387                 return tok;
388         }
389         if (c == '-') {
390                 int c;
391                 if ((c = isl_stream_getc(s)) == '>') {
392                         tok = isl_token_new(s->ctx, line, col, old_line != line);
393                         if (!tok)
394                                 return NULL;
395                         tok->u.s = strdup("->");
396                         tok->type = ISL_TOKEN_TO;
397                         return tok;
398                 }
399                 if (c != -1)
400                         isl_stream_ungetc(s, c);
401                 if (!isdigit(c)) {
402                         tok = isl_token_new(s->ctx, line, col, old_line != line);
403                         if (!tok)
404                                 return NULL;
405                         tok->type = (enum isl_token_type) '-';
406                         return tok;
407                 }
408         }
409         if (c == '-' || isdigit(c)) {
410                 int minus = c == '-';
411                 tok = isl_token_new(s->ctx, line, col, old_line != line);
412                 if (!tok)
413                         return NULL;
414                 tok->type = ISL_TOKEN_VALUE;
415                 isl_int_init(tok->u.v);
416                 if (isl_stream_push_char(s, c))
417                         goto error;
418                 while ((c = isl_stream_getc(s)) != -1 && isdigit(c))
419                         if (isl_stream_push_char(s, c))
420                                 goto error;
421                 if (c != -1)
422                         isl_stream_ungetc(s, c);
423                 isl_stream_push_char(s, '\0');
424                 isl_int_read(tok->u.v, s->buffer);
425                 if (minus && isl_int_is_zero(tok->u.v)) {
426                         tok->col++;
427                         tok->on_new_line = 0;
428                         isl_stream_push_token(s, tok);
429                         tok = isl_token_new(s->ctx, line, col, old_line != line);
430                         if (!tok)
431                                 return NULL;
432                         tok->type = (enum isl_token_type) '-';
433                 }
434                 return tok;
435         }
436         if (isalpha(c) || c == '_') {
437                 tok = isl_token_new(s->ctx, line, col, old_line != line);
438                 if (!tok)
439                         return NULL;
440                 isl_stream_push_char(s, c);
441                 while ((c = isl_stream_getc(s)) != -1 &&
442                                 (isalnum(c) || c == '_'))
443                         isl_stream_push_char(s, c);
444                 if (c != -1)
445                         isl_stream_ungetc(s, c);
446                 while ((c = isl_stream_getc(s)) != -1 && c == '\'')
447                         isl_stream_push_char(s, c);
448                 if (c != -1)
449                         isl_stream_ungetc(s, c);
450                 isl_stream_push_char(s, '\0');
451                 tok->type = check_keywords(s);
452                 if (tok->type != ISL_TOKEN_IDENT)
453                         tok->is_keyword = 1;
454                 tok->u.s = strdup(s->buffer);
455                 if (!tok->u.s)
456                         goto error;
457                 return tok;
458         }
459         if (c == '"') {
460                 tok = isl_token_new(s->ctx, line, col, old_line != line);
461                 if (!tok)
462                         return NULL;
463                 tok->type = ISL_TOKEN_STRING;
464                 tok->u.s = NULL;
465                 while ((c = isl_stream_getc(s)) != -1 && c != '"' && c != '\n')
466                         isl_stream_push_char(s, c);
467                 if (c != '"') {
468                         isl_stream_error(s, NULL, "unterminated string");
469                         goto error;
470                 }
471                 isl_stream_push_char(s, '\0');
472                 tok->u.s = strdup(s->buffer);
473                 return tok;
474         }
475         if (c == '=') {
476                 int c;
477                 tok = isl_token_new(s->ctx, line, col, old_line != line);
478                 if (!tok)
479                         return NULL;
480                 if ((c = isl_stream_getc(s)) == '=') {
481                         tok->u.s = strdup("==");
482                         tok->type = ISL_TOKEN_EQ_EQ;
483                         return tok;
484                 }
485                 if (c != -1)
486                         isl_stream_ungetc(s, c);
487                 tok->type = (enum isl_token_type) '=';
488                 return tok;
489         }
490         if (c == ':') {
491                 int c;
492                 tok = isl_token_new(s->ctx, line, col, old_line != line);
493                 if (!tok)
494                         return NULL;
495                 if ((c = isl_stream_getc(s)) == '=') {
496                         tok->u.s = strdup(":=");
497                         tok->type = ISL_TOKEN_DEF;
498                         return tok;
499                 }
500                 if (c != -1)
501                         isl_stream_ungetc(s, c);
502                 tok->type = (enum isl_token_type) ':';
503                 return tok;
504         }
505         if (c == '>') {
506                 int c;
507                 tok = isl_token_new(s->ctx, line, col, old_line != line);
508                 if (!tok)
509                         return NULL;
510                 if ((c = isl_stream_getc(s)) == '=') {
511                         tok->u.s = strdup(">=");
512                         tok->type = ISL_TOKEN_GE;
513                         return tok;
514                 } else if (c == '>') {
515                         if ((c = isl_stream_getc(s)) == '=') {
516                                 tok->u.s = strdup(">>=");
517                                 tok->type = ISL_TOKEN_LEX_GE;
518                                 return tok;
519                         }
520                         tok->u.s = strdup(">>");
521                         tok->type = ISL_TOKEN_LEX_GT;
522                 } else {
523                         tok->u.s = strdup(">");
524                         tok->type = ISL_TOKEN_GT;
525                 }
526                 if (c != -1)
527                         isl_stream_ungetc(s, c);
528                 return tok;
529         }
530         if (c == '<') {
531                 int c;
532                 tok = isl_token_new(s->ctx, line, col, old_line != line);
533                 if (!tok)
534                         return NULL;
535                 if ((c = isl_stream_getc(s)) == '=') {
536                         tok->u.s = strdup("<=");
537                         tok->type = ISL_TOKEN_LE;
538                         return tok;
539                 } else if (c == '<') {
540                         if ((c = isl_stream_getc(s)) == '=') {
541                                 tok->u.s = strdup("<<=");
542                                 tok->type = ISL_TOKEN_LEX_LE;
543                                 return tok;
544                         }
545                         tok->u.s = strdup("<<");
546                         tok->type = ISL_TOKEN_LEX_LT;
547                 } else {
548                         tok->u.s = strdup("<");
549                         tok->type = ISL_TOKEN_LT;
550                 }
551                 if (c != -1)
552                         isl_stream_ungetc(s, c);
553                 return tok;
554         }
555         if (c == '&') {
556                 tok = isl_token_new(s->ctx, line, col, old_line != line);
557                 if (!tok)
558                         return NULL;
559                 tok->type = ISL_TOKEN_AND;
560                 if ((c = isl_stream_getc(s)) != '&' && c != -1) {
561                         tok->u.s = strdup("&");
562                         isl_stream_ungetc(s, c);
563                 } else
564                         tok->u.s = strdup("&&");
565                 return tok;
566         }
567         if (c == '|') {
568                 tok = isl_token_new(s->ctx, line, col, old_line != line);
569                 if (!tok)
570                         return NULL;
571                 tok->type = ISL_TOKEN_OR;
572                 if ((c = isl_stream_getc(s)) != '|' && c != -1) {
573                         tok->u.s = strdup("|");
574                         isl_stream_ungetc(s, c);
575                 } else
576                         tok->u.s = strdup("||");
577                 return tok;
578         }
579         if (c == '/') {
580                 tok = isl_token_new(s->ctx, line, col, old_line != line);
581                 if (!tok)
582                         return NULL;
583                 if ((c = isl_stream_getc(s)) != '\\' && c != -1) {
584                         tok->type = (enum isl_token_type) '/';
585                         isl_stream_ungetc(s, c);
586                 } else {
587                         tok->u.s = strdup("/\\");
588                         tok->type = ISL_TOKEN_AND;
589                 }
590                 return tok;
591         }
592         if (c == '\\') {
593                 tok = isl_token_new(s->ctx, line, col, old_line != line);
594                 if (!tok)
595                         return NULL;
596                 if ((c = isl_stream_getc(s)) != '/' && c != -1) {
597                         tok->type = (enum isl_token_type) '\\';
598                         isl_stream_ungetc(s, c);
599                 } else {
600                         tok->u.s = strdup("\\/");
601                         tok->type = ISL_TOKEN_OR;
602                 }
603                 return tok;
604         }
605         if (c == '!') {
606                 tok = isl_token_new(s->ctx, line, col, old_line != line);
607                 if (!tok)
608                         return NULL;
609                 if ((c = isl_stream_getc(s)) == '=') {
610                         tok->u.s = strdup("!=");
611                         tok->type = ISL_TOKEN_NE;
612                         return tok;
613                 } else {
614                         tok->type = ISL_TOKEN_NOT;
615                         tok->u.s = strdup("!");
616                 }
617                 if (c != -1)
618                         isl_stream_ungetc(s, c);
619                 return tok;
620         }
621
622         tok = isl_token_new(s->ctx, line, col, old_line != line);
623         if (!tok)
624                 return NULL;
625         tok->type = ISL_TOKEN_UNKNOWN;
626         return tok;
627 error:
628         isl_token_free(tok);
629         return NULL;
630 }
631
632 struct isl_token *isl_stream_next_token(struct isl_stream *s)
633 {
634         return next_token(s, 0);
635 }
636
637 struct isl_token *isl_stream_next_token_on_same_line(struct isl_stream *s)
638 {
639         return next_token(s, 1);
640 }
641
642 int isl_stream_eat_if_available(struct isl_stream *s, int type)
643 {
644         struct isl_token *tok;
645
646         tok = isl_stream_next_token(s);
647         if (!tok)
648                 return 0;
649         if (tok->type == type) {
650                 isl_token_free(tok);
651                 return 1;
652         }
653         isl_stream_push_token(s, tok);
654         return 0;
655 }
656
657 int isl_stream_next_token_is(struct isl_stream *s, int type)
658 {
659         struct isl_token *tok;
660         int r;
661
662         tok = isl_stream_next_token(s);
663         if (!tok)
664                 return 0;
665         r = tok->type == type;
666         isl_stream_push_token(s, tok);
667         return r;
668 }
669
670 char *isl_stream_read_ident_if_available(struct isl_stream *s)
671 {
672         struct isl_token *tok;
673
674         tok = isl_stream_next_token(s);
675         if (!tok)
676                 return NULL;
677         if (tok->type == ISL_TOKEN_IDENT) {
678                 char *ident = strdup(tok->u.s);
679                 isl_token_free(tok);
680                 return ident;
681         }
682         isl_stream_push_token(s, tok);
683         return NULL;
684 }
685
686 int isl_stream_eat(struct isl_stream *s, int type)
687 {
688         struct isl_token *tok;
689
690         tok = isl_stream_next_token(s);
691         if (!tok)
692                 return -1;
693         if (tok->type == type) {
694                 isl_token_free(tok);
695                 return 0;
696         }
697         isl_stream_error(s, tok, "expecting other token");
698         isl_stream_push_token(s, tok);
699         return -1;
700 }
701
702 int isl_stream_is_empty(struct isl_stream *s)
703 {
704         struct isl_token *tok;
705
706         tok = isl_stream_next_token(s);
707
708         if (!tok)
709                 return 1;
710
711         isl_stream_push_token(s, tok);
712         return 0;
713 }
714
715 static int free_keyword(void **p, void *user)
716 {
717         struct isl_keyword *keyword = *p;
718
719         free(keyword->name);
720         free(keyword);
721
722         return 0;
723 }
724
725 void isl_stream_flush_tokens(struct isl_stream *s)
726 {
727         int i;
728
729         if (!s)
730                 return;
731         for (i = 0; i < s->n_token; ++i)
732                 isl_token_free(s->tokens[i]);
733         s->n_token = 0;
734 }
735
736 void isl_stream_free(struct isl_stream *s)
737 {
738         if (!s)
739                 return;
740         free(s->buffer);
741         if (s->n_token != 0) {
742                 struct isl_token *tok = isl_stream_next_token(s);
743                 isl_stream_error(s, tok, "unexpected token");
744                 isl_token_free(tok);
745         }
746         if (s->keywords) {
747                 isl_hash_table_foreach(s->ctx, s->keywords, &free_keyword, NULL);
748                 isl_hash_table_free(s->ctx, s->keywords);
749         }
750         isl_ctx_deref(s->ctx);
751         free(s);
752 }