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