aboutsummaryrefslogtreecommitdiff
path: root/src/xkbcomp/ast-build.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xkbcomp/ast-build.c')
-rw-r--r--src/xkbcomp/ast-build.c830
1 files changed, 830 insertions, 0 deletions
diff --git a/src/xkbcomp/ast-build.c b/src/xkbcomp/ast-build.c
new file mode 100644
index 0000000..7ee13d0
--- /dev/null
+++ b/src/xkbcomp/ast-build.c
@@ -0,0 +1,830 @@
+/************************************************************
+ * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of Silicon Graphics not be
+ * used in advertising or publicity pertaining to distribution
+ * of the software without specific prior written permission.
+ * Silicon Graphics makes no representation about the suitability
+ * of this software for any purpose. It is provided "as is"
+ * without any express or implied warranty.
+ *
+ * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+ * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
+ * THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ ********************************************************/
+
+/*
+ * Copyright © 2012 Intel Corporation
+ * Copyright © 2012 Ran Benita <ran234@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Daniel Stone <daniel@fooishbar.org>
+ * Ran Benita <ran234@gmail.com>
+ */
+
+#include "config.h"
+
+#include "xkbcomp-priv.h"
+#include "ast-build.h"
+#include "include.h"
+
+static ExprDef *
+ExprCreate(enum expr_op_type op, enum expr_value_type type, size_t size)
+{
+ ExprDef *expr = malloc(size);
+ if (!expr)
+ return NULL;
+
+ expr->common.type = STMT_EXPR;
+ expr->common.next = NULL;
+ expr->expr.op = op;
+ expr->expr.value_type = type;
+
+ return expr;
+}
+
+ExprDef *
+ExprCreateString(xkb_atom_t str)
+{
+ ExprDef *expr = ExprCreate(EXPR_VALUE, EXPR_TYPE_STRING, sizeof(ExprString));
+ if (!expr)
+ return NULL;
+ expr->string.str = str;
+ return expr;
+}
+
+ExprDef *
+ExprCreateInteger(int ival)
+{
+ ExprDef *expr = ExprCreate(EXPR_VALUE, EXPR_TYPE_INT, sizeof(ExprInteger));
+ if (!expr)
+ return NULL;
+ expr->integer.ival = ival;
+ return expr;
+}
+
+ExprDef *
+ExprCreateFloat(void)
+{
+ ExprDef *expr = ExprCreate(EXPR_VALUE, EXPR_TYPE_FLOAT, sizeof(ExprFloat));
+ if (!expr)
+ return NULL;
+ return expr;
+}
+
+ExprDef *
+ExprCreateBoolean(bool set)
+{
+ ExprDef *expr = ExprCreate(EXPR_VALUE, EXPR_TYPE_BOOLEAN, sizeof(ExprBoolean));
+ if (!expr)
+ return NULL;
+ expr->boolean.set = set;
+ return expr;
+}
+
+ExprDef *
+ExprCreateKeyName(xkb_atom_t key_name)
+{
+ ExprDef *expr = ExprCreate(EXPR_VALUE, EXPR_TYPE_KEYNAME, sizeof(ExprKeyName));
+ if (!expr)
+ return NULL;
+ expr->key_name.key_name = key_name;
+ return expr;
+}
+
+ExprDef *
+ExprCreateIdent(xkb_atom_t ident)
+{
+ ExprDef *expr = ExprCreate(EXPR_IDENT, EXPR_TYPE_UNKNOWN, sizeof(ExprIdent));
+ if (!expr)
+ return NULL;
+ expr->ident.ident = ident;
+ return expr;
+}
+
+ExprDef *
+ExprCreateUnary(enum expr_op_type op, enum expr_value_type type,
+ ExprDef *child)
+{
+ ExprDef *expr = ExprCreate(op, type, sizeof(ExprUnary));
+ if (!expr)
+ return NULL;
+ expr->unary.child = child;
+ return expr;
+}
+
+ExprDef *
+ExprCreateBinary(enum expr_op_type op, ExprDef *left, ExprDef *right)
+{
+ ExprDef *expr = ExprCreate(op, EXPR_TYPE_UNKNOWN, sizeof(ExprBinary));
+ if (!expr)
+ return NULL;
+
+ if (op == EXPR_ASSIGN || left->expr.value_type == EXPR_TYPE_UNKNOWN)
+ expr->expr.value_type = right->expr.value_type;
+ else if (left->expr.value_type == right->expr.value_type ||
+ right->expr.value_type == EXPR_TYPE_UNKNOWN)
+ expr->expr.value_type = left->expr.value_type;
+ expr->binary.left = left;
+ expr->binary.right = right;
+
+ return expr;
+}
+
+ExprDef *
+ExprCreateFieldRef(xkb_atom_t element, xkb_atom_t field)
+{
+ ExprDef *expr = ExprCreate(EXPR_FIELD_REF, EXPR_TYPE_UNKNOWN, sizeof(ExprFieldRef));
+ if (!expr)
+ return NULL;
+ expr->field_ref.element = element;
+ expr->field_ref.field = field;
+ return expr;
+}
+
+ExprDef *
+ExprCreateArrayRef(xkb_atom_t element, xkb_atom_t field, ExprDef *entry)
+{
+ ExprDef *expr = ExprCreate(EXPR_ARRAY_REF, EXPR_TYPE_UNKNOWN, sizeof(ExprArrayRef));
+ if (!expr)
+ return NULL;
+ expr->array_ref.element = element;
+ expr->array_ref.field = field;
+ expr->array_ref.entry = entry;
+ return expr;
+}
+
+ExprDef *
+ExprCreateAction(xkb_atom_t name, ExprDef *args)
+{
+ ExprDef *expr = ExprCreate(EXPR_ACTION_DECL, EXPR_TYPE_UNKNOWN, sizeof(ExprAction));
+ if (!expr)
+ return NULL;
+ expr->action.name = name;
+ expr->action.args = args;
+ return expr;
+}
+
+ExprDef *
+ExprCreateActionList(ExprDef *actions)
+{
+ ExprDef *expr = ExprCreate(EXPR_ACTION_LIST, EXPR_TYPE_ACTIONS, sizeof(ExprActionList));
+ if (!expr)
+ return NULL;
+ expr->actions.actions = actions;
+ return expr;
+}
+
+ExprDef *
+ExprCreateKeysymList(xkb_keysym_t sym)
+{
+ ExprDef *expr = ExprCreate(EXPR_KEYSYM_LIST, EXPR_TYPE_SYMBOLS, sizeof(ExprKeysymList));
+ if (!expr)
+ return NULL;
+
+ darray_init(expr->keysym_list.syms);
+ darray_init(expr->keysym_list.symsMapIndex);
+ darray_init(expr->keysym_list.symsNumEntries);
+
+ darray_append(expr->keysym_list.syms, sym);
+ darray_append(expr->keysym_list.symsMapIndex, 0);
+ darray_append(expr->keysym_list.symsNumEntries, 1);
+
+ return expr;
+}
+
+ExprDef *
+ExprCreateMultiKeysymList(ExprDef *expr)
+{
+ unsigned nLevels = darray_size(expr->keysym_list.symsMapIndex);
+
+ darray_resize(expr->keysym_list.symsMapIndex, 1);
+ darray_resize(expr->keysym_list.symsNumEntries, 1);
+ darray_item(expr->keysym_list.symsMapIndex, 0) = 0;
+ darray_item(expr->keysym_list.symsNumEntries, 0) = nLevels;
+
+ return expr;
+}
+
+ExprDef *
+ExprAppendKeysymList(ExprDef *expr, xkb_keysym_t sym)
+{
+ unsigned nSyms = darray_size(expr->keysym_list.syms);
+
+ darray_append(expr->keysym_list.symsMapIndex, nSyms);
+ darray_append(expr->keysym_list.symsNumEntries, 1);
+ darray_append(expr->keysym_list.syms, sym);
+
+ return expr;
+}
+
+ExprDef *
+ExprAppendMultiKeysymList(ExprDef *expr, ExprDef *append)
+{
+ unsigned nSyms = darray_size(expr->keysym_list.syms);
+ unsigned numEntries = darray_size(append->keysym_list.syms);
+
+ darray_append(expr->keysym_list.symsMapIndex, nSyms);
+ darray_append(expr->keysym_list.symsNumEntries, numEntries);
+ darray_concat(expr->keysym_list.syms, append->keysym_list.syms);
+
+ FreeStmt((ParseCommon *) append);
+
+ return expr;
+}
+
+KeycodeDef *
+KeycodeCreate(xkb_atom_t name, int64_t value)
+{
+ KeycodeDef *def = malloc(sizeof(*def));
+ if (!def)
+ return NULL;
+
+ def->common.type = STMT_KEYCODE;
+ def->common.next = NULL;
+ def->name = name;
+ def->value = value;
+
+ return def;
+}
+
+KeyAliasDef *
+KeyAliasCreate(xkb_atom_t alias, xkb_atom_t real)
+{
+ KeyAliasDef *def = malloc(sizeof(*def));
+ if (!def)
+ return NULL;
+
+ def->common.type = STMT_ALIAS;
+ def->common.next = NULL;
+ def->alias = alias;
+ def->real = real;
+
+ return def;
+}
+
+VModDef *
+VModCreate(xkb_atom_t name, ExprDef *value)
+{
+ VModDef *def = malloc(sizeof(*def));
+ if (!def)
+ return NULL;
+
+ def->common.type = STMT_VMOD;
+ def->common.next = NULL;
+ def->name = name;
+ def->value = value;
+
+ return def;
+}
+
+VarDef *
+VarCreate(ExprDef *name, ExprDef *value)
+{
+ VarDef *def = malloc(sizeof(*def));
+ if (!def)
+ return NULL;
+
+ def->common.type = STMT_VAR;
+ def->common.next = NULL;
+ def->name = name;
+ def->value = value;
+
+ return def;
+}
+
+VarDef *
+BoolVarCreate(xkb_atom_t ident, bool set)
+{
+ ExprDef *name, *value;
+ VarDef *def;
+ if (!(name = ExprCreateIdent(ident))) {
+ return NULL;
+ }
+ if (!(value = ExprCreateBoolean(set))) {
+ FreeStmt((ParseCommon *) name);
+ return NULL;
+ }
+ if (!(def = VarCreate(name, value))) {
+ FreeStmt((ParseCommon *) name);
+ FreeStmt((ParseCommon *) value);
+ return NULL;
+ }
+ return def;
+}
+
+InterpDef *
+InterpCreate(xkb_keysym_t sym, ExprDef *match)
+{
+ InterpDef *def = malloc(sizeof(*def));
+ if (!def)
+ return NULL;
+
+ def->common.type = STMT_INTERP;
+ def->common.next = NULL;
+ def->sym = sym;
+ def->match = match;
+ def->def = NULL;
+
+ return def;
+}
+
+KeyTypeDef *
+KeyTypeCreate(xkb_atom_t name, VarDef *body)
+{
+ KeyTypeDef *def = malloc(sizeof(*def));
+ if (!def)
+ return NULL;
+
+ def->common.type = STMT_TYPE;
+ def->common.next = NULL;
+ def->merge = MERGE_DEFAULT;
+ def->name = name;
+ def->body = body;
+
+ return def;
+}
+
+SymbolsDef *
+SymbolsCreate(xkb_atom_t keyName, VarDef *symbols)
+{
+ SymbolsDef *def = malloc(sizeof(*def));
+ if (!def)
+ return NULL;
+
+ def->common.type = STMT_SYMBOLS;
+ def->common.next = NULL;
+ def->merge = MERGE_DEFAULT;
+ def->keyName = keyName;
+ def->symbols = symbols;
+
+ return def;
+}
+
+GroupCompatDef *
+GroupCompatCreate(unsigned group, ExprDef *val)
+{
+ GroupCompatDef *def = malloc(sizeof(*def));
+ if (!def)
+ return NULL;
+
+ def->common.type = STMT_GROUP_COMPAT;
+ def->common.next = NULL;
+ def->merge = MERGE_DEFAULT;
+ def->group = group;
+ def->def = val;
+
+ return def;
+}
+
+ModMapDef *
+ModMapCreate(xkb_atom_t modifier, ExprDef *keys)
+{
+ ModMapDef *def = malloc(sizeof(*def));
+ if (!def)
+ return NULL;
+
+ def->common.type = STMT_MODMAP;
+ def->common.next = NULL;
+ def->merge = MERGE_DEFAULT;
+ def->modifier = modifier;
+ def->keys = keys;
+
+ return def;
+}
+
+LedMapDef *
+LedMapCreate(xkb_atom_t name, VarDef *body)
+{
+ LedMapDef *def = malloc(sizeof(*def));
+ if (!def)
+ return NULL;
+
+ def->common.type = STMT_LED_MAP;
+ def->common.next = NULL;
+ def->merge = MERGE_DEFAULT;
+ def->name = name;
+ def->body = body;
+
+ return def;
+}
+
+LedNameDef *
+LedNameCreate(unsigned ndx, ExprDef *name, bool virtual)
+{
+ LedNameDef *def = malloc(sizeof(*def));
+ if (!def)
+ return NULL;
+
+ def->common.type = STMT_LED_NAME;
+ def->common.next = NULL;
+ def->merge = MERGE_DEFAULT;
+ def->ndx = ndx;
+ def->name = name;
+ def->virtual = virtual;
+
+ return def;
+}
+
+static void
+FreeInclude(IncludeStmt *incl);
+
+IncludeStmt *
+IncludeCreate(struct xkb_context *ctx, char *str, enum merge_mode merge)
+{
+ IncludeStmt *incl, *first;
+ char *file, *map, *stmt, *tmp, *extra_data;
+ char nextop;
+
+ incl = first = NULL;
+ file = map = NULL;
+ tmp = str;
+ stmt = strdup_safe(str);
+ while (tmp && *tmp)
+ {
+ if (!ParseIncludeMap(&tmp, &file, &map, &nextop, &extra_data))
+ goto err;
+
+ /*
+ * Given an RMLVO (here layout) like 'us,,fr', the rules parser
+ * will give out something like 'pc+us+:2+fr:3+inet(evdev)'.
+ * We should just skip the ':2' in this case and leave it to the
+ * appropriate section to deal with the empty group.
+ */
+ if (isempty(file)) {
+ free(file);
+ free(map);
+ free(extra_data);
+ continue;
+ }
+
+ if (first == NULL) {
+ first = incl = malloc(sizeof(*first));
+ } else {
+ incl->next_incl = malloc(sizeof(*first));
+ incl = incl->next_incl;
+ }
+
+ if (!incl)
+ break;
+
+ incl->common.type = STMT_INCLUDE;
+ incl->common.next = NULL;
+ incl->merge = merge;
+ incl->stmt = NULL;
+ incl->file = file;
+ incl->map = map;
+ incl->modifier = extra_data;
+ incl->next_incl = NULL;
+
+ if (nextop == '|')
+ merge = MERGE_AUGMENT;
+ else
+ merge = MERGE_OVERRIDE;
+ }
+
+ if (first)
+ first->stmt = stmt;
+ else
+ free(stmt);
+
+ return first;
+
+err:
+ log_err(ctx, "Illegal include statement \"%s\"; Ignored\n", stmt);
+ FreeInclude(first);
+ free(stmt);
+ return NULL;
+}
+
+XkbFile *
+XkbFileCreate(enum xkb_file_type type, char *name, ParseCommon *defs,
+ enum xkb_map_flags flags)
+{
+ XkbFile *file;
+
+ file = calloc(1, sizeof(*file));
+ if (!file)
+ return NULL;
+
+ XkbEscapeMapName(name);
+ file->file_type = type;
+ file->name = name ? name : strdup("(unnamed)");
+ file->defs = defs;
+ file->flags = flags;
+
+ return file;
+}
+
+XkbFile *
+XkbFileFromComponents(struct xkb_context *ctx,
+ const struct xkb_component_names *kkctgs)
+{
+ char *const components[] = {
+ kkctgs->keycodes, kkctgs->types,
+ kkctgs->compat, kkctgs->symbols,
+ };
+ enum xkb_file_type type;
+ IncludeStmt *include = NULL;
+ XkbFile *file = NULL;
+ ParseCommon *defs = NULL, *defsLast = NULL;
+
+ for (type = FIRST_KEYMAP_FILE_TYPE; type <= LAST_KEYMAP_FILE_TYPE; type++) {
+ include = IncludeCreate(ctx, components[type], MERGE_DEFAULT);
+ if (!include)
+ goto err;
+
+ file = XkbFileCreate(type, NULL, (ParseCommon *) include, 0);
+ if (!file) {
+ FreeInclude(include);
+ goto err;
+ }
+
+ if (!defs)
+ defsLast = defs = &file->common;
+ else
+ defsLast = defsLast->next = &file->common;
+ }
+
+ file = XkbFileCreate(FILE_TYPE_KEYMAP, NULL, defs, 0);
+ if (!file)
+ goto err;
+
+ return file;
+
+err:
+ FreeXkbFile((XkbFile *) defs);
+ return NULL;
+}
+
+static void
+FreeExpr(ExprDef *expr)
+{
+ if (!expr)
+ return;
+
+ switch (expr->expr.op) {
+ case EXPR_NEGATE:
+ case EXPR_UNARY_PLUS:
+ case EXPR_NOT:
+ case EXPR_INVERT:
+ FreeStmt((ParseCommon *) expr->unary.child);
+ break;
+
+ case EXPR_DIVIDE:
+ case EXPR_ADD:
+ case EXPR_SUBTRACT:
+ case EXPR_MULTIPLY:
+ case EXPR_ASSIGN:
+ FreeStmt((ParseCommon *) expr->binary.left);
+ FreeStmt((ParseCommon *) expr->binary.right);
+ break;
+
+ case EXPR_ACTION_DECL:
+ FreeStmt((ParseCommon *) expr->action.args);
+ break;
+
+ case EXPR_ACTION_LIST:
+ FreeStmt((ParseCommon *) expr->actions.actions);
+ break;
+
+ case EXPR_ARRAY_REF:
+ FreeStmt((ParseCommon *) expr->array_ref.entry);
+ break;
+
+ case EXPR_KEYSYM_LIST:
+ darray_free(expr->keysym_list.syms);
+ darray_free(expr->keysym_list.symsMapIndex);
+ darray_free(expr->keysym_list.symsNumEntries);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+FreeInclude(IncludeStmt *incl)
+{
+ IncludeStmt *next;
+
+ while (incl)
+ {
+ next = incl->next_incl;
+
+ free(incl->file);
+ free(incl->map);
+ free(incl->modifier);
+ free(incl->stmt);
+
+ free(incl);
+ incl = next;
+ }
+}
+
+void
+FreeStmt(ParseCommon *stmt)
+{
+ ParseCommon *next;
+
+ while (stmt)
+ {
+ next = stmt->next;
+
+ switch (stmt->type) {
+ case STMT_INCLUDE:
+ FreeInclude((IncludeStmt *) stmt);
+ /* stmt is already free'd here. */
+ stmt = NULL;
+ break;
+ case STMT_EXPR:
+ FreeExpr((ExprDef *) stmt);
+ break;
+ case STMT_VAR:
+ FreeStmt((ParseCommon *) ((VarDef *) stmt)->name);
+ FreeStmt((ParseCommon *) ((VarDef *) stmt)->value);
+ break;
+ case STMT_TYPE:
+ FreeStmt((ParseCommon *) ((KeyTypeDef *) stmt)->body);
+ break;
+ case STMT_INTERP:
+ FreeStmt((ParseCommon *) ((InterpDef *) stmt)->match);
+ FreeStmt((ParseCommon *) ((InterpDef *) stmt)->def);
+ break;
+ case STMT_VMOD:
+ FreeStmt((ParseCommon *) ((VModDef *) stmt)->value);
+ break;
+ case STMT_SYMBOLS:
+ FreeStmt((ParseCommon *) ((SymbolsDef *) stmt)->symbols);
+ break;
+ case STMT_MODMAP:
+ FreeStmt((ParseCommon *) ((ModMapDef *) stmt)->keys);
+ break;
+ case STMT_GROUP_COMPAT:
+ FreeStmt((ParseCommon *) ((GroupCompatDef *) stmt)->def);
+ break;
+ case STMT_LED_MAP:
+ FreeStmt((ParseCommon *) ((LedMapDef *) stmt)->body);
+ break;
+ case STMT_LED_NAME:
+ FreeStmt((ParseCommon *) ((LedNameDef *) stmt)->name);
+ break;
+ default:
+ break;
+ }
+
+ free(stmt);
+ stmt = next;
+ }
+}
+
+void
+FreeXkbFile(XkbFile *file)
+{
+ XkbFile *next;
+
+ while (file)
+ {
+ next = (XkbFile *) file->common.next;
+
+ switch (file->file_type) {
+ case FILE_TYPE_KEYMAP:
+ FreeXkbFile((XkbFile *) file->defs);
+ break;
+
+ case FILE_TYPE_TYPES:
+ case FILE_TYPE_COMPAT:
+ case FILE_TYPE_SYMBOLS:
+ case FILE_TYPE_KEYCODES:
+ case FILE_TYPE_GEOMETRY:
+ FreeStmt(file->defs);
+ break;
+
+ default:
+ break;
+ }
+
+ free(file->name);
+ free(file);
+ file = next;
+ }
+}
+
+static const char *xkb_file_type_strings[_FILE_TYPE_NUM_ENTRIES] = {
+ [FILE_TYPE_KEYCODES] = "xkb_keycodes",
+ [FILE_TYPE_TYPES] = "xkb_types",
+ [FILE_TYPE_COMPAT] = "xkb_compatibility",
+ [FILE_TYPE_SYMBOLS] = "xkb_symbols",
+ [FILE_TYPE_GEOMETRY] = "xkb_geometry",
+ [FILE_TYPE_KEYMAP] = "xkb_keymap",
+ [FILE_TYPE_RULES] = "rules",
+};
+
+const char *
+xkb_file_type_to_string(enum xkb_file_type type)
+{
+ if (type >= _FILE_TYPE_NUM_ENTRIES)
+ return "unknown";
+ return xkb_file_type_strings[type];
+}
+
+static const char *stmt_type_strings[_STMT_NUM_VALUES] = {
+ [STMT_UNKNOWN] = "unknown statement",
+ [STMT_INCLUDE] = "include statement",
+ [STMT_KEYCODE] = "key name definition",
+ [STMT_ALIAS] = "key alias definition",
+ [STMT_EXPR] = "expression",
+ [STMT_VAR] = "variable definition",
+ [STMT_TYPE] = "key type definition",
+ [STMT_INTERP] = "symbol interpretation definition",
+ [STMT_VMOD] = "virtual modifiers definition",
+ [STMT_SYMBOLS] = "key symbols definition",
+ [STMT_MODMAP] = "modifier map declaration",
+ [STMT_GROUP_COMPAT] = "group declaration",
+ [STMT_LED_MAP] = "indicator map declaration",
+ [STMT_LED_NAME] = "indicator name declaration",
+};
+
+const char *
+stmt_type_to_string(enum stmt_type type)
+{
+ if (type >= _STMT_NUM_VALUES)
+ return NULL;
+ return stmt_type_strings[type];
+}
+
+static const char *expr_op_type_strings[_EXPR_NUM_VALUES] = {
+ [EXPR_VALUE] = "literal",
+ [EXPR_IDENT] = "identifier",
+ [EXPR_ACTION_DECL] = "action declaration",
+ [EXPR_FIELD_REF] = "field reference",
+ [EXPR_ARRAY_REF] = "array reference",
+ [EXPR_KEYSYM_LIST] = "list of keysyms",
+ [EXPR_ACTION_LIST] = "list of actions",
+ [EXPR_ADD] = "addition",
+ [EXPR_SUBTRACT] = "subtraction",
+ [EXPR_MULTIPLY] = "multiplication",
+ [EXPR_DIVIDE] = "division",
+ [EXPR_ASSIGN] = "assignment",
+ [EXPR_NOT] = "logical negation",
+ [EXPR_NEGATE] = "arithmetic negation",
+ [EXPR_INVERT] = "bitwise inversion",
+ [EXPR_UNARY_PLUS] = "unary plus",
+};
+
+const char *
+expr_op_type_to_string(enum expr_op_type type)
+{
+ if (type >= _EXPR_NUM_VALUES)
+ return NULL;
+ return expr_op_type_strings[type];
+}
+
+static const char *expr_value_type_strings[_EXPR_TYPE_NUM_VALUES] = {
+ [EXPR_TYPE_UNKNOWN] = "unknown",
+ [EXPR_TYPE_BOOLEAN] = "boolean",
+ [EXPR_TYPE_INT] = "int",
+ [EXPR_TYPE_FLOAT] = "float",
+ [EXPR_TYPE_STRING] = "string",
+ [EXPR_TYPE_ACTION] = "action",
+ [EXPR_TYPE_ACTIONS] = "actions",
+ [EXPR_TYPE_KEYNAME] = "keyname",
+ [EXPR_TYPE_SYMBOLS] = "symbols",
+};
+
+const char *
+expr_value_type_to_string(enum expr_value_type type)
+{
+ if (type >= _EXPR_TYPE_NUM_VALUES)
+ return NULL;
+ return expr_value_type_strings[type];
+}