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
58ParseCommon *
59AppendStmt(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
72static ExprDef *
73ExprCreate(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
92ExprDef *
93ExprCreateString(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
100ExprDef *
101ExprCreateInteger(int ival)
102{
103    EXPR_CREATE(ExprInteger, expr, EXPR_VALUE, EXPR_TYPE_INT);
104    expr->integer.ival = ival;
105    return expr;
106}
107
108ExprDef *
109ExprCreateBoolean(bool set)
110{
111    EXPR_CREATE(ExprBoolean, expr, EXPR_VALUE, EXPR_TYPE_BOOLEAN);
112    expr->boolean.set = set;
113    return expr;
114}
115
116ExprDef *
117ExprCreateKeyName(xkb_atom_t key_name)
118{
119    EXPR_CREATE(ExprKeyName, expr, EXPR_VALUE, EXPR_TYPE_KEYNAME);
120    expr->key_name.key_name = key_name;
121    return expr;
122}
123
124ExprDef *
125ExprCreateIdent(xkb_atom_t ident)
126{
127    EXPR_CREATE(ExprIdent, expr, EXPR_IDENT, EXPR_TYPE_UNKNOWN);
128    expr->ident.ident = ident;
129    return expr;
130}
131
132ExprDef *
133ExprCreateUnary(enum expr_op_type op, enum expr_value_type type,
134                ExprDef *child)
135{
136    EXPR_CREATE(ExprUnary, expr, op, type);
137    expr->unary.child = child;
138    return expr;
139}
140
141ExprDef *
142ExprCreateBinary(enum expr_op_type op, ExprDef *left, ExprDef *right)
143{
144    EXPR_CREATE(ExprBinary, expr, op, EXPR_TYPE_UNKNOWN);
145
146    if (op == EXPR_ASSIGN || left->expr.value_type == EXPR_TYPE_UNKNOWN)
147        expr->expr.value_type = right->expr.value_type;
148    else if (left->expr.value_type == right->expr.value_type ||
149             right->expr.value_type == EXPR_TYPE_UNKNOWN)
150        expr->expr.value_type = left->expr.value_type;
151    expr->binary.left = left;
152    expr->binary.right = right;
153
154    return expr;
155}
156
157ExprDef *
158ExprCreateFieldRef(xkb_atom_t element, xkb_atom_t field)
159{
160    EXPR_CREATE(ExprFieldRef, expr, EXPR_FIELD_REF, EXPR_TYPE_UNKNOWN);
161    expr->field_ref.element = element;
162    expr->field_ref.field = field;
163    return expr;
164}
165
166ExprDef *
167ExprCreateArrayRef(xkb_atom_t element, xkb_atom_t field, ExprDef *entry)
168{
169    EXPR_CREATE(ExprArrayRef, expr, EXPR_ARRAY_REF, EXPR_TYPE_UNKNOWN);
170    expr->array_ref.element = element;
171    expr->array_ref.field = field;
172    expr->array_ref.entry = entry;
173    return expr;
174}
175
176ExprDef *
177ExprCreateAction(xkb_atom_t name, ExprDef *args)
178{
179    EXPR_CREATE(ExprAction, expr, EXPR_ACTION_DECL, EXPR_TYPE_UNKNOWN);
180    expr->action.name = name;
181    expr->action.args = args;
182    return expr;
183}
184
185ExprDef *
186ExprCreateKeysymList(xkb_keysym_t sym)
187{
188    EXPR_CREATE(ExprKeysymList, expr, EXPR_KEYSYM_LIST, EXPR_TYPE_SYMBOLS);
189
190    darray_init(expr->keysym_list.syms);
191    darray_init(expr->keysym_list.symsMapIndex);
192    darray_init(expr->keysym_list.symsNumEntries);
193
194    darray_append(expr->keysym_list.syms, sym);
195    darray_append(expr->keysym_list.symsMapIndex, 0);
196    darray_append(expr->keysym_list.symsNumEntries, 1);
197
198    return expr;
199}
200
201ExprDef *
202ExprCreateMultiKeysymList(ExprDef *expr)
203{
204    unsigned nLevels = darray_size(expr->keysym_list.symsMapIndex);
205
206    darray_resize(expr->keysym_list.symsMapIndex, 1);
207    darray_resize(expr->keysym_list.symsNumEntries, 1);
208    darray_item(expr->keysym_list.symsMapIndex, 0) = 0;
209    darray_item(expr->keysym_list.symsNumEntries, 0) = nLevels;
210
211    return expr;
212}
213
214ExprDef *
215ExprAppendKeysymList(ExprDef *expr, xkb_keysym_t sym)
216{
217    unsigned nSyms = darray_size(expr->keysym_list.syms);
218
219    darray_append(expr->keysym_list.symsMapIndex, nSyms);
220    darray_append(expr->keysym_list.symsNumEntries, 1);
221    darray_append(expr->keysym_list.syms, sym);
222
223    return expr;
224}
225
226ExprDef *
227ExprAppendMultiKeysymList(ExprDef *expr, ExprDef *append)
228{
229    xkb_keysym_t *syms;
230    unsigned nSyms = darray_size(expr->keysym_list.syms);
231    unsigned numEntries = darray_size(append->keysym_list.syms);
232
233    darray_append(expr->keysym_list.symsMapIndex, nSyms);
234    darray_append(expr->keysym_list.symsNumEntries, numEntries);
235    darray_steal(append->keysym_list.syms, &syms, NULL);
236    darray_append_items(expr->keysym_list.syms, syms, numEntries);
237
238    FreeStmt((ParseCommon *) &append);
239
240    return expr;
241}
242
243KeycodeDef *
244KeycodeCreate(xkb_atom_t name, int64_t value)
245{
246    KeycodeDef *def = malloc(sizeof(*def));
247    if (!def)
248        return NULL;
249
250    def->common.type = STMT_KEYCODE;
251    def->common.next = NULL;
252    def->name = name;
253    def->value = value;
254
255    return def;
256}
257
258KeyAliasDef *
259KeyAliasCreate(xkb_atom_t alias, xkb_atom_t real)
260{
261    KeyAliasDef *def = malloc(sizeof(*def));
262    if (!def)
263        return NULL;
264
265    def->common.type = STMT_ALIAS;
266    def->common.next = NULL;
267    def->alias = alias;
268    def->real = real;
269
270    return def;
271}
272
273VModDef *
274VModCreate(xkb_atom_t name, ExprDef *value)
275{
276    VModDef *def = malloc(sizeof(*def));
277    if (!def)
278        return NULL;
279
280    def->common.type = STMT_VMOD;
281    def->common.next = NULL;
282    def->name = name;
283    def->value = value;
284
285    return def;
286}
287
288VarDef *
289VarCreate(ExprDef *name, ExprDef *value)
290{
291    VarDef *def = malloc(sizeof(*def));
292    if (!def)
293        return NULL;
294
295    def->common.type = STMT_VAR;
296    def->common.next = NULL;
297    def->name = name;
298    def->value = value;
299
300    return def;
301}
302
303VarDef *
304BoolVarCreate(xkb_atom_t ident, bool set)
305{
306    ExprDef *name, *value;
307    VarDef *def;
308    if (!(name = ExprCreateIdent(ident))) {
309        return NULL;
310    }
311    if (!(value = ExprCreateBoolean(set))) {
312        FreeStmt((ParseCommon *) name);
313        return NULL;
314    }
315    if (!(def = VarCreate(name, value))) {
316        FreeStmt((ParseCommon *) name);
317        FreeStmt((ParseCommon *) value);
318        return NULL;
319    }
320    return def;
321}
322
323InterpDef *
324InterpCreate(xkb_keysym_t sym, ExprDef *match)
325{
326    InterpDef *def = malloc(sizeof(*def));
327    if (!def)
328        return NULL;
329
330    def->common.type = STMT_INTERP;
331    def->common.next = NULL;
332    def->sym = sym;
333    def->match = match;
334    def->def = NULL;
335
336    return def;
337}
338
339KeyTypeDef *
340KeyTypeCreate(xkb_atom_t name, VarDef *body)
341{
342    KeyTypeDef *def = malloc(sizeof(*def));
343    if (!def)
344        return NULL;
345
346    def->common.type = STMT_TYPE;
347    def->common.next = NULL;
348    def->merge = MERGE_DEFAULT;
349    def->name = name;
350    def->body = body;
351
352    return def;
353}
354
355SymbolsDef *
356SymbolsCreate(xkb_atom_t keyName, VarDef *symbols)
357{
358    SymbolsDef *def = malloc(sizeof(*def));
359    if (!def)
360        return NULL;
361
362    def->common.type = STMT_SYMBOLS;
363    def->common.next = NULL;
364    def->merge = MERGE_DEFAULT;
365    def->keyName = keyName;
366    def->symbols = symbols;
367
368    return def;
369}
370
371GroupCompatDef *
372GroupCompatCreate(unsigned group, ExprDef *val)
373{
374    GroupCompatDef *def = malloc(sizeof(*def));
375    if (!def)
376        return NULL;
377
378    def->common.type = STMT_GROUP_COMPAT;
379    def->common.next = NULL;
380    def->merge = MERGE_DEFAULT;
381    def->group = group;
382    def->def = val;
383
384    return def;
385}
386
387ModMapDef *
388ModMapCreate(xkb_atom_t modifier, ExprDef *keys)
389{
390    ModMapDef *def = malloc(sizeof(*def));
391    if (!def)
392        return NULL;
393
394    def->common.type = STMT_MODMAP;
395    def->common.next = NULL;
396    def->merge = MERGE_DEFAULT;
397    def->modifier = modifier;
398    def->keys = keys;
399
400    return def;
401}
402
403LedMapDef *
404LedMapCreate(xkb_atom_t name, VarDef *body)
405{
406    LedMapDef *def = malloc(sizeof(*def));
407    if (!def)
408        return NULL;
409
410    def->common.type = STMT_LED_MAP;
411    def->common.next = NULL;
412    def->merge = MERGE_DEFAULT;
413    def->name = name;
414    def->body = body;
415
416    return def;
417}
418
419LedNameDef *
420LedNameCreate(unsigned ndx, ExprDef *name, bool virtual)
421{
422    LedNameDef *def = malloc(sizeof(*def));
423    if (!def)
424        return NULL;
425
426    def->common.type = STMT_LED_NAME;
427    def->common.next = NULL;
428    def->merge = MERGE_DEFAULT;
429    def->ndx = ndx;
430    def->name = name;
431    def->virtual = virtual;
432
433    return def;
434}
435
436static void
437FreeInclude(IncludeStmt *incl);
438
439IncludeStmt *
440IncludeCreate(struct xkb_context *ctx, char *str, enum merge_mode merge)
441{
442    IncludeStmt *incl, *first;
443    char *file, *map, *stmt, *tmp, *extra_data;
444    char nextop;
445
446    incl = first = NULL;
447    file = map = NULL;
448    tmp = str;
449    stmt = strdup_safe(str);
450    while (tmp && *tmp)
451    {
452        if (!ParseIncludeMap(&tmp, &file, &map, &nextop, &extra_data))
453            goto err;
454
455        /*
456         * Given an RMLVO (here layout) like 'us,,fr', the rules parser
457         * will give out something like 'pc+us+:2+fr:3+inet(evdev)'.
458         * We should just skip the ':2' in this case and leave it to the
459         * appropriate section to deal with the empty group.
460         */
461        if (isempty(file)) {
462            free(file);
463            free(map);
464            free(extra_data);
465            continue;
466        }
467
468        if (first == NULL) {
469            first = incl = malloc(sizeof(*first));
470        } else {
471            incl->next_incl = malloc(sizeof(*first));
472            incl = incl->next_incl;
473        }
474
475        if (!incl) {
476            log_wsgo(ctx,
477                     "Allocation failure in IncludeCreate; "
478                     "Using only part of the include\n");
479            break;
480        }
481
482        incl->common.type = STMT_INCLUDE;
483        incl->common.next = NULL;
484        incl->merge = merge;
485        incl->stmt = NULL;
486        incl->file = file;
487        incl->map = map;
488        incl->modifier = extra_data;
489        incl->next_incl = NULL;
490
491        if (nextop == '|')
492            merge = MERGE_AUGMENT;
493        else
494            merge = MERGE_OVERRIDE;
495    }
496
497    if (first)
498        first->stmt = stmt;
499    else
500        free(stmt);
501
502    return first;
503
504err:
505    log_err(ctx, "Illegal include statement \"%s\"; Ignored\n", stmt);
506    FreeInclude(first);
507    free(stmt);
508    return NULL;
509}
510
511XkbFile *
512XkbFileCreate(enum xkb_file_type type, char *name, ParseCommon *defs,
513              enum xkb_map_flags flags)
514{
515    XkbFile *file;
516
517    file = calloc(1, sizeof(*file));
518    if (!file)
519        return NULL;
520
521    XkbEscapeMapName(name);
522    file->file_type = type;
523    file->topName = strdup_safe(name);
524    file->name = name;
525    file->defs = defs;
526    file->flags = flags;
527
528    return file;
529}
530
531XkbFile *
532XkbFileFromComponents(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
564err:
565    FreeXkbFile((XkbFile *) defs);
566    return NULL;
567}
568
569static void
570FreeExpr(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
612static void
613FreeInclude(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
631void
632FreeStmt(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
687void
688FreeXkbFile(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->topName);
715        free(file);
716        file = next;
717    }
718}
719
720static const char *xkb_file_type_strings[_FILE_TYPE_NUM_ENTRIES] = {
721    [FILE_TYPE_KEYCODES] = "xkb_keycodes",
722    [FILE_TYPE_TYPES] = "xkb_types",
723    [FILE_TYPE_COMPAT] = "xkb_compatibility",
724    [FILE_TYPE_SYMBOLS] = "xkb_symbols",
725    [FILE_TYPE_GEOMETRY] = "xkb_geometry",
726    [FILE_TYPE_KEYMAP] = "xkb_keymap",
727    [FILE_TYPE_RULES] = "rules",
728};
729
730const char *
731xkb_file_type_to_string(enum xkb_file_type type)
732{
733    if (type > _FILE_TYPE_NUM_ENTRIES)
734        return "unknown";
735    return xkb_file_type_strings[type];
736}
737
738static const char *stmt_type_strings[_STMT_NUM_VALUES] = {
739    [STMT_UNKNOWN] = "unknown statement",
740    [STMT_INCLUDE] = "include statement",
741    [STMT_KEYCODE] = "key name definition",
742    [STMT_ALIAS] = "key alias definition",
743    [STMT_EXPR] = "expression",
744    [STMT_VAR] = "variable definition",
745    [STMT_TYPE] = "key type definition",
746    [STMT_INTERP] = "symbol interpretation definition",
747    [STMT_VMOD] = "virtual modifiers definition",
748    [STMT_SYMBOLS] = "key symbols definition",
749    [STMT_MODMAP] = "modifier map declaration",
750    [STMT_GROUP_COMPAT] = "group declaration",
751    [STMT_LED_MAP] = "indicator map declaration",
752    [STMT_LED_NAME] = "indicator name declaration",
753};
754
755const char *
756stmt_type_to_string(enum stmt_type type)
757{
758    if (type >= _STMT_NUM_VALUES)
759        return NULL;
760    return stmt_type_strings[type];
761}
762
763static const char *expr_op_type_strings[_EXPR_NUM_VALUES] = {
764    [EXPR_VALUE] = "literal",
765    [EXPR_IDENT] = "identifier",
766    [EXPR_ACTION_DECL] = "action declaration",
767    [EXPR_FIELD_REF] = "field reference",
768    [EXPR_ARRAY_REF] = "array reference",
769    [EXPR_KEYSYM_LIST] = "list of keysyms",
770    [EXPR_ACTION_LIST] = "list of actions",
771    [EXPR_ADD] = "addition",
772    [EXPR_SUBTRACT] = "subtraction",
773    [EXPR_MULTIPLY] = "multiplication",
774    [EXPR_DIVIDE] = "division",
775    [EXPR_ASSIGN] = "assignment",
776    [EXPR_NOT] = "logical negation",
777    [EXPR_NEGATE] = "arithmetic negation",
778    [EXPR_INVERT] = "bitwise inversion",
779    [EXPR_UNARY_PLUS] = "unary plus",
780};
781
782const char *
783expr_op_type_to_string(enum expr_op_type type)
784{
785    if (type >= _EXPR_NUM_VALUES)
786        return NULL;
787    return expr_op_type_strings[type];
788}
789
790static const char *expr_value_type_strings[_EXPR_TYPE_NUM_VALUES] = {
791    [EXPR_TYPE_UNKNOWN] = "unknown",
792    [EXPR_TYPE_BOOLEAN] = "boolean",
793    [EXPR_TYPE_INT] = "int",
794    [EXPR_TYPE_STRING] = "string",
795    [EXPR_TYPE_ACTION] = "action",
796    [EXPR_TYPE_KEYNAME] = "keyname",
797    [EXPR_TYPE_SYMBOLS] = "symbols",
798};
799
800const char *
801expr_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}
807