Copyright updates
[platform/upstream/libxkbcommon.git] / src / xkbcomp / ast-build.c
1 /************************************************************
2  * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3  *
4  * Permission to use, copy, modify, and distribute this
5  * software and its documentation for any purpose and without
6  * fee is hereby granted, provided that the above copyright
7  * notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting
9  * documentation, and that the name of Silicon Graphics not be
10  * used in advertising or publicity pertaining to distribution
11  * of the software without specific prior written permission.
12  * Silicon Graphics makes no representation about the suitability
13  * of this software for any purpose. It is provided "as is"
14  * without any express or implied warranty.
15  *
16  * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18  * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19  * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23  * THE USE OR PERFORMANCE OF THIS SOFTWARE.
24  *
25  ********************************************************/
26
27 /*
28  * Copyright © 2012 Intel Corporation
29  * Copyright © 2012 Ran Benita <ran234@gmail.com>
30  *
31  * Permission is hereby granted, free of charge, to any person obtaining a
32  * copy of this software and associated documentation files (the "Software"),
33  * to deal in the Software without restriction, including without limitation
34  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
35  * and/or sell copies of the Software, and to permit persons to whom the
36  * Software is furnished to do so, subject to the following conditions:
37  *
38  * The above copyright notice and this permission notice (including the next
39  * paragraph) shall be included in all copies or substantial portions of the
40  * Software.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
45  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
47  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
48  * DEALINGS IN THE SOFTWARE.
49  *
50  * Author: Daniel Stone <daniel@fooishbar.org>
51  *         Ran Benita <ran234@gmail.com>
52  */
53
54 #include "xkbcomp-priv.h"
55 #include "ast-build.h"
56 #include "parser-priv.h"
57 #include "include.h"
58
59 ATTR_MALLOC static void *
60 malloc_or_die(size_t size)
61 {
62     void *p = malloc(size);
63     if (!p) {
64         fprintf(stderr, "Out of memory\n");
65         exit(1);
66     }
67     return p;
68 }
69
70 ParseCommon *
71 AppendStmt(ParseCommon * to, ParseCommon * append)
72 {
73     ParseCommon *start = to;
74
75     if (append == NULL)
76         return to;
77     while ((to != NULL) && (to->next != NULL))
78     {
79         to = to->next;
80     }
81     if (to) {
82         to->next = append;
83         return start;
84     }
85     return append;
86 }
87
88 ExprDef *
89 ExprCreate(enum expr_op_type op, enum expr_value_type type)
90 {
91     ExprDef *expr;
92
93     expr = malloc_or_die(sizeof(*expr));
94
95     expr->common.type = STMT_EXPR;
96     expr->common.next = NULL;
97     expr->op = op;
98     expr->value_type = type;
99     return expr;
100 }
101
102 ExprDef *
103 ExprCreateUnary(enum expr_op_type op, enum expr_value_type type,
104                 ExprDef *child)
105 {
106     ExprDef *expr;
107     expr = malloc_or_die(sizeof(*expr));
108
109     expr->common.type = STMT_EXPR;
110     expr->common.next = NULL;
111     expr->op = op;
112     expr->value_type = type;
113     expr->value.child = child;
114     return expr;
115 }
116
117 ExprDef *
118 ExprCreateBinary(enum expr_op_type op, ExprDef *left, ExprDef *right)
119 {
120     ExprDef *expr;
121
122     expr = malloc_or_die(sizeof(*expr));
123
124     expr->common.type = STMT_EXPR;
125     expr->common.next = NULL;
126     expr->op = op;
127     if (op == EXPR_ASSIGN || left->value_type == EXPR_TYPE_UNKNOWN)
128         expr->value_type = right->value_type;
129     else if (left->value_type == right->value_type ||
130              right->value_type == EXPR_TYPE_UNKNOWN)
131         expr->value_type = left->value_type;
132     else
133         expr->value_type = EXPR_TYPE_UNKNOWN;
134     expr->value.binary.left = left;
135     expr->value.binary.right = right;
136     return expr;
137 }
138
139 KeycodeDef *
140 KeycodeCreate(char keyName[XKB_KEY_NAME_LENGTH], unsigned long value)
141 {
142     KeycodeDef *def;
143
144     def = malloc_or_die(sizeof(*def));
145
146     def->common.type = STMT_KEYCODE;
147     def->common.next = NULL;
148     strncpy(def->name, keyName, XKB_KEY_NAME_LENGTH);
149     def->value = value;
150     return def;
151 }
152
153 KeyAliasDef *
154 KeyAliasCreate(char alias[XKB_KEY_NAME_LENGTH], char real[XKB_KEY_NAME_LENGTH])
155 {
156     KeyAliasDef *def;
157
158     def = malloc_or_die(sizeof(*def));
159
160     def->common.type = STMT_ALIAS;
161     def->common.next = NULL;
162     strncpy(def->alias, alias, XKB_KEY_NAME_LENGTH);
163     strncpy(def->real, real, XKB_KEY_NAME_LENGTH);
164     return def;
165 }
166
167 VModDef *
168 VModCreate(xkb_atom_t name, ExprDef * value)
169 {
170     VModDef *def;
171
172     def = malloc_or_die(sizeof(*def));
173
174     def->common.type = STMT_VMOD;
175     def->common.next = NULL;
176     def->name = name;
177     def->value = value;
178     return def;
179 }
180
181 VarDef *
182 VarCreate(ExprDef * name, ExprDef * value)
183 {
184     VarDef *def;
185     def = malloc_or_die(sizeof(*def));
186
187     def->common.type = STMT_VAR;
188     def->common.next = NULL;
189     def->name = name;
190     def->value = value;
191     return def;
192 }
193
194 VarDef *
195 BoolVarCreate(xkb_atom_t nameToken, unsigned set)
196 {
197     ExprDef *name, *value;
198
199     name = ExprCreate(EXPR_IDENT, EXPR_TYPE_UNKNOWN);
200     name->value.str = nameToken;
201     value = ExprCreate(EXPR_VALUE, EXPR_TYPE_BOOLEAN);
202     value->value.uval = set;
203     return VarCreate(name, value);
204 }
205
206 InterpDef *
207 InterpCreate(char *sym, ExprDef * match)
208 {
209     InterpDef *def;
210
211     def = malloc_or_die(sizeof(*def));
212
213     def->common.type = STMT_INTERP;
214     def->common.next = NULL;
215     def->sym = sym;
216     def->match = match;
217     return def;
218 }
219
220 KeyTypeDef *
221 KeyTypeCreate(xkb_atom_t name, VarDef * body)
222 {
223     KeyTypeDef *def;
224
225     def = malloc_or_die(sizeof(*def));
226
227     def->common.type = STMT_TYPE;
228     def->common.next = NULL;
229     def->merge = MERGE_DEFAULT;
230     def->name = name;
231     def->body = body;
232     return def;
233 }
234
235 SymbolsDef *
236 SymbolsCreate(char keyName[XKB_KEY_NAME_LENGTH], ExprDef *symbols)
237 {
238     SymbolsDef *def;
239
240     def = malloc_or_die(sizeof(*def));
241
242     def->common.type = STMT_SYMBOLS;
243     def->common.next = NULL;
244     def->merge = MERGE_DEFAULT;
245     strncpy(def->keyName, keyName, XKB_KEY_NAME_LENGTH);
246     def->symbols = symbols;
247     return def;
248 }
249
250 GroupCompatDef *
251 GroupCompatCreate(int group, ExprDef * val)
252 {
253     GroupCompatDef *def;
254
255     def = malloc_or_die(sizeof(*def));
256
257     def->common.type = STMT_GROUP_COMPAT;
258     def->common.next = NULL;
259     def->merge = MERGE_DEFAULT;
260     def->group = group;
261     def->def = val;
262     return def;
263 }
264
265 ModMapDef *
266 ModMapCreate(uint32_t modifier, ExprDef * keys)
267 {
268     ModMapDef *def;
269
270     def = malloc_or_die(sizeof(*def));
271
272     def->common.type = STMT_MODMAP;
273     def->common.next = NULL;
274     def->merge = MERGE_DEFAULT;
275     def->modifier = modifier;
276     def->keys = keys;
277     return def;
278 }
279
280 IndicatorMapDef *
281 IndicatorMapCreate(xkb_atom_t name, VarDef * body)
282 {
283     IndicatorMapDef *def;
284
285     def = malloc_or_die(sizeof(*def));
286
287     def->common.type = STMT_INDICATOR_MAP;
288     def->common.next = NULL;
289     def->merge = MERGE_DEFAULT;
290     def->name = name;
291     def->body = body;
292     return def;
293 }
294
295 IndicatorNameDef *
296 IndicatorNameCreate(int ndx, ExprDef * name, bool virtual)
297 {
298     IndicatorNameDef *def;
299
300     def = malloc_or_die(sizeof(*def));
301
302     def->common.type = STMT_INDICATOR_NAME;
303     def->common.next = NULL;
304     def->merge = MERGE_DEFAULT;
305     def->ndx = ndx;
306     def->name = name;
307     def->virtual = virtual;
308     return def;
309 }
310
311 ExprDef *
312 ActionCreate(xkb_atom_t name, ExprDef * args)
313 {
314     ExprDef *act;
315
316     act = malloc_or_die(sizeof(*act));
317
318     act->common.type = STMT_EXPR;
319     act->common.next = NULL;
320     act->op = EXPR_ACTION_DECL;
321     act->value.action.name = name;
322     act->value.action.args = args;
323     return act;
324 }
325
326 ExprDef *
327 CreateKeysymList(char *sym)
328 {
329     ExprDef *def;
330
331     def = ExprCreate(EXPR_KEYSYM_LIST, EXPR_TYPE_SYMBOLS);
332
333     darray_init(def->value.list.syms);
334     darray_init(def->value.list.symsMapIndex);
335     darray_init(def->value.list.symsNumEntries);
336
337     darray_append(def->value.list.syms, sym);
338     darray_append(def->value.list.symsMapIndex, 0);
339     darray_append(def->value.list.symsNumEntries, 1);
340
341     return def;
342 }
343
344 ExprDef *
345 CreateMultiKeysymList(ExprDef *list)
346 {
347     size_t nLevels = darray_size(list->value.list.symsMapIndex);
348
349     darray_resize(list->value.list.symsMapIndex, 1);
350     darray_resize(list->value.list.symsNumEntries, 1);
351     darray_item(list->value.list.symsMapIndex, 0) = 0;
352     darray_item(list->value.list.symsNumEntries, 0) = nLevels;
353
354     return list;
355 }
356
357 ExprDef *
358 AppendKeysymList(ExprDef * list, char *sym)
359 {
360     size_t nSyms = darray_size(list->value.list.syms);
361
362     darray_append(list->value.list.symsMapIndex, nSyms);
363     darray_append(list->value.list.symsNumEntries, 1);
364     darray_append(list->value.list.syms, sym);
365
366     return list;
367 }
368
369 ExprDef *
370 AppendMultiKeysymList(ExprDef * list, ExprDef * append)
371 {
372     size_t nSyms = darray_size(list->value.list.syms);
373     size_t numEntries = darray_size(append->value.list.syms);
374
375     darray_append(list->value.list.symsMapIndex, nSyms);
376     darray_append(list->value.list.symsNumEntries, numEntries);
377     darray_append_items(list->value.list.syms,
378                         darray_mem(append->value.list.syms, 0),
379                         numEntries);
380
381     darray_resize(append->value.list.syms, 0);
382     FreeStmt(&append->common);
383
384     return list;
385 }
386
387 static void
388 FreeInclude(IncludeStmt *incl);
389
390 IncludeStmt *
391 IncludeCreate(struct xkb_context *ctx, char *str, enum merge_mode merge)
392 {
393     IncludeStmt *incl, *first;
394     char *file, *map, *stmt, *tmp, *extra_data;
395     char nextop;
396
397     incl = first = NULL;
398     file = map = NULL;
399     tmp = str;
400     stmt = strdup_safe(str);
401     while (tmp && *tmp)
402     {
403         if (!ParseIncludeMap(&tmp, &file, &map, &nextop, &extra_data))
404             goto err;
405
406         if (first == NULL) {
407             first = incl = malloc(sizeof(*first));
408         } else {
409             incl->next_incl = malloc(sizeof(*first));
410             incl = incl->next_incl;
411         }
412
413         if (!incl) {
414             log_wsgo(ctx,
415                      "Allocation failure in IncludeCreate; "
416                      "Using only part of the include\n");
417             break;
418         }
419
420         incl->common.type = STMT_INCLUDE;
421         incl->common.next = NULL;
422         incl->merge = merge;
423         incl->stmt = NULL;
424         incl->file = file;
425         incl->map = map;
426         incl->modifier = extra_data;
427         incl->next_incl = NULL;
428
429         if (nextop == '|')
430             merge = MERGE_AUGMENT;
431         else
432             merge = MERGE_OVERRIDE;
433     }
434
435     if (first)
436         first->stmt = stmt;
437     else
438         free(stmt);
439
440     return first;
441
442 err:
443     log_err(ctx, "Illegal include statement \"%s\"; Ignored\n", stmt);
444     FreeInclude(first);
445     free(stmt);
446     return NULL;
447 }
448
449 /*
450  * All latin-1 alphanumerics, plus parens, slash, minus, underscore and
451  * wildcards.
452  */
453 static const unsigned char componentSpecLegal[] = {
454     0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xff, 0x83,
455     0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x07,
456     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
457     0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff
458 };
459
460 static void
461 EnsureSafeMapName(char *name)
462 {
463     if (!name)
464         return;
465
466     while (*name != '\0') {
467         if ((componentSpecLegal[(*name) / 8] & (1 << ((*name) % 8))) == 0)
468             *name = '_';
469         name++;
470     }
471 }
472
473 XkbFile *
474 XkbFileCreate(struct xkb_context *ctx, enum xkb_file_type type, char *name,
475               ParseCommon *defs, enum xkb_map_flags flags)
476 {
477     XkbFile *file;
478
479     file = calloc(1, sizeof(*file));
480     if (!file)
481         return NULL;
482
483     EnsureSafeMapName(name);
484     file->file_type = type;
485     file->topName = strdup_safe(name);
486     file->name = name;
487     file->defs = defs;
488     file->id = xkb_context_take_file_id(ctx);
489     file->flags = flags;
490     return file;
491 }
492
493 XkbFile *
494 XkbFileFromComponents(struct xkb_context *ctx,
495                       struct xkb_component_names *kkctgs)
496 {
497     IncludeStmt *inc;
498     XkbFile *keycodes, *types, *compat, *symbols;
499
500     inc = IncludeCreate(ctx, kkctgs->keycodes, MERGE_DEFAULT);
501     keycodes = XkbFileCreate(ctx, FILE_TYPE_KEYCODES, NULL,
502                              (ParseCommon *) inc, 0);
503
504     inc = IncludeCreate(ctx, kkctgs->types, MERGE_DEFAULT);
505     types = XkbFileCreate(ctx, FILE_TYPE_TYPES, NULL,
506                           (ParseCommon *) inc, 0);
507     AppendStmt(&keycodes->common, &types->common);
508
509     inc = IncludeCreate(ctx, kkctgs->compat, MERGE_DEFAULT);
510     compat = XkbFileCreate(ctx, FILE_TYPE_COMPAT, NULL,
511                            (ParseCommon *) inc, 0);
512     AppendStmt(&keycodes->common, &compat->common);
513
514     inc = IncludeCreate(ctx, kkctgs->symbols, MERGE_DEFAULT);
515     symbols = XkbFileCreate(ctx, FILE_TYPE_SYMBOLS, NULL,
516                             (ParseCommon *) inc, 0);
517     AppendStmt(&keycodes->common, &symbols->common);
518
519     return XkbFileCreate(ctx, FILE_TYPE_KEYMAP, NULL,
520                          &keycodes->common, 0);
521 }
522
523 static void
524 FreeExpr(ExprDef *expr)
525 {
526     char **sym;
527
528     if (!expr)
529         return;
530
531     switch (expr->op) {
532     case EXPR_ACTION_LIST:
533     case EXPR_NEGATE:
534     case EXPR_UNARY_PLUS:
535     case EXPR_NOT:
536     case EXPR_INVERT:
537         FreeStmt(&expr->value.child->common);
538         break;
539
540     case EXPR_DIVIDE:
541     case EXPR_ADD:
542     case EXPR_SUBTRACT:
543     case EXPR_MULTIPLY:
544     case EXPR_ASSIGN:
545         FreeStmt(&expr->value.binary.left->common);
546         FreeStmt(&expr->value.binary.right->common);
547         break;
548
549     case EXPR_ACTION_DECL:
550         FreeStmt(&expr->value.action.args->common);
551         break;
552
553     case EXPR_ARRAY_REF:
554         FreeStmt(&expr->value.array.entry->common);
555         break;
556
557     case EXPR_KEYSYM_LIST:
558         darray_foreach(sym, expr->value.list.syms)
559             free(*sym);
560         darray_free(expr->value.list.syms);
561         darray_free(expr->value.list.symsMapIndex);
562         darray_free(expr->value.list.symsNumEntries);
563         break;
564
565     default:
566         break;
567     }
568 }
569
570 static void
571 FreeInclude(IncludeStmt *incl)
572 {
573     IncludeStmt *next;
574
575     while (incl)
576     {
577         next = incl->next_incl;
578
579         free(incl->file);
580         free(incl->map);
581         free(incl->modifier);
582         free(incl->stmt);
583
584         free(incl);
585         incl = next;
586     }
587 }
588
589 void
590 FreeStmt(ParseCommon *stmt)
591 {
592     ParseCommon *next;
593     YYSTYPE u;
594
595     while (stmt)
596     {
597         next = stmt->next;
598         u.any = stmt;
599
600         switch (stmt->type) {
601         case STMT_INCLUDE:
602             FreeInclude((IncludeStmt *) stmt);
603             /* stmt is already free'd here. */
604             stmt = NULL;
605             break;
606         case STMT_EXPR:
607             FreeExpr(u.expr);
608             break;
609         case STMT_VAR:
610             FreeStmt(&u.var->name->common);
611             FreeStmt(&u.var->value->common);
612             break;
613         case STMT_TYPE:
614             FreeStmt(&u.keyType->body->common);
615             break;
616         case STMT_INTERP:
617             free(u.interp->sym);
618             FreeStmt(&u.interp->match->common);
619             FreeStmt(&u.interp->def->common);
620             break;
621         case STMT_VMOD:
622             FreeStmt(&u.vmod->value->common);
623             break;
624         case STMT_SYMBOLS:
625             FreeStmt(&u.syms->symbols->common);
626             break;
627         case STMT_MODMAP:
628             FreeStmt(&u.modMask->keys->common);
629             break;
630         case STMT_GROUP_COMPAT:
631             FreeStmt(&u.groupCompat->def->common);
632             break;
633         case STMT_INDICATOR_MAP:
634             FreeStmt(&u.ledMap->body->common);
635             break;
636         case STMT_INDICATOR_NAME:
637             FreeStmt(&u.ledName->name->common);
638             break;
639         default:
640             break;
641         }
642
643         free(stmt);
644         stmt = next;
645     }
646 }
647
648 void
649 FreeXkbFile(XkbFile *file)
650 {
651     XkbFile *next;
652
653     while (file)
654     {
655         next = (XkbFile *) file->common.next;
656
657         switch (file->file_type) {
658         case FILE_TYPE_KEYMAP:
659             FreeXkbFile((XkbFile *) file->defs);
660             break;
661
662         case FILE_TYPE_TYPES:
663         case FILE_TYPE_COMPAT:
664         case FILE_TYPE_SYMBOLS:
665         case FILE_TYPE_KEYCODES:
666         case FILE_TYPE_GEOMETRY:
667             FreeStmt(file->defs);
668             break;
669
670         default:
671             break;
672         }
673
674         free(file->name);
675         free(file->topName);
676         free(file);
677         file = next;
678     }
679 }
680
681 static const char *xkb_file_type_strings[_FILE_TYPE_NUM_ENTRIES] = {
682     [FILE_TYPE_KEYCODES] = "xkb_keycodes",
683     [FILE_TYPE_TYPES] = "xkb_types",
684     [FILE_TYPE_COMPAT] = "xkb_compatibility",
685     [FILE_TYPE_SYMBOLS] = "xkb_symbols",
686     [FILE_TYPE_KEYMAP] = "xkb_keymap",
687     [FILE_TYPE_RULES] = "rules",
688 };
689
690 const char *
691 xkb_file_type_to_string(enum xkb_file_type type)
692 {
693     if (type > _FILE_TYPE_NUM_ENTRIES)
694         return "unknown";
695     return xkb_file_type_strings[type];
696 }
697
698 static const char *stmt_type_strings[_STMT_NUM_VALUES] = {
699     [STMT_UNKNOWN] = "unknown statement",
700     [STMT_INCLUDE] = "include statement",
701     [STMT_KEYCODE] = "key name definition",
702     [STMT_ALIAS] = "key alias definition",
703     [STMT_EXPR] = "expression",
704     [STMT_VAR] = "variable definition",
705     [STMT_TYPE] = "key type definition",
706     [STMT_INTERP] = "symbol interpretation definition",
707     [STMT_VMOD] = "virtual modifiers definition",
708     [STMT_SYMBOLS] = "key symbols definition",
709     [STMT_MODMAP] = "modifier map declaration",
710     [STMT_GROUP_COMPAT] = "group declaration",
711     [STMT_INDICATOR_MAP] = "indicator map declaration",
712     [STMT_INDICATOR_NAME] = "indicator name declaration",
713 };
714
715 const char *
716 stmt_type_to_string(enum stmt_type type)
717 {
718     if (type >= _STMT_NUM_VALUES)
719         return NULL;
720     return stmt_type_strings[type];
721 }
722
723 static const char *expr_op_type_strings[_EXPR_NUM_VALUES] = {
724     [EXPR_VALUE] = "literal",
725     [EXPR_IDENT] = "identifier",
726     [EXPR_ACTION_DECL] = "action declaration",
727     [EXPR_FIELD_REF] = "field reference",
728     [EXPR_ARRAY_REF] = "array reference",
729     [EXPR_KEYSYM_LIST] = "list of keysyms",
730     [EXPR_ACTION_LIST] = "list of actions",
731     [EXPR_ADD] = "addition",
732     [EXPR_SUBTRACT] = "subtraction",
733     [EXPR_MULTIPLY] = "multiplication",
734     [EXPR_DIVIDE] = "division",
735     [EXPR_ASSIGN] = "assignment",
736     [EXPR_NOT] = "logical negation",
737     [EXPR_NEGATE] = "arithmetic negation",
738     [EXPR_INVERT] = "bitwise inversion",
739     [EXPR_UNARY_PLUS] = "unary plus",
740 };
741
742 const char *
743 expr_op_type_to_string(enum expr_op_type type)
744 {
745     if (type >= _EXPR_NUM_VALUES)
746         return NULL;
747     return expr_op_type_strings[type];
748 }
749
750 static const char *expr_value_type_strings[_EXPR_TYPE_NUM_VALUES] = {
751     [EXPR_TYPE_UNKNOWN] = "unknown",
752     [EXPR_TYPE_BOOLEAN] = "boolean",
753     [EXPR_TYPE_INT] = "int",
754     [EXPR_TYPE_STRING] = "string",
755     [EXPR_TYPE_ACTION] = "action",
756     [EXPR_TYPE_KEYNAME] = "keyname",
757     [EXPR_TYPE_SYMBOLS] = "symbols",
758 };
759
760 const char *
761 expr_value_type_to_string(enum expr_value_type type)
762 {
763     if (type >= _EXPR_TYPE_NUM_VALUES)
764         return NULL;
765     return expr_value_type_strings[type];
766 }