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