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