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