ast: constify argument
[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 *iter;
74
75     if (!to)
76         return append;
77
78     for (iter = to; iter->next; iter = iter->next);
79
80     iter->next = append;
81     return to;
82 }
83
84 ExprDef *
85 ExprCreate(enum expr_op_type op, enum expr_value_type type)
86 {
87     ExprDef *expr;
88
89     expr = malloc_or_die(sizeof(*expr));
90
91     expr->common.type = STMT_EXPR;
92     expr->common.next = NULL;
93     expr->op = op;
94     expr->value_type = type;
95     return expr;
96 }
97
98 ExprDef *
99 ExprCreateUnary(enum expr_op_type op, enum expr_value_type type,
100                 ExprDef *child)
101 {
102     ExprDef *expr;
103     expr = malloc_or_die(sizeof(*expr));
104
105     expr->common.type = STMT_EXPR;
106     expr->common.next = NULL;
107     expr->op = op;
108     expr->value_type = type;
109     expr->value.child = child;
110     return expr;
111 }
112
113 ExprDef *
114 ExprCreateBinary(enum expr_op_type op, ExprDef *left, ExprDef *right)
115 {
116     ExprDef *expr;
117
118     expr = malloc_or_die(sizeof(*expr));
119
120     expr->common.type = STMT_EXPR;
121     expr->common.next = NULL;
122     expr->op = op;
123     if (op == EXPR_ASSIGN || left->value_type == EXPR_TYPE_UNKNOWN)
124         expr->value_type = right->value_type;
125     else if (left->value_type == right->value_type ||
126              right->value_type == EXPR_TYPE_UNKNOWN)
127         expr->value_type = left->value_type;
128     else
129         expr->value_type = EXPR_TYPE_UNKNOWN;
130     expr->value.binary.left = left;
131     expr->value.binary.right = right;
132     return expr;
133 }
134
135 KeycodeDef *
136 KeycodeCreate(xkb_atom_t name, int64_t value)
137 {
138     KeycodeDef *def;
139
140     def = malloc_or_die(sizeof(*def));
141
142     def->common.type = STMT_KEYCODE;
143     def->common.next = NULL;
144     def->name = name;
145     def->value = value;
146     return def;
147 }
148
149 KeyAliasDef *
150 KeyAliasCreate(xkb_atom_t alias, xkb_atom_t real)
151 {
152     KeyAliasDef *def;
153
154     def = malloc_or_die(sizeof(*def));
155
156     def->common.type = STMT_ALIAS;
157     def->common.next = NULL;
158     def->alias = alias;
159     def->real = real;
160     return def;
161 }
162
163 VModDef *
164 VModCreate(xkb_atom_t name, ExprDef * value)
165 {
166     VModDef *def;
167
168     def = malloc_or_die(sizeof(*def));
169
170     def->common.type = STMT_VMOD;
171     def->common.next = NULL;
172     def->name = name;
173     def->value = value;
174     return def;
175 }
176
177 VarDef *
178 VarCreate(ExprDef * name, ExprDef * value)
179 {
180     VarDef *def;
181     def = malloc_or_die(sizeof(*def));
182
183     def->common.type = STMT_VAR;
184     def->common.next = NULL;
185     def->name = name;
186     def->value = value;
187     return def;
188 }
189
190 VarDef *
191 BoolVarCreate(xkb_atom_t nameToken, unsigned set)
192 {
193     ExprDef *name, *value;
194
195     name = ExprCreate(EXPR_IDENT, EXPR_TYPE_UNKNOWN);
196     name->value.str = nameToken;
197     value = ExprCreate(EXPR_VALUE, EXPR_TYPE_BOOLEAN);
198     value->value.uval = set;
199     return VarCreate(name, value);
200 }
201
202 InterpDef *
203 InterpCreate(char *sym, ExprDef * match)
204 {
205     InterpDef *def;
206
207     def = malloc_or_die(sizeof(*def));
208
209     def->common.type = STMT_INTERP;
210     def->common.next = NULL;
211     def->sym = sym;
212     def->match = match;
213     return def;
214 }
215
216 KeyTypeDef *
217 KeyTypeCreate(xkb_atom_t name, VarDef * body)
218 {
219     KeyTypeDef *def;
220
221     def = malloc_or_die(sizeof(*def));
222
223     def->common.type = STMT_TYPE;
224     def->common.next = NULL;
225     def->merge = MERGE_DEFAULT;
226     def->name = name;
227     def->body = body;
228     return def;
229 }
230
231 SymbolsDef *
232 SymbolsCreate(xkb_atom_t keyName, ExprDef *symbols)
233 {
234     SymbolsDef *def;
235
236     def = malloc_or_die(sizeof(*def));
237
238     def->common.type = STMT_SYMBOLS;
239     def->common.next = NULL;
240     def->merge = MERGE_DEFAULT;
241     def->keyName = keyName;
242     def->symbols = symbols;
243     return def;
244 }
245
246 GroupCompatDef *
247 GroupCompatCreate(int group, ExprDef * val)
248 {
249     GroupCompatDef *def;
250
251     def = malloc_or_die(sizeof(*def));
252
253     def->common.type = STMT_GROUP_COMPAT;
254     def->common.next = NULL;
255     def->merge = MERGE_DEFAULT;
256     def->group = group;
257     def->def = val;
258     return def;
259 }
260
261 ModMapDef *
262 ModMapCreate(uint32_t modifier, ExprDef * keys)
263 {
264     ModMapDef *def;
265
266     def = malloc_or_die(sizeof(*def));
267
268     def->common.type = STMT_MODMAP;
269     def->common.next = NULL;
270     def->merge = MERGE_DEFAULT;
271     def->modifier = modifier;
272     def->keys = keys;
273     return def;
274 }
275
276 LedMapDef *
277 LedMapCreate(xkb_atom_t name, VarDef * body)
278 {
279     LedMapDef *def;
280
281     def = malloc_or_die(sizeof(*def));
282
283     def->common.type = STMT_LED_MAP;
284     def->common.next = NULL;
285     def->merge = MERGE_DEFAULT;
286     def->name = name;
287     def->body = body;
288     return def;
289 }
290
291 LedNameDef *
292 LedNameCreate(int ndx, ExprDef * name, bool virtual)
293 {
294     LedNameDef *def;
295
296     def = malloc_or_die(sizeof(*def));
297
298     def->common.type = STMT_LED_NAME;
299     def->common.next = NULL;
300     def->merge = MERGE_DEFAULT;
301     def->ndx = ndx;
302     def->name = name;
303     def->virtual = virtual;
304     return def;
305 }
306
307 ExprDef *
308 ActionCreate(xkb_atom_t name, ExprDef * args)
309 {
310     ExprDef *act;
311
312     act = malloc_or_die(sizeof(*act));
313
314     act->common.type = STMT_EXPR;
315     act->common.next = NULL;
316     act->op = EXPR_ACTION_DECL;
317     act->value.action.name = name;
318     act->value.action.args = args;
319     return act;
320 }
321
322 ExprDef *
323 CreateKeysymList(char *sym)
324 {
325     ExprDef *def;
326
327     def = ExprCreate(EXPR_KEYSYM_LIST, EXPR_TYPE_SYMBOLS);
328
329     darray_init(def->value.list.syms);
330     darray_init(def->value.list.symsMapIndex);
331     darray_init(def->value.list.symsNumEntries);
332
333     darray_append(def->value.list.syms, sym);
334     darray_append(def->value.list.symsMapIndex, 0);
335     darray_append(def->value.list.symsNumEntries, 1);
336
337     return def;
338 }
339
340 ExprDef *
341 CreateMultiKeysymList(ExprDef *list)
342 {
343     size_t nLevels = darray_size(list->value.list.symsMapIndex);
344
345     darray_resize(list->value.list.symsMapIndex, 1);
346     darray_resize(list->value.list.symsNumEntries, 1);
347     darray_item(list->value.list.symsMapIndex, 0) = 0;
348     darray_item(list->value.list.symsNumEntries, 0) = nLevels;
349
350     return list;
351 }
352
353 ExprDef *
354 AppendKeysymList(ExprDef * list, char *sym)
355 {
356     size_t nSyms = darray_size(list->value.list.syms);
357
358     darray_append(list->value.list.symsMapIndex, nSyms);
359     darray_append(list->value.list.symsNumEntries, 1);
360     darray_append(list->value.list.syms, sym);
361
362     return list;
363 }
364
365 ExprDef *
366 AppendMultiKeysymList(ExprDef * list, ExprDef * append)
367 {
368     size_t nSyms = darray_size(list->value.list.syms);
369     size_t numEntries = darray_size(append->value.list.syms);
370
371     darray_append(list->value.list.symsMapIndex, nSyms);
372     darray_append(list->value.list.symsNumEntries, numEntries);
373     darray_append_items(list->value.list.syms,
374                         darray_mem(append->value.list.syms, 0),
375                         numEntries);
376
377     darray_resize(append->value.list.syms, 0);
378     FreeStmt(&append->common);
379
380     return list;
381 }
382
383 static void
384 FreeInclude(IncludeStmt *incl);
385
386 IncludeStmt *
387 IncludeCreate(struct xkb_context *ctx, char *str, enum merge_mode merge)
388 {
389     IncludeStmt *incl, *first;
390     char *file, *map, *stmt, *tmp, *extra_data;
391     char nextop;
392
393     incl = first = NULL;
394     file = map = NULL;
395     tmp = str;
396     stmt = strdup_safe(str);
397     while (tmp && *tmp)
398     {
399         if (!ParseIncludeMap(&tmp, &file, &map, &nextop, &extra_data))
400             goto err;
401
402         /*
403          * Given an RMLVO (here layout) like 'us,,fr', the rules parser
404          * will give out something like 'pc+us+:2+fr:3+inet(evdev)'.
405          * We should just skip the ':2' in this case and leave it to the
406          * appropriate section to deal with the empty group.
407          */
408         if (isempty(file)) {
409             free(file);
410             free(map);
411             free(extra_data);
412             continue;
413         }
414
415         if (first == NULL) {
416             first = incl = malloc(sizeof(*first));
417         } else {
418             incl->next_incl = malloc(sizeof(*first));
419             incl = incl->next_incl;
420         }
421
422         if (!incl) {
423             log_wsgo(ctx,
424                      "Allocation failure in IncludeCreate; "
425                      "Using only part of the include\n");
426             break;
427         }
428
429         incl->common.type = STMT_INCLUDE;
430         incl->common.next = NULL;
431         incl->merge = merge;
432         incl->stmt = NULL;
433         incl->file = file;
434         incl->map = map;
435         incl->modifier = extra_data;
436         incl->next_incl = NULL;
437
438         if (nextop == '|')
439             merge = MERGE_AUGMENT;
440         else
441             merge = MERGE_OVERRIDE;
442     }
443
444     if (first)
445         first->stmt = stmt;
446     else
447         free(stmt);
448
449     return first;
450
451 err:
452     log_err(ctx, "Illegal include statement \"%s\"; Ignored\n", stmt);
453     FreeInclude(first);
454     free(stmt);
455     return NULL;
456 }
457
458 /*
459  * All latin-1 alphanumerics, plus parens, slash, minus, underscore and
460  * wildcards.
461  */
462 static const unsigned char componentSpecLegal[] = {
463     0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xff, 0x83,
464     0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x07,
465     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
466     0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff
467 };
468
469 static void
470 EnsureSafeMapName(char *name)
471 {
472     if (!name)
473         return;
474
475     while (*name != '\0') {
476         if ((componentSpecLegal[(*name) / 8] & (1 << ((*name) % 8))) == 0)
477             *name = '_';
478         name++;
479     }
480 }
481
482 XkbFile *
483 XkbFileCreate(struct xkb_context *ctx, enum xkb_file_type type, char *name,
484               ParseCommon *defs, enum xkb_map_flags flags)
485 {
486     XkbFile *file;
487
488     file = calloc(1, sizeof(*file));
489     if (!file)
490         return NULL;
491
492     EnsureSafeMapName(name);
493     file->file_type = type;
494     file->topName = strdup_safe(name);
495     file->name = name;
496     file->defs = defs;
497     file->id = xkb_context_take_file_id(ctx);
498     file->flags = flags;
499     return file;
500 }
501
502 XkbFile *
503 XkbFileFromComponents(struct xkb_context *ctx,
504                       const struct xkb_component_names *kkctgs)
505 {
506     IncludeStmt *inc;
507     XkbFile *keycodes, *types, *compat, *symbols;
508
509     inc = IncludeCreate(ctx, kkctgs->keycodes, MERGE_DEFAULT);
510     keycodes = XkbFileCreate(ctx, FILE_TYPE_KEYCODES, NULL,
511                              (ParseCommon *) inc, 0);
512
513     inc = IncludeCreate(ctx, kkctgs->types, MERGE_DEFAULT);
514     types = XkbFileCreate(ctx, FILE_TYPE_TYPES, NULL,
515                           (ParseCommon *) inc, 0);
516     AppendStmt(&keycodes->common, &types->common);
517
518     inc = IncludeCreate(ctx, kkctgs->compat, MERGE_DEFAULT);
519     compat = XkbFileCreate(ctx, FILE_TYPE_COMPAT, NULL,
520                            (ParseCommon *) inc, 0);
521     AppendStmt(&keycodes->common, &compat->common);
522
523     inc = IncludeCreate(ctx, kkctgs->symbols, MERGE_DEFAULT);
524     symbols = XkbFileCreate(ctx, FILE_TYPE_SYMBOLS, NULL,
525                             (ParseCommon *) inc, 0);
526     AppendStmt(&keycodes->common, &symbols->common);
527
528     return XkbFileCreate(ctx, FILE_TYPE_KEYMAP, NULL,
529                          &keycodes->common, 0);
530 }
531
532 static void
533 FreeExpr(ExprDef *expr)
534 {
535     char **sym;
536
537     if (!expr)
538         return;
539
540     switch (expr->op) {
541     case EXPR_ACTION_LIST:
542     case EXPR_NEGATE:
543     case EXPR_UNARY_PLUS:
544     case EXPR_NOT:
545     case EXPR_INVERT:
546         FreeStmt(&expr->value.child->common);
547         break;
548
549     case EXPR_DIVIDE:
550     case EXPR_ADD:
551     case EXPR_SUBTRACT:
552     case EXPR_MULTIPLY:
553     case EXPR_ASSIGN:
554         FreeStmt(&expr->value.binary.left->common);
555         FreeStmt(&expr->value.binary.right->common);
556         break;
557
558     case EXPR_ACTION_DECL:
559         FreeStmt(&expr->value.action.args->common);
560         break;
561
562     case EXPR_ARRAY_REF:
563         FreeStmt(&expr->value.array.entry->common);
564         break;
565
566     case EXPR_KEYSYM_LIST:
567         darray_foreach(sym, expr->value.list.syms)
568             free(*sym);
569         darray_free(expr->value.list.syms);
570         darray_free(expr->value.list.symsMapIndex);
571         darray_free(expr->value.list.symsNumEntries);
572         break;
573
574     default:
575         break;
576     }
577 }
578
579 static void
580 FreeInclude(IncludeStmt *incl)
581 {
582     IncludeStmt *next;
583
584     while (incl)
585     {
586         next = incl->next_incl;
587
588         free(incl->file);
589         free(incl->map);
590         free(incl->modifier);
591         free(incl->stmt);
592
593         free(incl);
594         incl = next;
595     }
596 }
597
598 void
599 FreeStmt(ParseCommon *stmt)
600 {
601     ParseCommon *next;
602     YYSTYPE u;
603
604     while (stmt)
605     {
606         next = stmt->next;
607         u.any = stmt;
608
609         switch (stmt->type) {
610         case STMT_INCLUDE:
611             FreeInclude((IncludeStmt *) stmt);
612             /* stmt is already free'd here. */
613             stmt = NULL;
614             break;
615         case STMT_EXPR:
616             FreeExpr(u.expr);
617             break;
618         case STMT_VAR:
619             FreeStmt(&u.var->name->common);
620             FreeStmt(&u.var->value->common);
621             break;
622         case STMT_TYPE:
623             FreeStmt(&u.keyType->body->common);
624             break;
625         case STMT_INTERP:
626             free(u.interp->sym);
627             FreeStmt(&u.interp->match->common);
628             FreeStmt(&u.interp->def->common);
629             break;
630         case STMT_VMOD:
631             FreeStmt(&u.vmod->value->common);
632             break;
633         case STMT_SYMBOLS:
634             FreeStmt(&u.syms->symbols->common);
635             break;
636         case STMT_MODMAP:
637             FreeStmt(&u.modMask->keys->common);
638             break;
639         case STMT_GROUP_COMPAT:
640             FreeStmt(&u.groupCompat->def->common);
641             break;
642         case STMT_LED_MAP:
643             FreeStmt(&u.ledMap->body->common);
644             break;
645         case STMT_LED_NAME:
646             FreeStmt(&u.ledName->name->common);
647             break;
648         default:
649             break;
650         }
651
652         free(stmt);
653         stmt = next;
654     }
655 }
656
657 void
658 FreeXkbFile(XkbFile *file)
659 {
660     XkbFile *next;
661
662     while (file)
663     {
664         next = (XkbFile *) file->common.next;
665
666         switch (file->file_type) {
667         case FILE_TYPE_KEYMAP:
668             FreeXkbFile((XkbFile *) file->defs);
669             break;
670
671         case FILE_TYPE_TYPES:
672         case FILE_TYPE_COMPAT:
673         case FILE_TYPE_SYMBOLS:
674         case FILE_TYPE_KEYCODES:
675         case FILE_TYPE_GEOMETRY:
676             FreeStmt(file->defs);
677             break;
678
679         default:
680             break;
681         }
682
683         free(file->name);
684         free(file->topName);
685         free(file);
686         file = next;
687     }
688 }
689
690 static const char *xkb_file_type_strings[_FILE_TYPE_NUM_ENTRIES] = {
691     [FILE_TYPE_KEYCODES] = "xkb_keycodes",
692     [FILE_TYPE_TYPES] = "xkb_types",
693     [FILE_TYPE_COMPAT] = "xkb_compatibility",
694     [FILE_TYPE_SYMBOLS] = "xkb_symbols",
695     [FILE_TYPE_KEYMAP] = "xkb_keymap",
696     [FILE_TYPE_RULES] = "rules",
697 };
698
699 const char *
700 xkb_file_type_to_string(enum xkb_file_type type)
701 {
702     if (type > _FILE_TYPE_NUM_ENTRIES)
703         return "unknown";
704     return xkb_file_type_strings[type];
705 }
706
707 static const char *stmt_type_strings[_STMT_NUM_VALUES] = {
708     [STMT_UNKNOWN] = "unknown statement",
709     [STMT_INCLUDE] = "include statement",
710     [STMT_KEYCODE] = "key name definition",
711     [STMT_ALIAS] = "key alias definition",
712     [STMT_EXPR] = "expression",
713     [STMT_VAR] = "variable definition",
714     [STMT_TYPE] = "key type definition",
715     [STMT_INTERP] = "symbol interpretation definition",
716     [STMT_VMOD] = "virtual modifiers definition",
717     [STMT_SYMBOLS] = "key symbols definition",
718     [STMT_MODMAP] = "modifier map declaration",
719     [STMT_GROUP_COMPAT] = "group declaration",
720     [STMT_LED_MAP] = "indicator map declaration",
721     [STMT_LED_NAME] = "indicator name declaration",
722 };
723
724 const char *
725 stmt_type_to_string(enum stmt_type type)
726 {
727     if (type >= _STMT_NUM_VALUES)
728         return NULL;
729     return stmt_type_strings[type];
730 }
731
732 static const char *expr_op_type_strings[_EXPR_NUM_VALUES] = {
733     [EXPR_VALUE] = "literal",
734     [EXPR_IDENT] = "identifier",
735     [EXPR_ACTION_DECL] = "action declaration",
736     [EXPR_FIELD_REF] = "field reference",
737     [EXPR_ARRAY_REF] = "array reference",
738     [EXPR_KEYSYM_LIST] = "list of keysyms",
739     [EXPR_ACTION_LIST] = "list of actions",
740     [EXPR_ADD] = "addition",
741     [EXPR_SUBTRACT] = "subtraction",
742     [EXPR_MULTIPLY] = "multiplication",
743     [EXPR_DIVIDE] = "division",
744     [EXPR_ASSIGN] = "assignment",
745     [EXPR_NOT] = "logical negation",
746     [EXPR_NEGATE] = "arithmetic negation",
747     [EXPR_INVERT] = "bitwise inversion",
748     [EXPR_UNARY_PLUS] = "unary plus",
749 };
750
751 const char *
752 expr_op_type_to_string(enum expr_op_type type)
753 {
754     if (type >= _EXPR_NUM_VALUES)
755         return NULL;
756     return expr_op_type_strings[type];
757 }
758
759 static const char *expr_value_type_strings[_EXPR_TYPE_NUM_VALUES] = {
760     [EXPR_TYPE_UNKNOWN] = "unknown",
761     [EXPR_TYPE_BOOLEAN] = "boolean",
762     [EXPR_TYPE_INT] = "int",
763     [EXPR_TYPE_STRING] = "string",
764     [EXPR_TYPE_ACTION] = "action",
765     [EXPR_TYPE_KEYNAME] = "keyname",
766     [EXPR_TYPE_SYMBOLS] = "symbols",
767 };
768
769 const char *
770 expr_value_type_to_string(enum expr_value_type type)
771 {
772     if (type >= _EXPR_TYPE_NUM_VALUES)
773         return NULL;
774     return expr_value_type_strings[type];
775 }