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