2 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4 * A simple, extensible s-exp evaluation engine.
7 * Michael Zucchi <notzed@ximian.com>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of version 2 of the GNU Lesser General Public
11 * License as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
25 The following built-in s-exp's are supported:
28 perform an intersection of a number of lists, and return that.
31 perform a boolean AND of boolean values.
34 perform a union of a number of lists, returning the new list.
37 perform a boolean OR of boolean values.
49 Subtract integers from the first.
52 Subtract time_t values from the first.
54 gint = (cast-int string|int|bool)
55 Cast to an integer value.
57 string = (cast-string string|int|bool)
58 Cast to an string value.
66 bool = (< string string)
67 bool = (> string string)
68 bool = (= string string)
70 bool = (< time_t time_t)
71 bool = (> time_t time_t)
72 bool = (= time_t time_t)
73 Perform a comparision of 2 integers, 2 string values, or 2 time values.
77 type = (if bool function)
78 type = (if bool function function)
79 Choose a flow path based on a boolean value
81 type = (begin func func func)
82 Execute a sequence. The last function return is the return type.
97 #define p(x) /* parse debug */
98 #define r(x) /* run debug */
99 #define d(x) /* general debug */
101 #ifdef E_SEXP_IS_G_OBJECT
102 G_DEFINE_TYPE (ESExp, e_sexp, G_TYPE_OBJECT)
105 static struct _ESExpTerm * parse_list (ESExp *f, gint gotbrace);
106 static struct _ESExpTerm * parse_value (ESExp *f);
109 static void parse_dump_term (struct _ESExpTerm *t, gint depth);
112 #ifdef E_SEXP_IS_G_OBJECT
113 static GObjectClass *parent_class;
116 typedef gboolean (ESGeneratorFunc) (gint argc, struct _ESExpResult **argv, struct _ESExpResult *r);
117 typedef gboolean (ESOperatorFunc) (gint argc, struct _ESExpResult **argv, struct _ESExpResult *r);
119 /* FIXME: constant _TIME_MAX used in different files, move it somewhere */
120 #define _TIME_MAX ((time_t) INT_MAX) /* Max valid time_t */
122 static const GScannerConfig scanner_config =
124 ( (gchar *) " \t\r\n") /* cset_skip_characters */,
125 ( (gchar *) G_CSET_a_2_z
127 G_CSET_A_2_Z) /* cset_identifier_first */,
128 ( (gchar *) G_CSET_a_2_z
132 G_CSET_LATINC ) /* cset_identifier_nth */,
133 ( (gchar *) ";\n" ) /* cpair_comment_single */,
135 FALSE /* case_sensitive */,
137 TRUE /* skip_comment_multi */,
138 TRUE /* skip_comment_single */,
139 TRUE /* scan_comment_multi */,
140 TRUE /* scan_identifier */,
141 TRUE /* scan_identifier_1char */,
142 FALSE /* scan_identifier_NULL */,
143 TRUE /* scan_symbols */,
144 FALSE /* scan_binary */,
145 TRUE /* scan_octal */,
146 TRUE /* scan_float */,
148 FALSE /* scan_hex_dollar */,
149 TRUE /* scan_string_sq */,
150 TRUE /* scan_string_dq */,
151 TRUE /* numbers_2_int */,
152 FALSE /* int_2_float */,
153 FALSE /* identifier_2_string */,
154 TRUE /* char_2_token */,
155 FALSE /* symbol_2_token */,
156 FALSE /* scope_0_fallback */,
159 /* jumps back to the caller of f->failenv, only to be called from inside a callback */
161 e_sexp_fatal_error (struct _ESExp *f, const gchar *why, ...)
168 va_start (args, why);
169 f->error = g_strdup_vprintf (why, args);
172 longjmp (f->failenv, 1);
176 e_sexp_error (struct _ESExp *f)
181 struct _ESExpResult *
182 e_sexp_result_new (struct _ESExp *f, gint type)
184 struct _ESExpResult *r = e_memchunk_alloc0 (f->result_chunks);
186 r->occuring_start = 0;
187 r->occuring_end = _TIME_MAX;
188 r->time_generator = FALSE;
193 e_sexp_result_free (struct _ESExp *f, struct _ESExpResult *t)
199 case ESEXP_RES_ARRAY_PTR:
200 g_ptr_array_free (t->value.ptrarray, TRUE);
206 case ESEXP_RES_STRING:
207 g_free (t->value.string);
209 case ESEXP_RES_UNDEFINED:
212 g_assert_not_reached ();
214 e_memchunk_free (f->result_chunks, t);
217 /* used in normal functions if they have to abort, and free their arguments */
219 e_sexp_resultv_free (struct _ESExp *f, gint argc, struct _ESExpResult **argv)
223 for (i=0;i<argc;i++) {
224 e_sexp_result_free (f, argv[i]);
228 /* implementations for the builtin functions */
230 /* we can only itereate a hashtable from a called function */
236 /* ok, store any values that are in all sets */
238 htand (gchar *key, gint value, struct IterData *iter_data)
240 if (value == iter_data->count) {
241 g_ptr_array_add (iter_data->uids, key);
245 /* or, store all unique values */
247 htor (gchar *key, gint value, struct IterData *iter_data)
249 g_ptr_array_add (iter_data->uids, key);
253 term_eval_and (struct _ESExp *f, gint argc, struct _ESExpTerm **argv, gpointer data)
255 struct _ESExpResult *r, *r1;
256 GHashTable *ht = g_hash_table_new (g_str_hash, g_str_equal);
257 struct IterData lambdafoo;
263 r(printf("( and\n"));
265 r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
268 f->operators = g_slist_prepend (f->operators, (gpointer) oper);
270 for (i=0;bool && i<argc;i++) {
271 r1 = e_sexp_term_eval (f, argv[i]);
274 if (type != r1->type) {
275 e_sexp_result_free (f, r);
276 e_sexp_result_free (f, r1);
277 g_hash_table_destroy (ht);
278 e_sexp_fatal_error(f, "Invalid types in AND");
279 } else if (r1->type == ESEXP_RES_ARRAY_PTR) {
283 a1 = (gchar **)r1->value.ptrarray->pdata;
284 l1 = r1->value.ptrarray->len;
288 ptr = g_hash_table_lookup (ht, a1[j]);
289 n = GPOINTER_TO_INT (ptr);
290 g_hash_table_insert (ht, a1[j], GINT_TO_POINTER (n+1));
292 } else if (r1->type == ESEXP_RES_BOOL) {
293 bool = bool && r1->value.boolean;
295 e_sexp_result_free (f, r1);
298 if (type == ESEXP_RES_ARRAY_PTR) {
299 lambdafoo.count = argc;
300 lambdafoo.uids = g_ptr_array_new ();
301 g_hash_table_foreach (ht, (GHFunc)htand, &lambdafoo);
302 r->type = ESEXP_RES_ARRAY_PTR;
303 r->value.ptrarray = lambdafoo.uids;
304 } else if (type == ESEXP_RES_BOOL) {
305 r->type = ESEXP_RES_BOOL;
306 r->value.boolean = bool;
309 g_hash_table_destroy (ht);
310 f->operators = g_slist_remove (f->operators, oper);
316 term_eval_or (struct _ESExp *f, gint argc, struct _ESExpTerm **argv, gpointer data)
318 struct _ESExpResult *r, *r1;
319 GHashTable *ht = g_hash_table_new (g_str_hash, g_str_equal);
320 struct IterData lambdafoo;
329 f->operators = g_slist_prepend (f->operators, (gpointer) oper);
331 r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
333 for (i=0;!bool && i<argc;i++) {
334 r1 = e_sexp_term_eval (f, argv[i]);
337 if (r1->type != type) {
338 e_sexp_result_free (f, r);
339 e_sexp_result_free (f, r1);
340 g_hash_table_destroy (ht);
341 e_sexp_fatal_error(f, "Invalid types in OR");
342 } else if (r1->type == ESEXP_RES_ARRAY_PTR) {
346 a1 = (gchar **)r1->value.ptrarray->pdata;
347 l1 = r1->value.ptrarray->len;
349 g_hash_table_insert (ht, a1[j], (gpointer)1);
351 } else if (r1->type == ESEXP_RES_BOOL) {
352 bool |= r1->value.boolean;
354 e_sexp_result_free (f, r1);
357 if (type == ESEXP_RES_ARRAY_PTR) {
358 lambdafoo.count = argc;
359 lambdafoo.uids = g_ptr_array_new ();
360 g_hash_table_foreach (ht, (GHFunc)htor, &lambdafoo);
361 r->type = ESEXP_RES_ARRAY_PTR;
362 r->value.ptrarray = lambdafoo.uids;
363 } else if (type == ESEXP_RES_BOOL) {
364 r->type = ESEXP_RES_BOOL;
365 r->value.boolean = bool;
367 g_hash_table_destroy (ht);
369 f->operators = g_slist_remove (f->operators, oper);
374 term_eval_not (struct _ESExp *f, gint argc, struct _ESExpResult **argv, gpointer data)
380 if (argv[0]->type == ESEXP_RES_BOOL
381 && argv[0]->value.boolean)
384 r = e_sexp_result_new (f, ESEXP_RES_BOOL);
385 r->value.boolean = res;
389 /* this should support all arguments ...? */
391 term_eval_lt (struct _ESExp *f, gint argc, struct _ESExpTerm **argv, gpointer data)
393 struct _ESExpResult *r, *r1, *r2;
395 r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
398 r1 = e_sexp_term_eval (f, argv[0]);
399 r2 = e_sexp_term_eval (f, argv[1]);
400 if (r1->type != r2->type) {
401 e_sexp_result_free (f, r1);
402 e_sexp_result_free (f, r2);
403 e_sexp_result_free (f, r);
404 e_sexp_fatal_error(f, "Incompatible types in compare <");
405 } else if (r1->type == ESEXP_RES_INT) {
406 r->type = ESEXP_RES_BOOL;
407 r->value.boolean = r1->value.number < r2->value.number;
408 } else if (r1->type == ESEXP_RES_TIME) {
409 r->type = ESEXP_RES_BOOL;
410 r->value.boolean = r1->value.time < r2->value.time;
411 } else if (r1->type == ESEXP_RES_STRING) {
412 r->type = ESEXP_RES_BOOL;
413 r->value.boolean = strcmp (r1->value.string, r2->value.string) < 0;
415 e_sexp_result_free (f, r1);
416 e_sexp_result_free (f, r2);
421 /* this should support all arguments ...? */
423 term_eval_gt (struct _ESExp *f, gint argc, struct _ESExpTerm **argv, gpointer data)
425 struct _ESExpResult *r, *r1, *r2;
427 r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
430 r1 = e_sexp_term_eval (f, argv[0]);
431 r2 = e_sexp_term_eval (f, argv[1]);
432 if (r1->type != r2->type) {
433 e_sexp_result_free (f, r1);
434 e_sexp_result_free (f, r2);
435 e_sexp_result_free (f, r);
436 e_sexp_fatal_error(f, "Incompatible types in compare >");
437 } else if (r1->type == ESEXP_RES_INT) {
438 r->type = ESEXP_RES_BOOL;
439 r->value.boolean = r1->value.number > r2->value.number;
440 } else if (r1->type == ESEXP_RES_TIME) {
441 r->type = ESEXP_RES_BOOL;
442 r->value.boolean = r1->value.time > r2->value.time;
443 } else if (r1->type == ESEXP_RES_STRING) {
444 r->type = ESEXP_RES_BOOL;
445 r->value.boolean = strcmp (r1->value.string, r2->value.string) > 0;
447 e_sexp_result_free (f, r1);
448 e_sexp_result_free (f, r2);
453 /* this should support all arguments ...? */
455 term_eval_eq (struct _ESExp *f, gint argc, struct _ESExpTerm **argv, gpointer data)
457 struct _ESExpResult *r, *r1, *r2;
459 r = e_sexp_result_new (f, ESEXP_RES_BOOL);
462 r1 = e_sexp_term_eval (f, argv[0]);
463 r2 = e_sexp_term_eval (f, argv[1]);
464 if (r1->type != r2->type) {
465 r->value.boolean = FALSE;
466 } else if (r1->type == ESEXP_RES_INT) {
467 r->value.boolean = r1->value.number == r2->value.number;
468 } else if (r1->type == ESEXP_RES_BOOL) {
469 r->value.boolean = r1->value.boolean == r2->value.boolean;
470 } else if (r1->type == ESEXP_RES_TIME) {
471 r->value.boolean = r1->value.time == r2->value.time;
472 } else if (r1->type == ESEXP_RES_STRING) {
473 r->value.boolean = strcmp (r1->value.string, r2->value.string) == 0;
475 e_sexp_result_free (f, r1);
476 e_sexp_result_free (f, r2);
482 term_eval_plus (struct _ESExp *f, gint argc, struct _ESExpResult **argv, gpointer data)
484 struct _ESExpResult *r=NULL;
489 type = argv[0]->type;
491 case ESEXP_RES_INT: {
492 gint total = argv[0]->value.number;
493 for (i=1;i<argc && argv[i]->type == ESEXP_RES_INT;i++) {
494 total += argv[i]->value.number;
497 e_sexp_resultv_free (f, argc, argv);
498 e_sexp_fatal_error(f, "Invalid types in (+ ints)");
500 r = e_sexp_result_new (f, ESEXP_RES_INT);
501 r->value.number = total;
503 case ESEXP_RES_STRING: {
504 GString *s = g_string_new (argv[0]->value.string);
505 for (i=1;i<argc && argv[i]->type == ESEXP_RES_STRING;i++) {
506 g_string_append (s, argv[i]->value.string);
509 e_sexp_resultv_free (f, argc, argv);
510 e_sexp_fatal_error(f, "Invalid types in (+ strings)");
512 r = e_sexp_result_new (f, ESEXP_RES_STRING);
513 r->value.string = s->str;
514 g_string_free (s, FALSE);
516 case ESEXP_RES_TIME: {
519 total = argv[0]->value.time;
521 for (i = 1; i < argc && argv[i]->type == ESEXP_RES_TIME; i++)
522 total += argv[i]->value.time;
525 e_sexp_resultv_free (f, argc, argv);
526 e_sexp_fatal_error (f, "Invalid types in (+ time_t)");
529 r = e_sexp_result_new (f, ESEXP_RES_TIME);
530 r->value.time = total;
536 r = e_sexp_result_new (f, ESEXP_RES_INT);
543 term_eval_sub (struct _ESExp *f, gint argc, struct _ESExpResult **argv, gpointer data)
545 struct _ESExpResult *r=NULL;
550 type = argv[0]->type;
552 case ESEXP_RES_INT: {
553 gint total = argv[0]->value.number;
554 for (i=1;i<argc && argv[i]->type == ESEXP_RES_INT;i++) {
555 total -= argv[i]->value.number;
558 e_sexp_resultv_free (f, argc, argv);
559 e_sexp_fatal_error(f, "Invalid types in -");
561 r = e_sexp_result_new (f, ESEXP_RES_INT);
562 r->value.number = total;
564 case ESEXP_RES_TIME: {
567 total = argv[0]->value.time;
569 for (i = 1; i < argc && argv[i]->type == ESEXP_RES_TIME; i++)
570 total -= argv[i]->value.time;
573 e_sexp_resultv_free (f, argc, argv);
574 e_sexp_fatal_error (f, "Invalid types in (- time_t)");
577 r = e_sexp_result_new (f, ESEXP_RES_TIME);
578 r->value.time = total;
584 r = e_sexp_result_new (f, ESEXP_RES_INT);
592 term_eval_castint (struct _ESExp *f, gint argc, struct _ESExpResult **argv, gpointer data)
594 struct _ESExpResult *r;
597 e_sexp_fatal_error(f, "Incorrect argument count to (gint )");
599 r = e_sexp_result_new (f, ESEXP_RES_INT);
600 switch (argv[0]->type) {
602 r->value.number = argv[0]->value.number;
605 r->value.number = argv[0]->value.boolean != 0;
607 case ESEXP_RES_STRING:
608 r->value.number = strtoul (argv[0]->value.string, NULL, 10);
611 e_sexp_result_free (f, r);
612 e_sexp_fatal_error(f, "Invalid type in (cast-int )");
620 term_eval_caststring (struct _ESExp *f, gint argc, struct _ESExpResult **argv, gpointer data)
622 struct _ESExpResult *r;
625 e_sexp_fatal_error(f, "Incorrect argument count to (cast-string )");
627 r = e_sexp_result_new (f, ESEXP_RES_STRING);
628 switch (argv[0]->type) {
630 r->value.string = g_strdup_printf("%d", argv[0]->value.number);
633 r->value.string = g_strdup_printf("%d", argv[0]->value.boolean != 0);
635 case ESEXP_RES_STRING:
636 r->value.string = g_strdup (argv[0]->value.string);
639 e_sexp_result_free (f, r);
640 e_sexp_fatal_error(f, "Invalid type in (gint )");
646 /* implements 'if' function */
648 term_eval_if (struct _ESExp *f, gint argc, struct _ESExpTerm **argv, gpointer data)
650 struct _ESExpResult *r;
653 if (argc >=2 && argc<=3) {
654 r = e_sexp_term_eval (f, argv[0]);
655 doit = (r->type == ESEXP_RES_BOOL && r->value.boolean);
656 e_sexp_result_free (f, r);
658 return e_sexp_term_eval (f, argv[1]);
660 return e_sexp_term_eval (f, argv[2]);
663 return e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
666 /* implements 'begin' statement */
668 term_eval_begin (struct _ESExp *f, gint argc, struct _ESExpTerm **argv, gpointer data)
670 struct _ESExpResult *r=NULL;
673 for (i=0;i<argc;i++) {
675 e_sexp_result_free (f, r);
676 r = e_sexp_term_eval (f, argv[i]);
681 return e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
684 /* this must only be called from inside term evaluation callbacks! */
685 struct _ESExpResult *
686 e_sexp_term_eval (struct _ESExp *f, struct _ESExpTerm *t)
688 struct _ESExpResult *r = NULL;
690 struct _ESExpResult **argv;
692 g_return_val_if_fail (t != NULL, NULL);
694 r(printf("eval term :\n"));
695 r (parse_dump_term (t, 0));
698 case ESEXP_TERM_STRING:
699 r(printf(" (string \"%s\")\n", t->value.string));
700 r = e_sexp_result_new (f, ESEXP_RES_STRING);
701 /* erk, this shoul;dn't need to strdup this ... */
702 r->value.string = g_strdup (t->value.string);
705 r(printf(" (gint %d)\n", t->value.number));
706 r = e_sexp_result_new (f, ESEXP_RES_INT);
707 r->value.number = t->value.number;
709 case ESEXP_TERM_BOOL:
710 r(printf(" (gint %d)\n", t->value.number));
711 r = e_sexp_result_new (f, ESEXP_RES_BOOL);
712 r->value.boolean = t->value.boolean;
714 case ESEXP_TERM_TIME:
715 r(printf(" (time_t %ld)\n", t->value.time));
716 r = e_sexp_result_new (f, ESEXP_RES_TIME);
717 r->value.time = t->value.time;
719 case ESEXP_TERM_IFUNC:
720 if (t->value.func.sym && t->value.func.sym->f.ifunc)
721 r = t->value.func.sym->f.ifunc (f, t->value.func.termcount, t->value.func.terms, t->value.func.sym->data);
723 case ESEXP_TERM_FUNC:
724 /* first evaluate all arguments to result types */
725 argv = alloca (sizeof (argv[0]) * t->value.func.termcount);
726 for (i=0;i<t->value.func.termcount;i++) {
727 argv[i] = e_sexp_term_eval (f, t->value.func.terms[i]);
729 /* call the function */
730 if (t->value.func.sym->f.func)
731 r = t->value.func.sym->f.func (f, t->value.func.termcount, argv, t->value.func.sym->data);
733 e_sexp_resultv_free (f, t->value.func.termcount, argv);
736 e_sexp_fatal_error(f, "Unknown type in parse tree: %d", t->type);
740 r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
747 eval_dump_result (ESExpResult *r, gint depth)
752 printf("null result???\n");
756 for (i=0;i<depth;i++)
760 case ESEXP_RES_ARRAY_PTR:
761 printf("array pointers\n");
764 printf("int: %d\n", r->value.number);
766 case ESEXP_RES_STRING:
767 printf("string: '%s'\n", r->value.string);
770 printf("bool: %c\n", r->value.boolean?'t':'f');
773 printf("time_t: %ld\n", (glong) r->value.time);
775 case ESEXP_RES_UNDEFINED:
776 printf(" <undefined>\n");
785 parse_dump_term (struct _ESExpTerm *t, gint depth)
790 printf("null term??\n");
794 for (i=0;i<depth;i++)
798 case ESEXP_TERM_STRING:
799 printf(" \"%s\"", t->value.string);
802 printf(" %d", t->value.number);
804 case ESEXP_TERM_BOOL:
805 printf(" #%c", t->value.boolean?'t':'f');
807 case ESEXP_TERM_TIME:
808 printf(" %ld", (glong) t->value.time);
810 case ESEXP_TERM_IFUNC:
811 case ESEXP_TERM_FUNC:
812 printf(" (function %s\n", t->value.func.sym->name);
813 /*printf(" [%d] ", t->value.func.termcount);*/
814 for (i=0;i<t->value.func.termcount;i++) {
815 parse_dump_term (t->value.func.terms[i], depth+1);
817 for (i=0;i<depth;i++)
822 printf(" (variable %s )\n", t->value.var->name);
825 printf("unknown type: %d\n", t->type);
832 const gchar *time_functions[] = {
841 binary_generator (gint argc, struct _ESExpResult **argv, struct _ESExpResult *r)
843 g_return_val_if_fail (r != NULL, FALSE);
844 g_return_val_if_fail (argc == 2, FALSE);
846 if ((argv[0]->type != ESEXP_RES_TIME) || (argv[1]->type != ESEXP_RES_TIME))
849 r->occuring_start = argv[0]->value.time;
850 r->occuring_end = argv[1]->value.time;
856 unary_generator (gint argc, struct _ESExpResult **argv, struct _ESExpResult *r)
858 /* unary generator with end time */
859 g_return_val_if_fail (r != NULL, FALSE);
860 g_return_val_if_fail (argc == 1, FALSE);
862 if (argv[0]->type != ESEXP_RES_TIME)
865 r->occuring_start = 0;
866 r->occuring_end = argv[0]->value.time;
871 static const struct {
873 ESGeneratorFunc *func;
875 {"occur-in-time-range?", binary_generator},
876 {"due-in-time-range?", binary_generator},
877 {"has-alarms-in-range?", binary_generator},
878 {"completed-before?", unary_generator},
881 const gint generators_count = sizeof (generators) / sizeof (generators[0]);
884 or_operator (gint argc, struct _ESExpResult **argv, struct _ESExpResult *r)
889 norm (0) norm (0) norm (0)
890 gen (1) norm (0) norm (0)
891 norm (0) gen (1) norm (0)
892 gen (1) gen (1) gen*(1)
895 g_return_val_if_fail (r != NULL, FALSE);
896 g_return_val_if_fail (argc == 2, FALSE);
898 if ((r->time_generator = argv[0]->time_generator & argv[1]->time_generator)) {
899 r->occuring_start = MIN (argv[0]->occuring_start, argv[1]->occuring_start);
900 r->occuring_end = MAX (argv[0]->occuring_end, argv[1]->occuring_end);
907 and_operator (gint argc, struct _ESExpResult **argv, struct _ESExpResult *r)
912 norm (0) norm (0) norm (0)
913 gen (1) norm (0) gen (1)
914 norm (0) gen (1) gen (1)
915 gen (1) gen (1) gen (1)
918 g_return_val_if_fail (r != NULL, FALSE);
919 g_return_val_if_fail (argc == 2, FALSE);
921 if ((r->time_generator = argv[0]->time_generator | argv[1]->time_generator)) {
922 /* constraint interval */
923 r->occuring_start = MAX (argv[0]->occuring_start, argv[1]->occuring_start);
924 r->occuring_end = MIN (argv[0]->occuring_end, argv[1]->occuring_end);
930 static const struct {
932 ESOperatorFunc *func;
935 {"and", and_operator}
938 const gint operators_count = sizeof (operators) / sizeof (operators[0]);
940 static ESOperatorFunc*
941 get_operator_function (const gchar *fname)
945 g_return_val_if_fail (fname != NULL, NULL);
947 for (i = 0; i < sizeof (operators) / sizeof (operators[0]); i++)
948 if (strcmp (operators[i].name, fname) == 0)
949 return operators[i].func;
954 static inline gboolean
955 is_time_function (const gchar *fname)
959 g_return_val_if_fail (fname != NULL, FALSE);
961 for (i = 0; i < sizeof (time_functions) / sizeof (time_functions[0]); i++)
962 if (strcmp (time_functions[i], fname) == 0)
968 static ESGeneratorFunc*
969 get_generator_function (const gchar *fname)
973 g_return_val_if_fail (fname != NULL, NULL);
975 for (i = 0; i < sizeof (generators) / sizeof (generators[0]); i++)
976 if (strcmp (generators[i].name, fname) == 0)
977 return generators[i].func;
982 /* this must only be called from inside term evaluation callbacks! */
983 static struct _ESExpResult *
984 e_sexp_term_evaluate_occur_times (struct _ESExp *f, struct _ESExpTerm *t, time_t *start, time_t *end)
986 struct _ESExpResult *r = NULL;
988 struct _ESExpResult **argv;
991 g_return_val_if_fail (t != NULL, NULL);
992 g_return_val_if_fail (start != NULL, NULL);
993 g_return_val_if_fail (end != NULL, NULL);
996 printf("eval term :\n");
997 parse_dump_term (t, 0);
1001 case ESEXP_TERM_STRING:
1002 r(printf(" (string \"%s\")\n", t->value.string));
1003 r = e_sexp_result_new (f, ESEXP_RES_STRING);
1004 r->value.string = g_strdup (t->value.string);
1006 case ESEXP_TERM_IFUNC:
1007 case ESEXP_TERM_FUNC:
1009 ESGeneratorFunc *generator = NULL;
1010 ESOperatorFunc *operator = NULL;
1012 r(printf(" (function \"%s\"\n", t->value.func.sym->name));
1014 r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
1015 argc = t->value.func.termcount;
1016 argv = alloca (sizeof (argv[0]) * argc);
1018 for (i=0;i<t->value.func.termcount;i++) {
1019 argv[i] = e_sexp_term_evaluate_occur_times (f, t->value.func.terms[i],
1023 if (is_time_function (t->value.func.sym->name)) {
1025 if (t->value.func.sym->f.func)
1026 r = t->value.func.sym->f.func (f, t->value.func.termcount,
1027 argv, t->value.func.sym->data);
1028 } else if ((generator = get_generator_function (t->value.func.sym->name)) != NULL) {
1029 /* evaluate generator function */
1030 r->time_generator = TRUE;
1031 ok = generator (argc, argv, r);
1032 } else if ((operator = get_operator_function (t->value.func.sym->name)) != NULL)
1033 /* evaluate operator function */
1034 ok = operator (argc, argv, r);
1036 /* normal function: we need to scan all objects */
1037 r->time_generator = FALSE;
1040 e_sexp_resultv_free (f, t->value.func.termcount, argv);
1043 case ESEXP_TERM_INT:
1044 case ESEXP_TERM_BOOL:
1045 case ESEXP_TERM_TIME:
1053 e_sexp_fatal_error(f, "Error in parse tree");
1056 r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
1065 static struct _ESExpTerm *
1066 parse_term_new (struct _ESExp *f, gint type)
1068 struct _ESExpTerm *s = e_memchunk_alloc0 (f->term_chunks);
1074 parse_term_free (struct _ESExp *f, struct _ESExpTerm *t)
1083 case ESEXP_TERM_INT:
1084 case ESEXP_TERM_BOOL:
1085 case ESEXP_TERM_TIME:
1086 case ESEXP_TERM_VAR:
1089 case ESEXP_TERM_STRING:
1090 g_free (t->value.string);
1093 case ESEXP_TERM_FUNC:
1094 case ESEXP_TERM_IFUNC:
1095 for (i=0;i<t->value.func.termcount;i++) {
1096 parse_term_free (f, t->value.func.terms[i]);
1098 g_free (t->value.func.terms);
1102 printf("parse_term_free: unknown type: %d\n", t->type);
1104 e_memchunk_free (f->term_chunks, t);
1107 static struct _ESExpTerm **
1108 parse_values (ESExp *f, gint *len)
1111 struct _ESExpTerm **terms;
1113 GScanner *gs = f->scanner;
1114 GSList *list = NULL, *l;
1116 p(printf("parsing values\n"));
1118 while ( (token = g_scanner_peek_next_token (gs)) != G_TOKEN_EOF
1120 list = g_slist_prepend (list, parse_value (f));
1124 /* go over the list, and put them backwards into the term array */
1125 terms = g_malloc (size * sizeof (*terms));
1127 for (i=size-1;i>=0;i--) {
1131 l = g_slist_next (l);
1133 g_slist_free (list);
1135 p(printf("found %d subterms\n", size));
1138 p(printf("done parsing values\n"));
1143 * e_sexp_parse_value:
1148 e_sexp_parse_value (ESExp *f)
1150 return parse_value (f);
1153 static struct _ESExpTerm *
1154 parse_value (ESExp *f)
1156 gint token, negative = FALSE;
1157 struct _ESExpTerm *t = NULL;
1158 GScanner *gs = f->scanner;
1159 struct _ESExpSymbol *s;
1161 p(printf("parsing value\n"));
1163 token = g_scanner_get_next_token (gs);
1167 case G_TOKEN_LEFT_PAREN:
1168 p(printf("got brace, its a list!\n"));
1169 return parse_list (f, TRUE);
1170 case G_TOKEN_STRING:
1171 p(printf("got string '%s'\n", g_scanner_cur_value(gs).v_string));
1172 t = parse_term_new (f, ESEXP_TERM_STRING);
1173 t->value.string = g_strdup (g_scanner_cur_value (gs).v_string);
1176 p(printf ("got negative int?\n"));
1177 token = g_scanner_get_next_token (gs);
1178 if (token != G_TOKEN_INT) {
1179 e_sexp_fatal_error (f, "Invalid format for a integer value");
1184 /* fall through... */
1186 t = parse_term_new (f, ESEXP_TERM_INT);
1187 t->value.number = g_scanner_cur_value (gs).v_int;
1189 t->value.number = -t->value.number;
1190 p(printf("got gint %d\n", t->value.number));
1195 p(printf("got bool?\n"));
1196 token = g_scanner_get_next_token (gs);
1197 if (token != G_TOKEN_IDENTIFIER) {
1198 e_sexp_fatal_error (f, "Invalid format for a boolean value");
1202 str = g_scanner_cur_value (gs).v_identifier;
1204 g_assert (str != NULL);
1205 if (!(strlen (str) == 1 && (str[0] == 't' || str[0] == 'f'))) {
1206 e_sexp_fatal_error (f, "Invalid format for a boolean value");
1210 t = parse_term_new (f, ESEXP_TERM_BOOL);
1211 t->value.boolean = (str[0] == 't');
1213 case G_TOKEN_SYMBOL:
1214 s = g_scanner_cur_value (gs).v_symbol;
1215 p(printf("got symbol '%s'\n", s->name));
1217 case ESEXP_TERM_FUNC:
1218 case ESEXP_TERM_IFUNC:
1219 /* this is basically invalid, since we can't use function
1220 pointers, but let the runtime catch it ... */
1221 t = parse_term_new (f, s->type);
1222 t->value.func.sym = s;
1223 t->value.func.terms = parse_values (f, &t->value.func.termcount);
1225 case ESEXP_TERM_VAR:
1226 t = parse_term_new (f, s->type);
1230 e_sexp_fatal_error(f, "Invalid symbol type: %s: %d", s->name, s->type);
1233 case G_TOKEN_IDENTIFIER:
1234 p(printf("got unknown identifider '%s'\n", g_scanner_cur_value(gs).v_identifier));
1235 e_sexp_fatal_error(f, "Unknown identifier: %s", g_scanner_cur_value(gs).v_identifier);
1238 e_sexp_fatal_error(f, "Unexpected token encountered: %d", token);
1240 p(printf("done parsing value\n"));
1244 /* FIXME: this needs some robustification */
1245 static struct _ESExpTerm *
1246 parse_list (ESExp *f, gint gotbrace)
1249 struct _ESExpTerm *t = NULL;
1250 GScanner *gs = f->scanner;
1252 p(printf("parsing list\n"));
1256 token = g_scanner_get_next_token (gs);
1258 token = g_scanner_get_next_token (gs);
1260 case G_TOKEN_SYMBOL: {
1261 struct _ESExpSymbol *s;
1263 s = g_scanner_cur_value (gs).v_symbol;
1264 p(printf("got funciton: %s\n", s->name));
1265 t = parse_term_new (f, s->type);
1266 p(printf("created new list %p\n", t));
1267 /* if we have a variable, find out its base type */
1268 while (s->type == ESEXP_TERM_VAR) {
1269 s = ((ESExpTerm *)(s->data))->value.var;
1271 if (s->type == ESEXP_TERM_FUNC
1272 || s->type == ESEXP_TERM_IFUNC) {
1273 t->value.func.sym = s;
1274 t->value.func.terms = parse_values (f, &t->value.func.termcount);
1276 parse_term_free (f, t);
1277 e_sexp_fatal_error(f, "Trying to call variable as function: %s", s->name);
1280 case G_TOKEN_IDENTIFIER:
1281 e_sexp_fatal_error(f, "Unknown identifier: %s", g_scanner_cur_value(gs).v_identifier);
1283 case G_TOKEN_LEFT_PAREN:
1284 return parse_list (f, TRUE);
1286 e_sexp_fatal_error(f, "Unexpected token encountered: %d", token);
1288 token = g_scanner_get_next_token (gs);
1290 e_sexp_fatal_error(f, "Missing ')'");
1293 e_sexp_fatal_error(f, "Missing '('");
1296 p(printf("returning list %p\n", t));
1300 static void e_sexp_finalise (gpointer);
1302 #ifdef E_SEXP_IS_G_OBJECT
1304 e_sexp_class_init (ESExpClass *klass)
1306 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1308 object_class->finalize = e_sexp_finalise;
1310 parent_class = g_type_class_ref (g_object_get_type ());
1314 /* 'builtin' functions */
1315 static const struct {
1318 gint type; /* set to 1 if a function can perform shortcut evaluation, or
1319 doesn't execute everything, 0 otherwise */
1321 { "and", (ESExpFunc *)term_eval_and, 1 },
1322 { "or", (ESExpFunc *)term_eval_or, 1 },
1323 { "not", (ESExpFunc *)term_eval_not, 0 },
1324 { "<", (ESExpFunc *)term_eval_lt, 1 },
1325 { ">", (ESExpFunc *)term_eval_gt, 1 },
1326 { "=", (ESExpFunc *)term_eval_eq, 1 },
1327 { "+", (ESExpFunc *)term_eval_plus, 0 },
1328 { "-", (ESExpFunc *)term_eval_sub, 0 },
1329 { "cast-int", (ESExpFunc *)term_eval_castint, 0 },
1330 { "cast-string", (ESExpFunc *)term_eval_caststring, 0 },
1331 { "if", (ESExpFunc *)term_eval_if, 1 },
1332 { "begin", (ESExpFunc *)term_eval_begin, 1 },
1336 free_symbol (gpointer key, gpointer value, gpointer data)
1338 struct _ESExpSymbol *s = value;
1345 e_sexp_finalise (gpointer o)
1347 ESExp *s = (ESExp *)o;
1350 parse_term_free (s, s->tree);
1354 e_memchunk_destroy (s->term_chunks);
1355 e_memchunk_destroy (s->result_chunks);
1357 g_scanner_scope_foreach_symbol (s->scanner, 0, free_symbol, NULL);
1358 g_scanner_destroy (s->scanner);
1360 #ifdef E_SEXP_IS_G_OBJECT
1361 G_OBJECT_CLASS (parent_class)->finalize (o);
1366 e_sexp_init (ESExp *s)
1370 s->scanner = g_scanner_new (&scanner_config);
1371 s->term_chunks = e_memchunk_new (16, sizeof (struct _ESExpTerm));
1372 s->result_chunks = e_memchunk_new (16, sizeof (struct _ESExpResult));
1374 /* load in builtin symbols? */
1375 for (i = 0; i < G_N_ELEMENTS (symbols); i++) {
1376 if (symbols[i].type == 1) {
1377 e_sexp_add_ifunction (s, 0, symbols[i].name, (ESExpIFunc *)symbols[i].func, (gpointer)&symbols[i]);
1379 e_sexp_add_function (s, 0, symbols[i].name, symbols[i].func, (gpointer)&symbols[i]);
1383 #ifndef E_SEXP_IS_G_OBJECT
1391 #ifdef E_SEXP_IS_G_OBJECT
1392 ESExp *f = (ESexp *) g_object_new (E_TYPE_SEXP, NULL);
1394 ESExp *f = g_malloc0 (sizeof (ESExp));
1401 #ifndef E_SEXP_IS_G_OBJECT
1403 e_sexp_ref (ESExp *f)
1409 e_sexp_unref (ESExp *f)
1412 if (f->refcount == 0) {
1413 e_sexp_finalise (f);
1420 e_sexp_add_function (ESExp *f, gint scope, const gchar *name, ESExpFunc *func, gpointer data)
1422 struct _ESExpSymbol *s;
1424 g_return_if_fail (IS_E_SEXP (f));
1425 g_return_if_fail (name != NULL);
1427 e_sexp_remove_symbol (f, scope, name);
1429 s = g_malloc0 (sizeof (*s));
1430 s->name = g_strdup (name);
1432 s->type = ESEXP_TERM_FUNC;
1434 g_scanner_scope_add_symbol (f->scanner, scope, s->name, s);
1438 e_sexp_add_ifunction (ESExp *f, gint scope, const gchar *name, ESExpIFunc *ifunc, gpointer data)
1440 struct _ESExpSymbol *s;
1442 g_return_if_fail (IS_E_SEXP (f));
1443 g_return_if_fail (name != NULL);
1445 e_sexp_remove_symbol (f, scope, name);
1447 s = g_malloc0 (sizeof (*s));
1448 s->name = g_strdup (name);
1450 s->type = ESEXP_TERM_IFUNC;
1452 g_scanner_scope_add_symbol (f->scanner, scope, s->name, s);
1456 e_sexp_add_variable (ESExp *f, gint scope, gchar *name, ESExpTerm *value)
1458 struct _ESExpSymbol *s;
1460 g_return_if_fail (IS_E_SEXP (f));
1461 g_return_if_fail (name != NULL);
1463 s = g_malloc0 (sizeof (*s));
1464 s->name = g_strdup (name);
1465 s->type = ESEXP_TERM_VAR;
1467 g_scanner_scope_add_symbol (f->scanner, scope, s->name, s);
1471 e_sexp_remove_symbol (ESExp *f, gint scope, const gchar *name)
1474 struct _ESExpSymbol *s;
1476 g_return_if_fail (IS_E_SEXP (f));
1477 g_return_if_fail (name != NULL);
1479 oldscope = g_scanner_set_scope (f->scanner, scope);
1480 s = g_scanner_lookup_symbol (f->scanner, name);
1481 g_scanner_scope_remove_symbol (f->scanner, scope, name);
1482 g_scanner_set_scope (f->scanner, oldscope);
1490 e_sexp_set_scope (ESExp *f, gint scope)
1492 g_return_val_if_fail (IS_E_SEXP (f), 0);
1494 return g_scanner_set_scope (f->scanner, scope);
1498 e_sexp_input_text (ESExp *f, const gchar *text, gint len)
1500 g_return_if_fail (IS_E_SEXP (f));
1501 g_return_if_fail (text != NULL);
1503 g_scanner_input_text (f->scanner, text, len);
1507 e_sexp_input_file (ESExp *f, gint fd)
1509 g_return_if_fail (IS_E_SEXP (f));
1511 g_scanner_input_file (f->scanner, fd);
1514 /* returns -1 on error */
1516 e_sexp_parse (ESExp *f)
1518 g_return_val_if_fail (IS_E_SEXP (f), -1);
1520 if (setjmp (f->failenv)) {
1521 g_warning("Error in parsing: %s", f->error);
1526 parse_term_free (f, f->tree);
1528 f->tree = parse_value (f);
1533 /* returns NULL on error */
1534 struct _ESExpResult *
1535 e_sexp_eval (ESExp *f)
1537 g_return_val_if_fail (IS_E_SEXP (f), NULL);
1538 g_return_val_if_fail (f->tree != NULL, NULL);
1540 if (setjmp (f->failenv)) {
1541 g_warning("Error in execution: %s", f->error);
1545 return e_sexp_term_eval (f, f->tree);
1549 * e_cal_backend_sexp_evaluate_occur_times:
1550 * @f: An #ESExp object.
1551 * @start: Start of the time window will be stored here.
1552 * @end: End of the time window will be stored here.
1554 * Determines biggest time window given by expressions "occur-in-range" in sexp.
1559 e_sexp_evaluate_occur_times (ESExp *f, time_t *start, time_t *end)
1561 struct _ESExpResult *r;
1563 g_return_val_if_fail (IS_E_SEXP (f), FALSE);
1564 g_return_val_if_fail (f->tree != NULL, FALSE);
1565 g_return_val_if_fail (start != NULL, FALSE);
1566 g_return_val_if_fail (end != NULL, FALSE);
1570 if (setjmp (f->failenv)) {
1571 g_warning("Error in execution: %s", f->error);
1575 r = e_sexp_term_evaluate_occur_times (f, f->tree, start, end);
1576 generator = r->time_generator;
1579 *start = r->occuring_start;
1580 *end = r->occuring_end;
1583 e_sexp_result_free (f, r);
1589 * e_sexp_encode_bool:
1593 * Encode a bool into an s-expression @s. Bools are
1594 * encoded using #t #f syntax.
1597 e_sexp_encode_bool (GString *s, gboolean state)
1600 g_string_append(s, " #t");
1602 g_string_append(s, " #f");
1606 * e_sexp_encode_string:
1607 * @s: Destination string.
1608 * @string: String expression.
1610 * Add a c string @string to the s-expression stored in
1611 * the gstring @s. Quotes are added, and special characters
1612 * are escaped appropriately.
1615 e_sexp_encode_string (GString *s, const gchar *string)
1624 g_string_append(s, " \"");
1625 while ((c = *p++)) {
1626 if (c=='\\' || c=='\"' || c=='\'')
1627 g_string_append_c (s, '\\');
1628 g_string_append_c (s, c);
1630 g_string_append(s, "\"");
1634 gint main (gint argc, gchar **argv)
1637 gchar *t = "(+ \"foo\" \"\\\"\" \"bar\" \"\\\\ blah \\x \")";
1644 e_sexp_add_variable(f, 0, "test", NULL);
1646 if (argc < 2 || !argv[1])
1649 e_sexp_input_text (f, t, t);
1653 parse_dump_term (f->tree, 0);
1656 r = e_sexp_eval (f);
1658 eval_dump_result (r, 0);
1660 printf("no result?|\n");