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