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