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