Some atom related optimizations
[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 "expr.h"
28
29 typedef bool (*IdentLookupFunc)(struct xkb_context *ctx, const void *priv,
30                                 xkb_atom_t field, unsigned type,
31                                 ExprResult *val_rtrn);
32
33 const char *
34 exprOpText(unsigned type)
35 {
36     static char buf[32];
37
38     switch (type) {
39     case ExprValue:
40         strcpy(buf, "literal");
41         break;
42     case ExprIdent:
43         strcpy(buf, "identifier");
44         break;
45     case ExprActionDecl:
46         strcpy(buf, "action declaration");
47         break;
48     case ExprFieldRef:
49         strcpy(buf, "field reference");
50         break;
51     case ExprArrayRef:
52         strcpy(buf, "array reference");
53         break;
54     case ExprKeysymList:
55         strcpy(buf, "list of keysyms");
56         break;
57     case ExprActionList:
58         strcpy(buf, "list of actions");
59         break;
60     case OpAdd:
61         strcpy(buf, "addition");
62         break;
63     case OpSubtract:
64         strcpy(buf, "subtraction");
65         break;
66     case OpMultiply:
67         strcpy(buf, "multiplication");
68         break;
69     case OpDivide:
70         strcpy(buf, "division");
71         break;
72     case OpAssign:
73         strcpy(buf, "assignment");
74         break;
75     case OpNot:
76         strcpy(buf, "logical not");
77         break;
78     case OpNegate:
79         strcpy(buf, "arithmetic negation");
80         break;
81     case OpInvert:
82         strcpy(buf, "bitwise inversion");
83         break;
84     case OpUnaryPlus:
85         strcpy(buf, "unary plus");
86         break;
87     default:
88         snprintf(buf, sizeof(buf), "illegal(%d)", type);
89         break;
90     }
91     return buf;
92 }
93
94 static const char *
95 exprTypeText(unsigned type)
96 {
97     static char buf[20];
98
99     switch (type) {
100     case TypeUnknown:
101         strcpy(buf, "unknown");
102         break;
103     case TypeBoolean:
104         strcpy(buf, "boolean");
105         break;
106     case TypeInt:
107         strcpy(buf, "int");
108         break;
109     case TypeString:
110         strcpy(buf, "string");
111         break;
112     case TypeAction:
113         strcpy(buf, "action");
114         break;
115     case TypeKeyName:
116         strcpy(buf, "keyname");
117         break;
118     default:
119         snprintf(buf, sizeof(buf), "illegal(%d)", type);
120         break;
121     }
122     return buf;
123 }
124
125 int
126 ExprResolveLhs(struct xkb_keymap *keymap, ExprDef *expr,
127                ExprResult *elem_rtrn, ExprResult *field_rtrn,
128                ExprDef **index_rtrn)
129 {
130     struct xkb_context *ctx = keymap->ctx;
131
132     switch (expr->op) {
133     case ExprIdent:
134         elem_rtrn->str = NULL;
135         field_rtrn->str = xkb_atom_text(ctx, expr->value.str);
136         *index_rtrn = NULL;
137         return true;
138     case ExprFieldRef:
139         elem_rtrn->str = xkb_atom_text(ctx, expr->value.field.element);
140         field_rtrn->str = xkb_atom_text(ctx, expr->value.field.field);
141         *index_rtrn = NULL;
142         return true;
143     case ExprArrayRef:
144         elem_rtrn->str = xkb_atom_text(ctx, expr->value.array.element);
145         field_rtrn->str = xkb_atom_text(ctx, expr->value.array.field);
146         *index_rtrn = expr->value.array.entry;
147         return true;
148     }
149     log_wsgo(keymap->ctx, "Unexpected operator %d in ResolveLhs\n", expr->op);
150     return false;
151 }
152
153 static bool
154 SimpleLookup(struct xkb_context *ctx, const void *priv,
155              xkb_atom_t field, unsigned type, ExprResult *val_rtrn)
156 {
157     const LookupEntry *entry;
158     const char *str;
159
160     if ((priv == NULL) || (field == XKB_ATOM_NONE) || (type != TypeInt))
161         return false;
162
163     str = xkb_atom_text(ctx, field);
164     for (entry = priv; (entry != NULL) && (entry->name != NULL); entry++) {
165         if (strcasecmp(str, entry->name) == 0) {
166             val_rtrn->uval = entry->result;
167             return true;
168         }
169     }
170
171     return false;
172 }
173
174 static const LookupEntry modIndexNames[] = {
175     { "shift", ShiftMapIndex },
176     { "control", ControlMapIndex },
177     { "lock", LockMapIndex },
178     { "mod1", Mod1MapIndex },
179     { "mod2", Mod2MapIndex },
180     { "mod3", Mod3MapIndex },
181     { "mod4", Mod4MapIndex },
182     { "mod5", Mod5MapIndex },
183     { "none", XkbNoModifier },
184     { NULL, 0 }
185 };
186
187 bool
188 LookupModIndex(struct xkb_context *ctx, const void *priv, xkb_atom_t field,
189                unsigned type, ExprResult *val_rtrn)
190 {
191     return SimpleLookup(ctx, modIndexNames, field, type, val_rtrn);
192 }
193
194 bool
195 LookupModMask(struct xkb_context *ctx, const void *priv, xkb_atom_t field,
196               unsigned type, ExprResult *val_rtrn)
197 {
198     const char *str;
199     bool ret = true;
200
201     if (type != TypeInt)
202         return false;
203     str = xkb_atom_text(ctx, field);
204     if (str == NULL)
205         return false;
206     if (strcasecmp(str, "all") == 0)
207         val_rtrn->uval = 0xff;
208     else if (strcasecmp(str, "none") == 0)
209         val_rtrn->uval = 0;
210     else if (LookupModIndex(ctx, priv, field, type, val_rtrn))
211         val_rtrn->uval = (1 << val_rtrn->uval);
212     else
213         ret = false;
214     return ret;
215 }
216
217 int
218 ExprResolveBoolean(struct xkb_context *ctx, ExprDef *expr,
219                    ExprResult *val_rtrn)
220 {
221     int ok = 0;
222     const char *bogus = NULL;
223
224     switch (expr->op) {
225     case ExprValue:
226         if (expr->type != TypeBoolean) {
227             log_err(ctx,
228                     "Found constant of type %s where boolean was expected\n",
229                     exprTypeText(expr->type));
230             return false;
231         }
232         val_rtrn->ival = expr->value.ival;
233         return true;
234
235     case ExprIdent:
236         bogus = xkb_atom_text(ctx, expr->value.str);
237         if (bogus) {
238             if ((strcasecmp(bogus, "true") == 0) ||
239                 (strcasecmp(bogus, "yes") == 0) ||
240                 (strcasecmp(bogus, "on") == 0)) {
241                 val_rtrn->uval = 1;
242                 return true;
243             }
244             else if ((strcasecmp(bogus, "false") == 0) ||
245                      (strcasecmp(bogus, "no") == 0) ||
246                      (strcasecmp(bogus, "off") == 0)) {
247                 val_rtrn->uval = 0;
248                 return true;
249             }
250         }
251         log_err(ctx, "Identifier \"%s\" of type int is unknown\n",
252                 xkb_atom_text(ctx, expr->value.str));
253         return false;
254
255     case ExprFieldRef:
256         log_err(ctx, "Default \"%s.%s\" of type boolean is unknown\n",
257                 xkb_atom_text(ctx, expr->value.field.element),
258                 xkb_atom_text(ctx, expr->value.field.field));
259         return false;
260
261     case OpInvert:
262     case OpNot:
263         ok = ExprResolveBoolean(ctx, expr, val_rtrn);
264         if (ok)
265             val_rtrn->uval = !val_rtrn->uval;
266         return ok;
267     case OpAdd:
268     case OpSubtract:
269     case OpMultiply:
270     case OpDivide:
271     case OpAssign:
272     case OpNegate:
273     case OpUnaryPlus:
274         log_err(ctx, "%s of boolean values not permitted\n",
275                 exprOpText(expr->op));
276         break;
277
278     default:
279         log_wsgo(ctx, "Unknown operator %d in ResolveBoolean\n", expr->op);
280         break;
281     }
282     return false;
283 }
284
285 int
286 ExprResolveKeyCode(struct xkb_context *ctx, ExprDef *expr,
287                    ExprResult *val_rtrn)
288 {
289     ExprResult leftRtrn, rightRtrn;
290     ExprDef *left, *right;
291
292     switch (expr->op) {
293     case ExprValue:
294         if (expr->type != TypeInt) {
295             log_err(ctx,
296                     "Found constant of type %s where an int was expected\n",
297                     exprTypeText(expr->type));
298             return false;
299         }
300         val_rtrn->uval = expr->value.uval;
301         return true;
302
303     case OpAdd:
304     case OpSubtract:
305     case OpMultiply:
306     case OpDivide:
307         left = expr->value.binary.left;
308         right = expr->value.binary.right;
309         if (ExprResolveKeyCode(ctx, left, &leftRtrn) &&
310             ExprResolveKeyCode(ctx, right, &rightRtrn)) {
311             switch (expr->op) {
312             case OpAdd:
313                 val_rtrn->uval = leftRtrn.uval + rightRtrn.uval;
314                 break;
315             case OpSubtract:
316                 val_rtrn->uval = leftRtrn.uval - rightRtrn.uval;
317                 break;
318             case OpMultiply:
319                 val_rtrn->uval = leftRtrn.uval * rightRtrn.uval;
320                 break;
321             case OpDivide:
322                 if (rightRtrn.uval == 0) {
323                     log_err(ctx, "Cannot divide by zero: %d / %d\n",
324                             leftRtrn.uval, rightRtrn.uval);
325                     return false;
326                 }
327                 val_rtrn->uval = leftRtrn.uval / rightRtrn.uval;
328                 break;
329             }
330             return true;
331         }
332         return false;
333
334     case OpNegate:
335         left = expr->value.child;
336         if (ExprResolveKeyCode(ctx, left, &leftRtrn)) {
337             val_rtrn->uval = ~leftRtrn.uval;
338             return true;
339         }
340         return false;
341
342     case OpUnaryPlus:
343         left = expr->value.child;
344         return ExprResolveKeyCode(ctx, left, val_rtrn);
345
346     default:
347         log_wsgo(ctx, "Unknown operator %d in ResolveKeyCode\n", expr->op);
348         break;
349     }
350     return false;
351 }
352
353 /**
354  * This function returns ... something.  It's a bit of a guess, really.
355  *
356  * If a string is given in value ctx, its first character will be
357  * returned in uval.  If an integer is given in value ctx, it will be
358  * returned in ival.  If a float is given in value ctx, it will be
359  * returned as millimetres (rather than points) in ival.
360  *
361  * If an ident or field reference is given, the lookup function (if given)
362  * will be called.  At the moment, only SimpleLookup use this, and they both
363  * return the results in uval.  And don't support field references.
364  *
365  * Cool.
366  */
367 static int
368 ExprResolveIntegerLookup(struct xkb_context *ctx, ExprDef *expr,
369                          ExprResult *val_rtrn, IdentLookupFunc lookup,
370                          const void *lookupPriv)
371 {
372     int ok = 0;
373     ExprResult leftRtrn, rightRtrn;
374     ExprDef *left, *right;
375
376     switch (expr->op) {
377     case ExprValue:
378         if (expr->type == TypeString) {
379             const char *str;
380             str = xkb_atom_text(ctx, expr->value.str);
381             if (str != NULL)
382                 switch (strlen(str)) {
383                 case 0:
384                     val_rtrn->uval = 0;
385                     return true;
386                 case 1:
387                     val_rtrn->uval = str[0];
388                     return true;
389                 default:
390                     break;
391                 }
392         }
393         if (expr->type != TypeInt) {
394             log_err(ctx,
395                     "Found constant of type %s where an int was expected\n",
396                     exprTypeText(expr->type));
397             return false;
398         }
399         val_rtrn->ival = expr->value.ival;
400         return true;
401
402     case ExprIdent:
403         if (lookup)
404             ok = lookup(ctx, lookupPriv, expr->value.str,
405                         TypeInt, val_rtrn);
406         if (!ok)
407             log_err(ctx, "Identifier \"%s\" of type int is unknown\n",
408                     xkb_atom_text(ctx, expr->value.str));
409         return ok;
410
411     case ExprFieldRef:
412         log_err(ctx, "Default \"%s.%s\" of type int is unknown\n",
413                 xkb_atom_text(ctx, expr->value.field.element),
414                 xkb_atom_text(ctx, expr->value.field.field));
415         return false;
416
417     case OpAdd:
418     case OpSubtract:
419     case OpMultiply:
420     case OpDivide:
421         left = expr->value.binary.left;
422         right = expr->value.binary.right;
423         if (ExprResolveIntegerLookup(ctx, left, &leftRtrn, lookup,
424                                      lookupPriv) &&
425             ExprResolveIntegerLookup(ctx, right, &rightRtrn, lookup,
426                                      lookupPriv)) {
427             switch (expr->op) {
428             case OpAdd:
429                 val_rtrn->ival = leftRtrn.ival + rightRtrn.ival;
430                 break;
431             case OpSubtract:
432                 val_rtrn->ival = leftRtrn.ival - rightRtrn.ival;
433                 break;
434             case OpMultiply:
435                 val_rtrn->ival = leftRtrn.ival * rightRtrn.ival;
436                 break;
437             case OpDivide:
438                 if (rightRtrn.ival == 0) {
439                     log_err(ctx, "Cannot divide by zero: %d / %d\n",
440                             leftRtrn.ival, rightRtrn.ival);
441                     return false;
442                 }
443                 val_rtrn->ival = leftRtrn.ival / rightRtrn.ival;
444                 break;
445             }
446             return true;
447         }
448         return false;
449
450     case OpAssign:
451         log_wsgo(ctx, "Assignment operator not implemented yet\n");
452         break;
453
454     case OpNot:
455         log_err(ctx, "The ! operator cannot be applied to an integer\n");
456         return false;
457
458     case OpInvert:
459     case OpNegate:
460         left = expr->value.child;
461         if (ExprResolveIntegerLookup(ctx, left, &leftRtrn, lookup,
462                                      lookupPriv)) {
463             if (expr->op == OpNegate)
464                 val_rtrn->ival = -leftRtrn.ival;
465             else
466                 val_rtrn->ival = ~leftRtrn.ival;
467             return true;
468         }
469         return false;
470
471     case OpUnaryPlus:
472         left = expr->value.child;
473         return ExprResolveIntegerLookup(ctx, left, val_rtrn, lookup,
474                                         lookupPriv);
475
476     default:
477         log_wsgo(ctx, "Unknown operator %d in ResolveInteger\n", expr->op);
478         break;
479     }
480     return false;
481 }
482
483 int
484 ExprResolveInteger(struct xkb_context *ctx, ExprDef *expr,
485                    ExprResult *val_rtrn)
486 {
487     return ExprResolveIntegerLookup(ctx, expr, val_rtrn, NULL, NULL);
488 }
489
490 int
491 ExprResolveGroup(struct xkb_context *ctx, ExprDef *expr,
492                  ExprResult *val_rtrn)
493 {
494     int ret;
495     static const LookupEntry group_names[] = {
496         { "group1", 1 },
497         { "group2", 2 },
498         { "group3", 3 },
499         { "group4", 4 },
500         { "group5", 5 },
501         { "group6", 6 },
502         { "group7", 7 },
503         { "group8", 8 },
504         { NULL, 0 }
505     };
506
507     ret = ExprResolveIntegerLookup(ctx, expr, val_rtrn, SimpleLookup,
508                                    group_names);
509     if (ret == false)
510         return ret;
511
512     if (val_rtrn->uval == 0 || val_rtrn->uval > XkbNumKbdGroups) {
513         log_err(ctx, "Group index %u is out of range (1..%d)\n",
514                 val_rtrn->uval, XkbNumKbdGroups);
515         return false;
516     }
517
518     return true;
519 }
520
521 int
522 ExprResolveLevel(struct xkb_context *ctx, ExprDef *expr,
523                  ExprResult *val_rtrn)
524 {
525     int ret;
526     static const LookupEntry level_names[] = {
527         { "level1", 1 },
528         { "level2", 2 },
529         { "level3", 3 },
530         { "level4", 4 },
531         { "level5", 5 },
532         { "level6", 6 },
533         { "level7", 7 },
534         { "level8", 8 },
535         { NULL, 0 }
536     };
537
538     ret = ExprResolveIntegerLookup(ctx, expr, val_rtrn, SimpleLookup,
539                                    level_names);
540     if (ret == false)
541         return ret;
542
543     if (val_rtrn->ival < 1 || val_rtrn->ival > XkbMaxShiftLevel) {
544         log_err(ctx, "Shift level %d is out of range (1..%d)\n",
545                 val_rtrn->ival, XkbMaxShiftLevel);
546         return false;
547     }
548
549     return true;
550 }
551
552 int
553 ExprResolveButton(struct xkb_context *ctx, ExprDef *expr,
554                   ExprResult *val_rtrn)
555 {
556     static const LookupEntry button_names[] = {
557         { "button1", 1 },
558         { "button2", 2 },
559         { "button3", 3 },
560         { "button4", 4 },
561         { "button5", 5 },
562         { "default", 0 },
563         { NULL, 0 }
564     };
565
566     return ExprResolveIntegerLookup(ctx, expr, val_rtrn, SimpleLookup,
567                                     button_names);
568 }
569
570 int
571 ExprResolveString(struct xkb_context *ctx, ExprDef *expr,
572                   ExprResult *val_rtrn)
573 {
574     switch (expr->op) {
575     case ExprValue:
576         if (expr->type != TypeString) {
577             log_err(ctx, "Found constant of type %s, expected a string\n",
578                     exprTypeText(expr->type));
579             return false;
580         }
581         val_rtrn->str = xkb_atom_text(ctx, expr->value.str);
582         return true;
583
584     case ExprIdent:
585         log_err(ctx, "Identifier \"%s\" of type string not found\n",
586                 xkb_atom_text(ctx, expr->value.str));
587         return false;
588
589     case ExprFieldRef:
590         log_err(ctx, "Default \"%s.%s\" of type string not found\n",
591                 xkb_atom_text(ctx, expr->value.field.element),
592                 xkb_atom_text(ctx, expr->value.field.field));
593         return false;
594
595     case OpAdd:
596     case OpSubtract:
597     case OpMultiply:
598     case OpDivide:
599     case OpAssign:
600     case OpNegate:
601     case OpInvert:
602     case OpNot:
603     case OpUnaryPlus:
604         log_err(ctx, "%s of strings not permitted\n", exprOpText(expr->op));
605         return false;
606
607     default:
608         log_wsgo(ctx, "Unknown operator %d in ResolveString\n", expr->op);
609         break;
610     }
611     return false;
612 }
613
614 int
615 ExprResolveKeyName(struct xkb_context *ctx, ExprDef *expr,
616                    ExprResult *val_rtrn)
617 {
618     switch (expr->op) {
619     case ExprValue:
620         if (expr->type != TypeKeyName) {
621             log_err(ctx, "Found constant of type %s, expected a key name\n",
622                     exprTypeText(expr->type));
623             return false;
624         }
625         memcpy(val_rtrn->name, expr->value.keyName, XkbKeyNameLength);
626         return true;
627
628     case ExprIdent:
629         log_err(ctx, "Identifier \"%s\" of type string not found\n",
630                 xkb_atom_text(ctx, expr->value.str));
631         return false;
632
633     case ExprFieldRef:
634         log_err(ctx, "Default \"%s.%s\" of type key name not found\n",
635                 xkb_atom_text(ctx, expr->value.field.element),
636                 xkb_atom_text(ctx, expr->value.field.field));
637         return false;
638
639     case OpAdd:
640     case OpSubtract:
641     case OpMultiply:
642     case OpDivide:
643     case OpAssign:
644     case OpNegate:
645     case OpInvert:
646     case OpNot:
647     case OpUnaryPlus:
648         log_err(ctx, "%s of key name values not permitted\n",
649                 exprOpText(expr->op));
650         return false;
651
652     default:
653         log_wsgo(ctx, "Unknown operator %d in ResolveKeyName\n", expr->op);
654         break;
655     }
656     return false;
657 }
658
659 /***====================================================================***/
660
661 int
662 ExprResolveEnum(struct xkb_context *ctx, ExprDef *expr,
663                 ExprResult *val_rtrn, const LookupEntry *values)
664 {
665     if (expr->op != ExprIdent) {
666         log_err(ctx, "Found a %s where an enumerated value was expected\n",
667                 exprOpText(expr->op));
668         return false;
669     }
670     if (!SimpleLookup(ctx, values, expr->value.str, TypeInt, val_rtrn)) {
671         int nOut = 0;
672         log_err(ctx, "Illegal identifier %s (expected one of: ",
673                 xkb_atom_text(ctx, expr->value.str));
674         while (values && values->name)
675         {
676             if (nOut != 0)
677                 log_info(ctx, ", %s", values->name);
678             else
679                 log_info(ctx, "%s", values->name);
680             values++;
681             nOut++;
682         }
683         log_info(ctx, ")\n");
684         return false;
685     }
686     return true;
687 }
688
689 static int
690 ExprResolveMaskLookup(struct xkb_context *ctx, ExprDef *expr,
691                       ExprResult *val_rtrn, IdentLookupFunc lookup,
692                       const void *lookupPriv)
693 {
694     int ok = 0;
695     ExprResult leftRtrn, rightRtrn;
696     ExprDef *left, *right;
697     const char *bogus = NULL;
698
699     switch (expr->op) {
700     case ExprValue:
701         if (expr->type != TypeInt) {
702             log_err(ctx,
703                     "Found constant of type %s where a mask was expected\n",
704                     exprTypeText(expr->type));
705             return false;
706         }
707         val_rtrn->ival = expr->value.ival;
708         return true;
709
710     case ExprIdent:
711         ok = lookup(ctx, lookupPriv, expr->value.str, TypeInt, val_rtrn);
712         if (!ok)
713             log_err(ctx, "Identifier \"%s\" of type int is unknown\n",
714                     xkb_atom_text(ctx, expr->value.str));
715         return ok;
716
717     case ExprFieldRef:
718         log_err(ctx, "Default \"%s.%s\" of type int is unknown\n",
719                 xkb_atom_text(ctx, expr->value.field.element),
720                 xkb_atom_text(ctx, expr->value.field.field));
721         return false;
722
723     case ExprArrayRef:
724         bogus = "array reference";
725
726     case ExprActionDecl:
727         if (bogus == NULL)
728             bogus = "function use";
729         log_err(ctx,
730                 "Unexpected %s in mask expression; Expression Ignored\n",
731                 bogus);
732         return false;
733
734     case OpAdd:
735     case OpSubtract:
736     case OpMultiply:
737     case OpDivide:
738         left = expr->value.binary.left;
739         right = expr->value.binary.right;
740         if (ExprResolveMaskLookup(ctx, left, &leftRtrn, lookup,
741                                   lookupPriv) &&
742             ExprResolveMaskLookup(ctx, right, &rightRtrn, lookup,
743                                   lookupPriv)) {
744             switch (expr->op) {
745             case OpAdd:
746                 val_rtrn->ival = leftRtrn.ival | rightRtrn.ival;
747                 break;
748             case OpSubtract:
749                 val_rtrn->ival = leftRtrn.ival & (~rightRtrn.ival);
750                 break;
751             case OpMultiply:
752             case OpDivide:
753                 log_err(ctx, "Cannot %s masks; Illegal operation ignored\n",
754                         (expr->op == OpDivide ? "divide" : "multiply"));
755                 return false;
756             }
757             return true;
758         }
759         return false;
760
761     case OpAssign:
762         log_wsgo(ctx, "Assignment operator not implemented yet\n");
763         break;
764
765     case OpInvert:
766         left = expr->value.child;
767         if (ExprResolveIntegerLookup(ctx, left, &leftRtrn, lookup,
768                                      lookupPriv)) {
769             val_rtrn->ival = ~leftRtrn.ival;
770             return true;
771         }
772         return false;
773
774     case OpUnaryPlus:
775     case OpNegate:
776     case OpNot:
777         left = expr->value.child;
778         if (ExprResolveIntegerLookup(ctx, left, &leftRtrn, lookup,
779                                      lookupPriv)) {
780             log_err(ctx, "The %s operator cannot be used with a mask\n",
781                     (expr->op == OpNegate ? "-" : "!"));
782         }
783         return false;
784
785     default:
786         log_wsgo(ctx, "Unknown operator %d in ResolveMask\n", expr->op);
787         break;
788     }
789     return false;
790 }
791
792 int
793 ExprResolveMask(struct xkb_context *ctx, ExprDef *expr,
794                 ExprResult *val_rtrn, const LookupEntry *values)
795 {
796     return ExprResolveMaskLookup(ctx, expr, val_rtrn, SimpleLookup, values);
797 }
798
799 int
800 ExprResolveModMask(struct xkb_context *ctx, ExprDef *expr,
801                    ExprResult *val_rtrn)
802 {
803     return ExprResolveMaskLookup(ctx, expr, val_rtrn, LookupModMask, NULL);
804 }
805
806 int
807 ExprResolveVModMask(struct xkb_keymap *keymap, ExprDef *expr,
808                     ExprResult *val_rtrn)
809 {
810     return ExprResolveMaskLookup(keymap->ctx, expr, val_rtrn, LookupVModMask,
811                                  keymap);
812 }
813
814 int
815 ExprResolveKeySym(struct xkb_context *ctx, ExprDef *expr,
816                   ExprResult *val_rtrn)
817 {
818     int ok = 0;
819     xkb_keysym_t sym;
820
821     if (expr->op == ExprIdent) {
822         const char *str;
823         str = xkb_atom_text(ctx, expr->value.str);
824         if (str) {
825             sym = xkb_keysym_from_name(str);
826             if (sym != XKB_KEY_NoSymbol) {
827                 val_rtrn->uval = sym;
828                 return true;
829             }
830         }
831     }
832     ok = ExprResolveInteger(ctx, expr, val_rtrn);
833     if ((ok) && (val_rtrn->uval < 10))
834         val_rtrn->uval += '0';
835     return ok;
836 }