• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "xkbcomp-priv.h"
28 #include "text.h"
29 #include "expr.h"
30 
31 typedef bool (*IdentLookupFunc)(struct xkb_context *ctx, const void *priv,
32                                 xkb_atom_t field, enum expr_value_type type,
33                                 unsigned int *val_rtrn);
34 
35 bool
ExprResolveLhs(struct xkb_context * ctx,const ExprDef * expr,const char ** elem_rtrn,const char ** field_rtrn,ExprDef ** index_rtrn)36 ExprResolveLhs(struct xkb_context *ctx, const ExprDef *expr,
37                const char **elem_rtrn, const char **field_rtrn,
38                ExprDef **index_rtrn)
39 {
40     switch (expr->expr.op) {
41     case EXPR_IDENT:
42         *elem_rtrn = NULL;
43         *field_rtrn = xkb_atom_text(ctx, expr->ident.ident);
44         *index_rtrn = NULL;
45         return true;
46     case EXPR_FIELD_REF:
47         *elem_rtrn = xkb_atom_text(ctx, expr->field_ref.element);
48         *field_rtrn = xkb_atom_text(ctx, expr->field_ref.field);
49         *index_rtrn = NULL;
50         return true;
51     case EXPR_ARRAY_REF:
52         *elem_rtrn = xkb_atom_text(ctx, expr->array_ref.element);
53         *field_rtrn = xkb_atom_text(ctx, expr->array_ref.field);
54         *index_rtrn = expr->array_ref.entry;
55         return true;
56     default:
57         break;
58     }
59     log_wsgo(ctx, "Unexpected operator %d in ResolveLhs\n", expr->expr.op);
60     return false;
61 }
62 
63 static bool
SimpleLookup(struct xkb_context * ctx,const void * priv,xkb_atom_t field,enum expr_value_type type,unsigned int * val_rtrn)64 SimpleLookup(struct xkb_context *ctx, const void *priv, xkb_atom_t field,
65              enum expr_value_type type, unsigned int *val_rtrn)
66 {
67     const LookupEntry *entry;
68     const char *str;
69 
70     if (!priv || field == XKB_ATOM_NONE || type != EXPR_TYPE_INT)
71         return false;
72 
73     str = xkb_atom_text(ctx, field);
74     for (entry = priv; entry && entry->name; entry++) {
75         if (istreq(str, entry->name)) {
76             *val_rtrn = entry->value;
77             return true;
78         }
79     }
80 
81     return false;
82 }
83 
84 /* Data passed in the *priv argument for LookupModMask. */
85 typedef struct {
86     const struct xkb_mod_set *mods;
87     enum mod_type mod_type;
88 } LookupModMaskPriv;
89 
90 static bool
LookupModMask(struct xkb_context * ctx,const void * priv,xkb_atom_t field,enum expr_value_type type,xkb_mod_mask_t * val_rtrn)91 LookupModMask(struct xkb_context *ctx, const void *priv, xkb_atom_t field,
92               enum expr_value_type type, xkb_mod_mask_t *val_rtrn)
93 {
94     const char *str;
95     xkb_mod_index_t ndx;
96     const LookupModMaskPriv *arg = priv;
97     const struct xkb_mod_set *mods = arg->mods;
98     enum mod_type mod_type = arg->mod_type;
99 
100     if (type != EXPR_TYPE_INT)
101         return false;
102 
103     str = xkb_atom_text(ctx, field);
104 
105     if (istreq(str, "all")) {
106         *val_rtrn  = MOD_REAL_MASK_ALL;
107         return true;
108     }
109 
110     if (istreq(str, "none")) {
111         *val_rtrn = 0;
112         return true;
113     }
114 
115     ndx = XkbModNameToIndex(mods, field, mod_type);
116     if (ndx == XKB_MOD_INVALID)
117         return false;
118 
119     *val_rtrn = (1u << ndx);
120     return true;
121 }
122 
123 bool
ExprResolveBoolean(struct xkb_context * ctx,const ExprDef * expr,bool * set_rtrn)124 ExprResolveBoolean(struct xkb_context *ctx, const ExprDef *expr,
125                    bool *set_rtrn)
126 {
127     bool ok = false;
128     const char *ident;
129 
130     switch (expr->expr.op) {
131     case EXPR_VALUE:
132         if (expr->expr.value_type != EXPR_TYPE_BOOLEAN) {
133             log_err(ctx,
134                     "Found constant of type %s where boolean was expected\n",
135                     expr_value_type_to_string(expr->expr.value_type));
136             return false;
137         }
138         *set_rtrn = expr->boolean.set;
139         return true;
140 
141     case EXPR_IDENT:
142         ident = xkb_atom_text(ctx, expr->ident.ident);
143         if (ident) {
144             if (istreq(ident, "true") ||
145                 istreq(ident, "yes") ||
146                 istreq(ident, "on")) {
147                 *set_rtrn = true;
148                 return true;
149             }
150             else if (istreq(ident, "false") ||
151                      istreq(ident, "no") ||
152                      istreq(ident, "off")) {
153                 *set_rtrn = false;
154                 return true;
155             }
156         }
157         log_err(ctx, "Identifier \"%s\" of type boolean is unknown\n", ident);
158         return false;
159 
160     case EXPR_FIELD_REF:
161         log_err(ctx, "Default \"%s.%s\" of type boolean is unknown\n",
162                 xkb_atom_text(ctx, expr->field_ref.element),
163                 xkb_atom_text(ctx, expr->field_ref.field));
164         return false;
165 
166     case EXPR_INVERT:
167     case EXPR_NOT:
168         ok = ExprResolveBoolean(ctx, expr, set_rtrn);
169         if (ok)
170             *set_rtrn = !*set_rtrn;
171         return ok;
172     case EXPR_ADD:
173     case EXPR_SUBTRACT:
174     case EXPR_MULTIPLY:
175     case EXPR_DIVIDE:
176     case EXPR_ASSIGN:
177     case EXPR_NEGATE:
178     case EXPR_UNARY_PLUS:
179         log_err(ctx, "%s of boolean values not permitted\n",
180                 expr_op_type_to_string(expr->expr.op));
181         break;
182 
183     default:
184         log_wsgo(ctx, "Unknown operator %d in ResolveBoolean\n",
185                  expr->expr.op);
186         break;
187     }
188 
189     return false;
190 }
191 
192 bool
ExprResolveKeyCode(struct xkb_context * ctx,const ExprDef * expr,xkb_keycode_t * kc)193 ExprResolveKeyCode(struct xkb_context *ctx, const ExprDef *expr,
194                    xkb_keycode_t *kc)
195 {
196     xkb_keycode_t leftRtrn, rightRtrn;
197 
198     switch (expr->expr.op) {
199     case EXPR_VALUE:
200         if (expr->expr.value_type != EXPR_TYPE_INT) {
201             log_err(ctx,
202                     "Found constant of type %s where an int was expected\n",
203                     expr_value_type_to_string(expr->expr.value_type));
204             return false;
205         }
206 
207         *kc = (xkb_keycode_t) expr->integer.ival;
208         return true;
209 
210     case EXPR_ADD:
211     case EXPR_SUBTRACT:
212     case EXPR_MULTIPLY:
213     case EXPR_DIVIDE:
214         if (!ExprResolveKeyCode(ctx, expr->binary.left, &leftRtrn) ||
215             !ExprResolveKeyCode(ctx, expr->binary.right, &rightRtrn))
216             return false;
217 
218         switch (expr->expr.op) {
219         case EXPR_ADD:
220             *kc = leftRtrn + rightRtrn;
221             break;
222         case EXPR_SUBTRACT:
223             *kc = leftRtrn - rightRtrn;
224             break;
225         case EXPR_MULTIPLY:
226             *kc = leftRtrn * rightRtrn;
227             break;
228         case EXPR_DIVIDE:
229             if (rightRtrn == 0) {
230                 log_err(ctx, "Cannot divide by zero: %d / %d\n",
231                         leftRtrn, rightRtrn);
232                 return false;
233             }
234 
235             *kc = leftRtrn / rightRtrn;
236             break;
237         default:
238             break;
239         }
240 
241         return true;
242 
243     case EXPR_NEGATE:
244         if (!ExprResolveKeyCode(ctx, expr->unary.child, &leftRtrn))
245             return false;
246 
247         *kc = ~leftRtrn;
248         return true;
249 
250     case EXPR_UNARY_PLUS:
251         return ExprResolveKeyCode(ctx, expr->unary.child, kc);
252 
253     default:
254         log_wsgo(ctx, "Unknown operator %d in ResolveKeyCode\n",
255                  expr->expr.op);
256         break;
257     }
258 
259     return false;
260 }
261 
262 /**
263  * This function returns ... something.  It's a bit of a guess, really.
264  *
265  * If an integer is given in value ctx, it will be returned in ival.
266  * If an ident or field reference is given, the lookup function (if given)
267  * will be called.  At the moment, only SimpleLookup use this, and they both
268  * return the results in uval.  And don't support field references.
269  *
270  * Cool.
271  */
272 static bool
ExprResolveIntegerLookup(struct xkb_context * ctx,const ExprDef * expr,int * val_rtrn,IdentLookupFunc lookup,const void * lookupPriv)273 ExprResolveIntegerLookup(struct xkb_context *ctx, const ExprDef *expr,
274                          int *val_rtrn, IdentLookupFunc lookup,
275                          const void *lookupPriv)
276 {
277     bool ok = false;
278     int l, r;
279     unsigned u;
280     ExprDef *left, *right;
281 
282     switch (expr->expr.op) {
283     case EXPR_VALUE:
284         if (expr->expr.value_type != EXPR_TYPE_INT) {
285             log_err(ctx,
286                     "Found constant of type %s where an int was expected\n",
287                     expr_value_type_to_string(expr->expr.value_type));
288             return false;
289         }
290 
291         *val_rtrn = expr->integer.ival;
292         return true;
293 
294     case EXPR_IDENT:
295         if (lookup)
296             ok = lookup(ctx, lookupPriv, expr->ident.ident, EXPR_TYPE_INT, &u);
297 
298         if (!ok)
299             log_err(ctx, "Identifier \"%s\" of type int is unknown\n",
300                     xkb_atom_text(ctx, expr->ident.ident));
301         else
302             *val_rtrn = (int) u;
303 
304         return ok;
305 
306     case EXPR_FIELD_REF:
307         log_err(ctx, "Default \"%s.%s\" of type int is unknown\n",
308                 xkb_atom_text(ctx, expr->field_ref.element),
309                 xkb_atom_text(ctx, expr->field_ref.field));
310         return false;
311 
312     case EXPR_ADD:
313     case EXPR_SUBTRACT:
314     case EXPR_MULTIPLY:
315     case EXPR_DIVIDE:
316         left = expr->binary.left;
317         right = expr->binary.right;
318         if (!ExprResolveIntegerLookup(ctx, left, &l, lookup, lookupPriv) ||
319             !ExprResolveIntegerLookup(ctx, right, &r, lookup, lookupPriv))
320             return false;
321 
322         switch (expr->expr.op) {
323         case EXPR_ADD:
324             *val_rtrn = l + r;
325             break;
326         case EXPR_SUBTRACT:
327             *val_rtrn = l - r;
328             break;
329         case EXPR_MULTIPLY:
330             *val_rtrn = l * r;
331             break;
332         case EXPR_DIVIDE:
333             if (r == 0) {
334                 log_err(ctx, "Cannot divide by zero: %d / %d\n", l, r);
335                 return false;
336             }
337             *val_rtrn = l / r;
338             break;
339         default:
340             log_err(ctx, "%s of integers not permitted\n",
341                     expr_op_type_to_string(expr->expr.op));
342             return false;
343         }
344 
345         return true;
346 
347     case EXPR_ASSIGN:
348         log_wsgo(ctx, "Assignment operator not implemented yet\n");
349         break;
350 
351     case EXPR_NOT:
352         log_err(ctx, "The ! operator cannot be applied to an integer\n");
353         return false;
354 
355     case EXPR_INVERT:
356     case EXPR_NEGATE:
357         left = expr->unary.child;
358         if (!ExprResolveIntegerLookup(ctx, left, &l, lookup, lookupPriv))
359             return false;
360 
361         *val_rtrn = (expr->expr.op == EXPR_NEGATE ? -l : ~l);
362         return true;
363 
364     case EXPR_UNARY_PLUS:
365         left = expr->unary.child;
366         return ExprResolveIntegerLookup(ctx, left, val_rtrn, lookup,
367                                         lookupPriv);
368 
369     default:
370         log_wsgo(ctx, "Unknown operator %d in ResolveInteger\n",
371                  expr->expr.op);
372         break;
373     }
374 
375     return false;
376 }
377 
378 bool
ExprResolveInteger(struct xkb_context * ctx,const ExprDef * expr,int * val_rtrn)379 ExprResolveInteger(struct xkb_context *ctx, const ExprDef *expr,
380                    int *val_rtrn)
381 {
382     return ExprResolveIntegerLookup(ctx, expr, val_rtrn, NULL, NULL);
383 }
384 
385 bool
ExprResolveGroup(struct xkb_context * ctx,const ExprDef * expr,xkb_layout_index_t * group_rtrn)386 ExprResolveGroup(struct xkb_context *ctx, const ExprDef *expr,
387                  xkb_layout_index_t *group_rtrn)
388 {
389     bool ok;
390     int result;
391 
392     ok = ExprResolveIntegerLookup(ctx, expr, &result, SimpleLookup,
393                                   groupNames);
394     if (!ok)
395         return false;
396 
397     if (result <= 0 || result > XKB_MAX_GROUPS) {
398         log_err(ctx, "Group index %u is out of range (1..%d)\n",
399                 result, XKB_MAX_GROUPS);
400         return false;
401     }
402 
403     *group_rtrn = (xkb_layout_index_t) result;
404     return true;
405 }
406 
407 bool
ExprResolveLevel(struct xkb_context * ctx,const ExprDef * expr,xkb_level_index_t * level_rtrn)408 ExprResolveLevel(struct xkb_context *ctx, const ExprDef *expr,
409                  xkb_level_index_t *level_rtrn)
410 {
411     bool ok;
412     int result;
413 
414     ok = ExprResolveIntegerLookup(ctx, expr, &result, SimpleLookup,
415                                   levelNames);
416     if (!ok)
417         return false;
418 
419     if (result < 1) {
420         log_err(ctx, "Shift level %d is out of range\n", result);
421         return false;
422     }
423 
424     /* Level is zero-indexed from now on. */
425     *level_rtrn = (unsigned int) (result - 1);
426     return true;
427 }
428 
429 bool
ExprResolveButton(struct xkb_context * ctx,const ExprDef * expr,int * btn_rtrn)430 ExprResolveButton(struct xkb_context *ctx, const ExprDef *expr, int *btn_rtrn)
431 {
432     return ExprResolveIntegerLookup(ctx, expr, btn_rtrn, SimpleLookup,
433                                     buttonNames);
434 }
435 
436 bool
ExprResolveString(struct xkb_context * ctx,const ExprDef * expr,xkb_atom_t * val_rtrn)437 ExprResolveString(struct xkb_context *ctx, const ExprDef *expr,
438                   xkb_atom_t *val_rtrn)
439 {
440     switch (expr->expr.op) {
441     case EXPR_VALUE:
442         if (expr->expr.value_type != EXPR_TYPE_STRING) {
443             log_err(ctx, "Found constant of type %s, expected a string\n",
444                     expr_value_type_to_string(expr->expr.value_type));
445             return false;
446         }
447 
448         *val_rtrn = expr->string.str;
449         return true;
450 
451     case EXPR_IDENT:
452         log_err(ctx, "Identifier \"%s\" of type string not found\n",
453                 xkb_atom_text(ctx, expr->ident.ident));
454         return false;
455 
456     case EXPR_FIELD_REF:
457         log_err(ctx, "Default \"%s.%s\" of type string not found\n",
458                 xkb_atom_text(ctx, expr->field_ref.element),
459                 xkb_atom_text(ctx, expr->field_ref.field));
460         return false;
461 
462     case EXPR_ADD:
463     case EXPR_SUBTRACT:
464     case EXPR_MULTIPLY:
465     case EXPR_DIVIDE:
466     case EXPR_ASSIGN:
467     case EXPR_NEGATE:
468     case EXPR_INVERT:
469     case EXPR_NOT:
470     case EXPR_UNARY_PLUS:
471         log_err(ctx, "%s of strings not permitted\n",
472                 expr_op_type_to_string(expr->expr.op));
473         return false;
474 
475     default:
476         log_wsgo(ctx, "Unknown operator %d in ResolveString\n",
477                  expr->expr.op);
478         break;
479     }
480     return false;
481 }
482 
483 bool
ExprResolveEnum(struct xkb_context * ctx,const ExprDef * expr,unsigned int * val_rtrn,const LookupEntry * values)484 ExprResolveEnum(struct xkb_context *ctx, const ExprDef *expr,
485                 unsigned int *val_rtrn, const LookupEntry *values)
486 {
487     if (expr->expr.op != EXPR_IDENT) {
488         log_err(ctx, "Found a %s where an enumerated value was expected\n",
489                 expr_op_type_to_string(expr->expr.op));
490         return false;
491     }
492 
493     if (!SimpleLookup(ctx, values, expr->ident.ident, EXPR_TYPE_INT,
494                       val_rtrn)) {
495         log_err(ctx, "Illegal identifier %s; expected one of:\n",
496                 xkb_atom_text(ctx, expr->ident.ident));
497         while (values && values->name)
498         {
499             log_err(ctx, "\t%s\n", values->name);
500             values++;
501         }
502         return false;
503     }
504 
505     return true;
506 }
507 
508 static bool
ExprResolveMaskLookup(struct xkb_context * ctx,const ExprDef * expr,unsigned int * val_rtrn,IdentLookupFunc lookup,const void * lookupPriv)509 ExprResolveMaskLookup(struct xkb_context *ctx, const ExprDef *expr,
510                       unsigned int *val_rtrn, IdentLookupFunc lookup,
511                       const void *lookupPriv)
512 {
513     bool ok = 0;
514     unsigned int l, r;
515     int v;
516     ExprDef *left, *right;
517     const char *bogus = NULL;
518 
519     switch (expr->expr.op) {
520     case EXPR_VALUE:
521         if (expr->expr.value_type != EXPR_TYPE_INT) {
522             log_err(ctx,
523                     "Found constant of type %s where a mask was expected\n",
524                     expr_value_type_to_string(expr->expr.value_type));
525             return false;
526         }
527         *val_rtrn = (unsigned int) expr->integer.ival;
528         return true;
529 
530     case EXPR_IDENT:
531         ok = lookup(ctx, lookupPriv, expr->ident.ident, EXPR_TYPE_INT,
532                     val_rtrn);
533         if (!ok)
534             log_err(ctx, "Identifier \"%s\" of type int is unknown\n",
535                     xkb_atom_text(ctx, expr->ident.ident));
536         return ok;
537 
538     case EXPR_FIELD_REF:
539         log_err(ctx, "Default \"%s.%s\" of type int is unknown\n",
540                 xkb_atom_text(ctx, expr->field_ref.element),
541                 xkb_atom_text(ctx, expr->field_ref.field));
542         return false;
543 
544     case EXPR_ARRAY_REF:
545         bogus = "array reference";
546 
547     case EXPR_ACTION_DECL:
548         if (bogus == NULL)
549             bogus = "function use";
550         log_err(ctx,
551                 "Unexpected %s in mask expression; Expression Ignored\n",
552                 bogus);
553         return false;
554 
555     case EXPR_ADD:
556     case EXPR_SUBTRACT:
557     case EXPR_MULTIPLY:
558     case EXPR_DIVIDE:
559         left = expr->binary.left;
560         right = expr->binary.right;
561         if (!ExprResolveMaskLookup(ctx, left, &l, lookup, lookupPriv) ||
562             !ExprResolveMaskLookup(ctx, right, &r, lookup, lookupPriv))
563             return false;
564 
565         switch (expr->expr.op) {
566         case EXPR_ADD:
567             *val_rtrn = l | r;
568             break;
569         case EXPR_SUBTRACT:
570             *val_rtrn = l & (~r);
571             break;
572         case EXPR_MULTIPLY:
573         case EXPR_DIVIDE:
574             log_err(ctx, "Cannot %s masks; Illegal operation ignored\n",
575                     (expr->expr.op == EXPR_DIVIDE ? "divide" : "multiply"));
576             return false;
577         default:
578             break;
579         }
580 
581         return true;
582 
583     case EXPR_ASSIGN:
584         log_wsgo(ctx, "Assignment operator not implemented yet\n");
585         break;
586 
587     case EXPR_INVERT:
588         left = expr->unary.child;
589         if (!ExprResolveIntegerLookup(ctx, left, &v, lookup, lookupPriv))
590             return false;
591 
592         *val_rtrn = ~v;
593         return true;
594 
595     case EXPR_UNARY_PLUS:
596     case EXPR_NEGATE:
597     case EXPR_NOT:
598         left = expr->unary.child;
599         if (!ExprResolveIntegerLookup(ctx, left, &v, lookup, lookupPriv))
600             log_err(ctx, "The %s operator cannot be used with a mask\n",
601                     (expr->expr.op == EXPR_NEGATE ? "-" : "!"));
602         return false;
603 
604     default:
605         log_wsgo(ctx, "Unknown operator %d in ResolveMask\n",
606                  expr->expr.op);
607         break;
608     }
609 
610     return false;
611 }
612 
613 bool
ExprResolveMask(struct xkb_context * ctx,const ExprDef * expr,unsigned int * mask_rtrn,const LookupEntry * values)614 ExprResolveMask(struct xkb_context *ctx, const ExprDef *expr,
615                 unsigned int *mask_rtrn, const LookupEntry *values)
616 {
617     return ExprResolveMaskLookup(ctx, expr, mask_rtrn, SimpleLookup, values);
618 }
619 
620 bool
ExprResolveModMask(struct xkb_context * ctx,const ExprDef * expr,enum mod_type mod_type,const struct xkb_mod_set * mods,xkb_mod_mask_t * mask_rtrn)621 ExprResolveModMask(struct xkb_context *ctx, const ExprDef *expr,
622                    enum mod_type mod_type, const struct xkb_mod_set *mods,
623                    xkb_mod_mask_t *mask_rtrn)
624 {
625     LookupModMaskPriv priv = { .mods = mods, .mod_type = mod_type };
626     return ExprResolveMaskLookup(ctx, expr, mask_rtrn, LookupModMask, &priv);
627 }
628 
629 bool
ExprResolveKeySym(struct xkb_context * ctx,const ExprDef * expr,xkb_keysym_t * sym_rtrn)630 ExprResolveKeySym(struct xkb_context *ctx, const ExprDef *expr,
631                   xkb_keysym_t *sym_rtrn)
632 {
633     int val;
634 
635     if (expr->expr.op == EXPR_IDENT) {
636         const char *str = xkb_atom_text(ctx, expr->ident.ident);
637         *sym_rtrn = xkb_keysym_from_name(str, 0);
638         if (*sym_rtrn != XKB_KEY_NoSymbol)
639             return true;
640     }
641 
642     if (!ExprResolveInteger(ctx, expr, &val))
643         return false;
644 
645     if (val < 0 || val >= 10)
646         return false;
647 
648     *sym_rtrn = XKB_KEY_0 + (xkb_keysym_t) val;
649     return true;
650 }
651 
652 bool
ExprResolveMod(struct xkb_context * ctx,const ExprDef * def,enum mod_type mod_type,const struct xkb_mod_set * mods,xkb_mod_index_t * ndx_rtrn)653 ExprResolveMod(struct xkb_context *ctx, const ExprDef *def,
654                enum mod_type mod_type, const struct xkb_mod_set *mods,
655                xkb_mod_index_t *ndx_rtrn)
656 {
657     xkb_mod_index_t ndx;
658     xkb_atom_t name;
659 
660     if (def->expr.op != EXPR_IDENT) {
661         log_err(ctx,
662                 "Cannot resolve virtual modifier: "
663                 "found %s where a virtual modifier name was expected\n",
664                 expr_op_type_to_string(def->expr.op));
665         return false;
666     }
667 
668     name = def->ident.ident;
669     ndx = XkbModNameToIndex(mods, name, mod_type);
670     if (ndx == XKB_MOD_INVALID) {
671         log_err(ctx,
672                 "Cannot resolve virtual modifier: "
673                 "\"%s\" was not previously declared\n",
674                 xkb_atom_text(ctx, name));
675         return false;
676     }
677 
678     *ndx_rtrn = ndx;
679     return true;
680 }
681