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