diff options
Diffstat (limited to 'src/xkbcomp/ast-build.c')
-rw-r--r-- | src/xkbcomp/ast-build.c | 830 |
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]; +} |