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