source: trunk/third/evolution/e-util/e-sexp.c @ 18142

Revision 18142, 30.8 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18141, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright 2000 Ximian (www.ximian.com).
3 *
4 * A simple, extensible s-exp evaluation engine.
5 *
6 * Author :
7 *  Michael Zucchi <notzed@ximian.com>
8
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of version 2 of the GNU General Public
11 * License as published by the Free Software Foundation.
12 *
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 General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 */
23
24/*
25  The following built-in s-exp's are supported:
26
27  list = (and list*)
28        perform an intersection of a number of lists, and return that.
29
30  bool = (and bool*)
31        perform a boolean AND of boolean values.
32
33  list = (or list*)
34        perform a union of a number of lists, returning the new list.
35
36  bool = (or bool*)
37        perform a boolean OR of boolean values.
38
39  int = (+ int*)
40        Add integers.
41
42  string = (+ string*)
43        Concat strings.
44
45  time_t = (+ time_t*)
46        Add time_t values.
47
48  int = (- int int*)
49        Subtract integers from the first.
50
51  time_t = (- time_t*)
52        Subtract time_t values from the first.
53
54  int = (cast-int string|int|bool)
55        Cast to an integer value.
56
57  string = (cast-string string|int|bool)
58        Cast to an string value.
59
60  Comparison operators:
61
62  bool = (< int int)
63  bool = (> int int)
64  bool = (= int int)
65
66  bool = (< string string)
67  bool = (> string string)
68  bool = (= string string)
69
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.
74
75  Function flow:
76
77  type = (if bool function)
78  type = (if bool function function)
79        Choose a flow path based on a boolean value
80
81  type = (begin  func func func)
82        Execute a sequence.  The last function return is the return type.
83*/
84
85#include "e-sexp.h"
86
87#include <stdio.h>
88#include <stdlib.h>
89#include <time.h>
90#include <string.h>
91
92#include <glib.h>
93#include "e-memory.h"
94#define p(x)                    /* parse debug */
95#define r(x)                    /* run debug */
96#define d(x)                    /* general debug */
97
98
99static struct _ESExpTerm * parse_list(ESExp *f, int gotbrace);
100static struct _ESExpTerm * parse_value(ESExp *f);
101
102static void parse_dump_term(struct _ESExpTerm *t, int depth);
103
104#ifdef E_SEXP_IS_GTK_OBJECT
105static GtkObjectClass *parent_class;
106#endif
107
108static GScannerConfig scanner_config =
109{
110        ( " \t\r\n")            /* cset_skip_characters */,
111        ( G_CSET_a_2_z
112          "_+-<=>?"
113          G_CSET_A_2_Z)         /* cset_identifier_first */,
114        ( G_CSET_a_2_z
115          "_0123456789-<>?"
116          G_CSET_A_2_Z
117          G_CSET_LATINS
118          G_CSET_LATINC )       /* cset_identifier_nth */,
119        ( ";\n" )               /* cpair_comment_single */,
120 
121        FALSE                   /* case_sensitive */,
122 
123        TRUE                    /* skip_comment_multi */,
124        TRUE                    /* skip_comment_single */,
125        TRUE                    /* scan_comment_multi */,
126        TRUE                    /* scan_identifier */,
127        TRUE                    /* scan_identifier_1char */,
128        FALSE                   /* scan_identifier_NULL */,
129        TRUE                    /* scan_symbols */,
130        FALSE                   /* scan_binary */,
131        TRUE                    /* scan_octal */,
132        TRUE                    /* scan_float */,
133        TRUE                    /* scan_hex */,
134        FALSE                   /* scan_hex_dollar */,
135        TRUE                    /* scan_string_sq */,
136        TRUE                    /* scan_string_dq */,
137        TRUE                    /* numbers_2_int */,
138        FALSE                   /* int_2_float */,
139        FALSE                   /* identifier_2_string */,
140        TRUE                    /* char_2_token */,
141        FALSE                   /* symbol_2_token */,
142        FALSE                   /* scope_0_fallback */,
143};
144
145/* jumps back to the caller of f->failenv, only to be called from inside a callback */
146void
147e_sexp_fatal_error(struct _ESExp *f, char *why, ...)
148{
149        va_list args;
150
151        if (f->error)
152                g_free(f->error);
153       
154        va_start(args, why);
155        f->error = g_strdup_vprintf(why, args);
156        va_end(args);
157
158        longjmp(f->failenv, 1);
159}
160
161const char *
162e_sexp_error(struct _ESExp *f)
163{
164        return f->error;
165}
166
167struct _ESExpResult *
168e_sexp_result_new(struct _ESExp *f, int type)
169{
170        struct _ESExpResult *r = e_memchunk_alloc0(f->result_chunks);
171        r->type = type;
172        return r;
173}
174
175void
176e_sexp_result_free(struct _ESExp *f, struct _ESExpResult *t)
177{
178        if (t == NULL)
179                return;
180
181        switch(t->type) {
182        case ESEXP_RES_ARRAY_PTR:
183                g_ptr_array_free(t->value.ptrarray, TRUE);
184                break;
185        case ESEXP_RES_BOOL:
186        case ESEXP_RES_INT:
187        case ESEXP_RES_TIME:
188                break;
189        case ESEXP_RES_STRING:
190                g_free(t->value.string);
191                break;
192        case ESEXP_RES_UNDEFINED:
193                break;
194        default:
195                g_assert_not_reached();
196        }
197        e_memchunk_free(f->result_chunks, t);
198}
199
200/* used in normal functions if they have to abort, and free their arguments */
201void
202e_sexp_resultv_free(struct _ESExp *f, int argc, struct _ESExpResult **argv)
203{
204        int i;
205
206        for (i=0;i<argc;i++) {
207                e_sexp_result_free(f, argv[i]);
208        }
209}
210
211/* implementations for the builtin functions */
212
213/* can you tell, i dont like glib? */
214/* we can only itereate a hashtable from a called function */
215struct _glib_sux_donkeys {
216        int count;
217        GPtrArray *uids;
218};
219
220/* ok, store any values that are in all sets */
221static void
222g_lib_sux_htand(char *key, int value, struct _glib_sux_donkeys *fuckup)
223{
224        if (value == fuckup->count) {
225                g_ptr_array_add(fuckup->uids, key);
226        }
227}
228
229/* or, store all unique values */
230static void
231g_lib_sux_htor(char *key, int value, struct _glib_sux_donkeys *fuckup)
232{
233        g_ptr_array_add(fuckup->uids, key);
234}
235
236static ESExpResult *
237term_eval_and(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
238{
239        struct _ESExpResult *r, *r1;
240        GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
241        struct _glib_sux_donkeys lambdafoo;
242        int type=-1;
243        int bool = TRUE;
244        int i;
245       
246        r(printf("( and\n"));
247
248        r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
249       
250        for (i=0;bool && i<argc;i++) {
251                r1 = e_sexp_term_eval(f, argv[i]);
252                if (type == -1)
253                        type = r1->type;
254                if (type != r1->type) {
255                        e_sexp_result_free(f, r);
256                        e_sexp_result_free(f, r1);
257                        g_hash_table_destroy(ht);
258                        e_sexp_fatal_error(f, "Invalid types in AND");
259                } else if (r1->type == ESEXP_RES_ARRAY_PTR) {
260                        char **a1;
261                        int l1, j;
262                       
263                        a1 = (char **)r1->value.ptrarray->pdata;
264                        l1 = r1->value.ptrarray->len;
265                        for (j=0;j<l1;j++) {
266                                int n;
267                                n = (int)g_hash_table_lookup(ht, a1[j]);
268                                g_hash_table_insert(ht, a1[j], (void *)n+1);
269                        }
270                } else if (r1->type == ESEXP_RES_BOOL) {
271                        bool = bool && r1->value.bool;
272                }
273                e_sexp_result_free(f, r1);
274        }
275       
276        if (type == ESEXP_RES_ARRAY_PTR) {
277                lambdafoo.count = argc;
278                lambdafoo.uids = g_ptr_array_new();
279                g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htand, &lambdafoo);
280                r->type = ESEXP_RES_ARRAY_PTR;
281                r->value.ptrarray = lambdafoo.uids;
282        } else if (type == ESEXP_RES_BOOL) {
283                r->type = ESEXP_RES_BOOL;
284                r->value.bool = bool;
285        }
286       
287        g_hash_table_destroy(ht);
288       
289        return r;
290}
291
292static ESExpResult *
293term_eval_or(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
294{
295        struct _ESExpResult *r, *r1;
296        GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
297        struct _glib_sux_donkeys lambdafoo;
298        int type = -1;
299        int bool = FALSE;
300        int i;
301       
302        r(printf("(or \n"));
303
304        r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
305       
306        for (i=0;!bool && i<argc;i++) {
307                r1 = e_sexp_term_eval(f, argv[i]);
308                if (type == -1)
309                        type = r1->type;
310                if (r1->type != type) {
311                        e_sexp_result_free(f, r);
312                        e_sexp_result_free(f, r1);
313                        g_hash_table_destroy(ht);
314                        e_sexp_fatal_error(f, "Invalid types in OR");
315                } else if (r1->type == ESEXP_RES_ARRAY_PTR) {
316                        char **a1;
317                        int l1, j;
318                       
319                        a1 = (char **)r1->value.ptrarray->pdata;
320                        l1 = r1->value.ptrarray->len;
321                        for (j=0;j<l1;j++) {
322                                g_hash_table_insert(ht, a1[j], (void *)1);
323                        }
324                } else if (r1->type == ESEXP_RES_BOOL) {
325                        bool |= r1->value.bool;                         
326                }
327                e_sexp_result_free(f, r1);
328        }
329       
330        if (type == ESEXP_RES_ARRAY_PTR) {
331                lambdafoo.count = argc;
332                lambdafoo.uids = g_ptr_array_new();
333                g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htor, &lambdafoo);
334                r->type = ESEXP_RES_ARRAY_PTR;
335                r->value.ptrarray = lambdafoo.uids;
336        } else if (type == ESEXP_RES_BOOL) {
337                r->type = ESEXP_RES_BOOL;
338                r->value.bool = bool;
339        }
340        g_hash_table_destroy(ht);
341       
342        return r;
343}
344
345static ESExpResult *
346term_eval_not(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
347{
348        int res = TRUE;
349        ESExpResult *r;
350
351        if (argc>0) {
352                if (argv[0]->type == ESEXP_RES_BOOL
353                    && argv[0]->value.bool)
354                        res = FALSE;
355        }
356        r = e_sexp_result_new(f, ESEXP_RES_BOOL);
357        r->value.bool = res;
358        return r;
359}
360
361/* this should support all arguments ...? */
362static ESExpResult *
363term_eval_lt(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
364{
365        struct _ESExpResult *r, *r1, *r2;
366
367        r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
368       
369        if (argc == 2) {
370                r1 = e_sexp_term_eval(f, argv[0]);
371                r2 = e_sexp_term_eval(f, argv[1]);
372                if (r1->type != r2->type) {
373                        e_sexp_result_free(f, r1);
374                        e_sexp_result_free(f, r2);
375                        e_sexp_result_free(f, r);
376                        e_sexp_fatal_error(f, "Incompatible types in compare <");
377                } else if (r1->type == ESEXP_RES_INT) {
378                        r->type = ESEXP_RES_BOOL;
379                        r->value.bool = r1->value.number < r2->value.number;
380                } else if (r1->type == ESEXP_RES_TIME) {
381                        r->type = ESEXP_RES_BOOL;
382                        r->value.bool = r1->value.time < r2->value.time;
383                } else if (r1->type == ESEXP_RES_STRING) {
384                        r->type = ESEXP_RES_BOOL;
385                        r->value.bool = strcmp(r1->value.string, r2->value.string) < 0;
386                }
387                e_sexp_result_free(f, r1);
388                e_sexp_result_free(f, r2);
389        }
390        return r;
391}
392
393/* this should support all arguments ...? */
394static ESExpResult *
395term_eval_gt(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
396{
397        struct _ESExpResult *r, *r1, *r2;
398
399        r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
400       
401        if (argc == 2) {
402                r1 = e_sexp_term_eval(f, argv[0]);
403                r2 = e_sexp_term_eval(f, argv[1]);
404                if (r1->type != r2->type) {
405                        e_sexp_result_free(f, r1);
406                        e_sexp_result_free(f, r2);
407                        e_sexp_result_free(f, r);
408                        e_sexp_fatal_error(f, "Incompatible types in compare >");
409                } else if (r1->type == ESEXP_RES_INT) {
410                        r->type = ESEXP_RES_BOOL;
411                        r->value.bool = r1->value.number > r2->value.number;
412                } else if (r1->type == ESEXP_RES_TIME) {
413                        r->type = ESEXP_RES_BOOL;
414                        r->value.bool = r1->value.time > r2->value.time;
415                } else if (r1->type == ESEXP_RES_STRING) {
416                        r->type = ESEXP_RES_BOOL;
417                        r->value.bool = strcmp(r1->value.string, r2->value.string) > 0;
418                }
419                e_sexp_result_free(f, r1);
420                e_sexp_result_free(f, r2);
421        }
422        return r;
423}
424
425/* this should support all arguments ...? */
426static ESExpResult *
427term_eval_eq(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
428{
429        struct _ESExpResult *r, *r1, *r2;
430
431        r = e_sexp_result_new(f, ESEXP_RES_BOOL);
432       
433        if (argc == 2) {
434                r1 = e_sexp_term_eval(f, argv[0]);
435                r2 = e_sexp_term_eval(f, argv[1]);
436                if (r1->type != r2->type) {
437                        r->value.bool = FALSE;
438                } else if (r1->type == ESEXP_RES_INT) {
439                        r->value.bool = r1->value.number == r2->value.number;
440                } else if (r1->type == ESEXP_RES_BOOL) {
441                        r->value.bool = r1->value.bool == r2->value.bool;
442                } else if (r1->type == ESEXP_RES_TIME) {
443                        r->value.bool = r1->value.time == r2->value.time;
444                } else if (r1->type == ESEXP_RES_STRING) {
445                        r->value.bool = strcmp(r1->value.string, r2->value.string) == 0;
446                }
447                e_sexp_result_free(f, r1);
448                e_sexp_result_free(f, r2);
449        }
450        return r;
451}
452
453static ESExpResult *
454term_eval_plus(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
455{
456        struct _ESExpResult *r=NULL;
457        int type;
458        int i;
459
460        if (argc>0) {
461                type = argv[0]->type;
462                switch(type) {
463                case ESEXP_RES_INT: {
464                        int total = argv[0]->value.number;
465                        for (i=1;i<argc && argv[i]->type == ESEXP_RES_INT;i++) {
466                                total += argv[i]->value.number;
467                        }
468                        if (i<argc) {
469                                e_sexp_resultv_free(f, argc, argv);
470                                e_sexp_fatal_error(f, "Invalid types in (+ ints)");
471                        }
472                        r = e_sexp_result_new(f, ESEXP_RES_INT);
473                        r->value.number = total;
474                        break; }
475                case ESEXP_RES_STRING: {
476                        GString *s = g_string_new(argv[0]->value.string);
477                        for (i=1;i<argc && argv[i]->type == ESEXP_RES_STRING;i++) {
478                                g_string_append(s, argv[i]->value.string);
479                        }
480                        if (i<argc) {
481                                e_sexp_resultv_free(f, argc, argv);
482                                e_sexp_fatal_error(f, "Invalid types in (+ strings)");
483                        }
484                        r = e_sexp_result_new(f, ESEXP_RES_STRING);
485                        r->value.string = s->str;
486                        g_string_free(s, FALSE);
487                        break; }
488                case ESEXP_RES_TIME: {
489                        time_t total;
490
491                        total = argv[0]->value.time;
492
493                        for (i = 1; i < argc && argv[i]->type == ESEXP_RES_TIME; i++)
494                                total += argv[i]->value.time;
495
496                        if (i < argc) {
497                                e_sexp_resultv_free (f, argc, argv);
498                                e_sexp_fatal_error (f, "Invalid types in (+ time_t)");
499                        }
500
501                        r = e_sexp_result_new (f, ESEXP_RES_TIME);
502                        r->value.time = total;
503                        break; }
504                }
505        }
506
507        if (!r) {
508                r = e_sexp_result_new(f, ESEXP_RES_INT);
509                r->value.number = 0;
510        }
511        return r;
512}
513
514static ESExpResult *
515term_eval_sub(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
516{
517        struct _ESExpResult *r=NULL;
518        int type;
519        int i;
520
521        if (argc>0) {
522                type = argv[0]->type;
523                switch(type) {
524                case ESEXP_RES_INT: {
525                        int total = argv[0]->value.number;
526                        for (i=1;i<argc && argv[i]->type == ESEXP_RES_INT;i++) {
527                                total -= argv[i]->value.number;
528                        }
529                        if (i<argc) {
530                                e_sexp_resultv_free(f, argc, argv);
531                                e_sexp_fatal_error(f, "Invalid types in -");
532                        }
533                        r = e_sexp_result_new(f, ESEXP_RES_INT);
534                        r->value.number = total;
535                        break; }
536                case ESEXP_RES_TIME: {
537                        time_t total;
538
539                        total = argv[0]->value.time;
540
541                        for (i = 1; i < argc && argv[i]->type == ESEXP_RES_TIME; i++)
542                                total -= argv[i]->value.time;
543
544                        if (i < argc) {
545                                e_sexp_resultv_free (f, argc, argv);
546                                e_sexp_fatal_error (f, "Invalid types in (- time_t)");
547                        }
548
549                        r = e_sexp_result_new (f, ESEXP_RES_TIME);
550                        r->value.time = total;
551                        break; }
552                }
553        }
554
555        if (!r) {
556                r = e_sexp_result_new(f, ESEXP_RES_INT);
557                r->value.number = 0;
558        }
559        return r;
560}
561
562/* cast to int */
563static ESExpResult *
564term_eval_castint(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
565{
566        struct _ESExpResult *r;
567
568        if (argc != 1)
569                e_sexp_fatal_error(f, "Incorrect argument count to (int )");
570
571        r = e_sexp_result_new(f, ESEXP_RES_INT);
572        switch (argv[0]->type) {
573        case ESEXP_RES_INT:
574                r->value.number = argv[0]->value.number;
575                break;
576        case ESEXP_RES_BOOL:
577                r->value.number = argv[0]->value.bool != 0;
578                break;
579        case ESEXP_RES_STRING:
580                r->value.number = strtoul(argv[0]->value.string, 0, 10);
581                break;
582        default:
583                e_sexp_result_free(f, r);
584                e_sexp_fatal_error(f, "Invalid type in (cast-int )");
585        }
586
587        return r;
588}
589
590/* cast to string */
591static ESExpResult *
592term_eval_caststring(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
593{
594        struct _ESExpResult *r;
595
596        if (argc != 1)
597                e_sexp_fatal_error(f, "Incorrect argument count to (cast-string )");
598
599        r = e_sexp_result_new(f, ESEXP_RES_STRING);
600        switch (argv[0]->type) {
601        case ESEXP_RES_INT:
602                r->value.string = g_strdup_printf("%d", argv[0]->value.number);
603                break;
604        case ESEXP_RES_BOOL:
605                r->value.string = g_strdup_printf("%d", argv[0]->value.bool != 0);
606                break;
607        case ESEXP_RES_STRING:
608                r->value.string = g_strdup(argv[0]->value.string);
609                break;
610        default:
611                e_sexp_result_free(f, r);
612                e_sexp_fatal_error(f, "Invalid type in (int )");
613        }
614
615        return r;
616}
617
618/* implements 'if' function */
619static ESExpResult *
620term_eval_if(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
621{
622        struct _ESExpResult *r;
623        int doit;
624
625        if (argc >=2 && argc<=3) {
626                r = e_sexp_term_eval(f, argv[0]);
627                doit = (r->type == ESEXP_RES_BOOL && r->value.bool);
628                e_sexp_result_free(f, r);
629                if (doit) {
630                        return e_sexp_term_eval(f, argv[1]);
631                } else if (argc>2) {
632                        return e_sexp_term_eval(f, argv[2]);
633                }
634        }
635        return e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
636}
637
638/* implements 'begin' statement */
639static ESExpResult *
640term_eval_begin(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
641{
642        struct _ESExpResult *r=NULL;
643        int i;
644
645        for (i=0;i<argc;i++) {
646                if (r)
647                        e_sexp_result_free(f, r);
648                r = e_sexp_term_eval(f, argv[i]);
649        }
650        if (r)
651                return r;
652        else
653                return e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
654}
655
656
657/* this must only be called from inside term evaluation callbacks! */
658struct _ESExpResult *
659e_sexp_term_eval(struct _ESExp *f, struct _ESExpTerm *t)
660{
661        struct _ESExpResult *r = NULL;
662        int i;
663        struct _ESExpResult **argv;
664
665        g_return_val_if_fail(t != NULL, NULL);
666
667        r(printf("eval term :\n"));
668        r(parse_dump_term(t, 0));
669
670        switch (t->type) {
671        case ESEXP_TERM_STRING:
672                r(printf(" (string \"%s\")\n", t->value.string));
673                r = e_sexp_result_new(f, ESEXP_RES_STRING);
674                /* erk, this shoul;dn't need to strdup this ... */
675                r->value.string = g_strdup(t->value.string);
676                break;
677        case ESEXP_TERM_INT:
678                r(printf(" (int %d)\n", t->value.number));
679                r = e_sexp_result_new(f, ESEXP_RES_INT);
680                r->value.number = t->value.number;
681                break;
682        case ESEXP_TERM_BOOL:
683                r(printf(" (int %d)\n", t->value.number));
684                r = e_sexp_result_new(f, ESEXP_RES_BOOL);
685                r->value.bool = t->value.bool;
686                break;
687        case ESEXP_TERM_TIME:
688                r(printf(" (time_t %d)\n", t->value.time));
689                r = e_sexp_result_new (f, ESEXP_RES_TIME);
690                r->value.time = t->value.time;
691                break;
692        case ESEXP_TERM_IFUNC:
693                if (t->value.func.sym->f.ifunc)
694                        r = t->value.func.sym->f.ifunc(f, t->value.func.termcount, t->value.func.terms, t->value.func.sym->data);
695                break;
696        case ESEXP_TERM_FUNC:
697                /* first evaluate all arguments to result types */
698                argv = alloca(sizeof(argv[0]) * t->value.func.termcount);
699                for (i=0;i<t->value.func.termcount;i++) {
700                        argv[i] = e_sexp_term_eval(f, t->value.func.terms[i]);
701                }
702                /* call the function */
703                if (t->value.func.sym->f.func)
704                        r = t->value.func.sym->f.func(f, t->value.func.termcount, argv, t->value.func.sym->data);
705
706                e_sexp_resultv_free(f, t->value.func.termcount, argv);
707                break;
708        default:
709                e_sexp_fatal_error(f, "Unknown type in parse tree: %d", t->type);
710        }
711
712        if (r==NULL)
713                r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
714
715        return r;
716}
717
718#ifdef TESTER
719static void
720eval_dump_result(ESExpResult *r, int depth)
721{
722        int i;
723       
724        if (r==NULL) {
725                printf("null result???\n");
726                return;
727        }
728
729        for (i=0;i<depth;i++)
730                printf("   ");
731
732        switch (r->type) {
733        case ESEXP_RES_ARRAY_PTR:
734                printf("array pointers\n");
735                break;
736        case ESEXP_RES_INT:
737                printf("int: %d\n", r->value.number);
738                break;
739        case ESEXP_RES_STRING:
740                printf("string: '%s'\n", r->value.string);
741                break;
742        case ESEXP_RES_BOOL:
743                printf("bool: %c\n", r->value.bool?'t':'f');
744                break;
745        case ESEXP_RES_TIME:
746                printf("time_t: %ld\n", (long) r->value.time);
747                break;
748        case ESEXP_RES_UNDEFINED:
749                printf(" <undefined>\n");
750                break;
751        }
752        printf("\n");
753}
754#endif
755
756static void
757parse_dump_term(struct _ESExpTerm *t, int depth)
758{
759        int i;
760
761        if (t==NULL) {
762                printf("null term??\n");
763                return;
764        }
765
766        for (i=0;i<depth;i++)
767                printf("   ");
768       
769        switch (t->type) {
770        case ESEXP_TERM_STRING:
771                printf(" \"%s\"", t->value.string);
772                break;
773        case ESEXP_TERM_INT:
774                printf(" %d", t->value.number);
775                break;
776        case ESEXP_TERM_BOOL:
777                printf(" #%c", t->value.bool?'t':'f');
778                break;
779        case ESEXP_TERM_TIME:
780                printf(" %ld", (long) t->value.time);
781                break;
782        case ESEXP_TERM_IFUNC:
783        case ESEXP_TERM_FUNC:
784                printf(" (function %s\n", t->value.func.sym->name);
785                /*printf(" [%d] ", t->value.func.termcount);*/
786                for (i=0;i<t->value.func.termcount;i++) {
787                        parse_dump_term(t->value.func.terms[i], depth+1);
788                }
789                for (i=0;i<depth;i++)
790                        printf("   ");
791                printf(" )");
792                break;
793        case ESEXP_TERM_VAR:
794                printf(" (variable %s )\n", t->value.var->name);
795                break;
796        default:
797                printf("unknown type: %d\n", t->type);
798        }
799
800        printf("\n");
801}
802
803/*
804  PARSER
805*/
806
807static struct _ESExpTerm *
808parse_term_new(struct _ESExp *f, int type)
809{
810        struct _ESExpTerm *s = e_memchunk_alloc0(f->term_chunks);
811        s->type = type;
812        return s;
813}
814
815static void
816parse_term_free(struct _ESExp *f, struct _ESExpTerm *t)
817{
818        int i;
819
820        if (t==NULL) {
821                return;
822        }
823       
824        switch (t->type) {
825        case ESEXP_TERM_INT:
826        case ESEXP_TERM_BOOL:
827        case ESEXP_TERM_TIME:
828        case ESEXP_TERM_VAR:
829                break;
830
831        case ESEXP_TERM_STRING:
832                g_free(t->value.string);
833                break;
834
835        case ESEXP_TERM_FUNC:
836        case ESEXP_TERM_IFUNC:
837                for (i=0;i<t->value.func.termcount;i++) {
838                        parse_term_free(f, t->value.func.terms[i]);
839                }
840                g_free(t->value.func.terms);
841                break;
842
843        default:
844                printf("parse_term_free: unknown type: %d\n", t->type);
845        }
846        e_memchunk_free(f->term_chunks, t);
847}
848
849static struct _ESExpTerm **
850parse_values(ESExp *f, int *len)
851{
852        int token;
853        struct _ESExpTerm **terms;
854        int i, size = 0;
855        GScanner *gs = f->scanner;
856        GSList *list = NULL, *l;
857
858        p(printf("parsing values\n"));
859
860        while ( (token = g_scanner_peek_next_token(gs)) != G_TOKEN_EOF
861                && token != ')') {
862                list = g_slist_prepend(list, parse_value(f));
863                size++;
864        }
865
866        /* go over the list, and put them backwards into the term array */
867        terms = g_malloc(size * sizeof(*terms));
868        l = list;
869        for (i=size-1;i>=0;i--) {
870                g_assert(l);
871                g_assert(l->data);
872                terms[i] = l->data;
873                l = g_slist_next(l);
874        }
875        g_slist_free(list);
876
877        p(printf("found %d subterms\n", size));
878        *len = size;
879       
880        p(printf("done parsing values\n"));
881        return terms;
882}
883
884static struct _ESExpTerm *
885parse_value(ESExp *f)
886{
887        int token, negative = FALSE;
888        struct _ESExpTerm *t = NULL;
889        GScanner *gs = f->scanner;
890        struct _ESExpSymbol *s;
891       
892        p(printf("parsing value\n"));
893       
894        token = g_scanner_get_next_token(gs);
895        switch(token) {
896        case G_TOKEN_LEFT_PAREN:
897                p(printf("got brace, its a list!\n"));
898                return parse_list(f, TRUE);
899        case G_TOKEN_STRING:
900                p(printf("got string\n"));
901                t = parse_term_new(f, ESEXP_TERM_STRING);
902                t->value.string = g_strdup(g_scanner_cur_value(gs).v_string);
903                break;
904        case '-':
905                p(printf ("got negative int?\n"));
906                token = g_scanner_get_next_token (gs);
907                if (token != G_TOKEN_INT) {
908                        e_sexp_fatal_error (f, "Invalid format for a integer value");
909                        return NULL;
910                }
911               
912                negative = TRUE;
913                /* fall through... */
914        case G_TOKEN_INT:
915                t = parse_term_new(f, ESEXP_TERM_INT);
916                t->value.number = g_scanner_cur_value(gs).v_int;
917                if (negative)
918                        t->value.number = -t->value.number;
919                p(printf("got int\n"));
920                break;
921        case '#': {
922                char *str;
923               
924                p(printf("got bool?\n"));
925                token = g_scanner_get_next_token(gs);
926                if (token != G_TOKEN_IDENTIFIER) {
927                        e_sexp_fatal_error (f, "Invalid format for a boolean value");
928                        return NULL;
929                }
930               
931                str = g_scanner_cur_value (gs).v_identifier;
932               
933                g_assert (str != NULL);
934                if (!(strlen (str) == 1 && (str[0] == 't' || str[0] == 'f'))) {
935                        e_sexp_fatal_error (f, "Invalid format for a boolean value");
936                        return NULL;
937                }
938               
939                t = parse_term_new(f, ESEXP_TERM_BOOL);
940                t->value.bool = (str[0] == 't');
941                break; }
942        case G_TOKEN_SYMBOL:
943                s = g_scanner_cur_value(gs).v_symbol;
944                switch (s->type) {
945                case ESEXP_TERM_FUNC:
946                case ESEXP_TERM_IFUNC:
947                                /* this is basically invalid, since we can't use function
948                                   pointers, but let the runtime catch it ... */
949                        t = parse_term_new(f, s->type);
950                        t->value.func.sym = s;
951                        t->value.func.terms = parse_values(f, &t->value.func.termcount);
952                        break;
953                case ESEXP_TERM_VAR:
954                        t = parse_term_new(f, s->type);
955                        t->value.var = s;
956                        break;
957                default:
958                        e_sexp_fatal_error(f, "Invalid symbol type: %s: %d", s->name, s->type);
959                }
960                break;
961        case G_TOKEN_IDENTIFIER:
962                e_sexp_fatal_error(f, "Unknown identifier: %s", g_scanner_cur_value(gs).v_identifier);
963                break;
964        default:
965                e_sexp_fatal_error(f, "Unexpected token encountered: %d", token);
966        }
967        p(printf("done parsing value\n"));
968        return t;
969}
970
971/* FIXME: this needs some robustification */
972static struct _ESExpTerm *
973parse_list(ESExp *f, int gotbrace)
974{
975        int token;
976        struct _ESExpTerm *t = NULL;
977        GScanner *gs = f->scanner;
978
979        p(printf("parsing list\n"));
980        if (gotbrace)
981                token = '(';
982        else
983                token = g_scanner_get_next_token(gs);
984        if (token =='(') {
985                token = g_scanner_get_next_token(gs);
986                switch(token) {
987                case G_TOKEN_SYMBOL: {
988                        struct _ESExpSymbol *s;
989
990                        s = g_scanner_cur_value(gs).v_symbol;
991                        p(printf("got funciton: %s\n", s->name));
992                        t = parse_term_new(f, s->type);
993                        p(printf("created new list %p\n", t));
994                        /* if we have a variable, find out its base type */
995                        while (s->type == ESEXP_TERM_VAR) {
996                                s = ((ESExpTerm *)(s->data))->value.var;
997                        }
998                        if (s->type == ESEXP_TERM_FUNC
999                            || s->type == ESEXP_TERM_IFUNC) {
1000                                t->value.func.sym = s;
1001                                t->value.func.terms = parse_values(f, &t->value.func.termcount);
1002                        } else {
1003                                parse_term_free(f, t);
1004                                e_sexp_fatal_error(f, "Trying to call variable as function: %s", s->name);
1005                        }
1006                        break; }
1007                case G_TOKEN_IDENTIFIER:
1008                        e_sexp_fatal_error(f, "Unknown identifier: %s", g_scanner_cur_value(gs).v_identifier);
1009                        break;
1010                default:
1011                        e_sexp_fatal_error(f, "Unexpected token encountered: %d", token);
1012                }
1013                token = g_scanner_get_next_token(gs);
1014                if (token != ')') {
1015                        e_sexp_fatal_error(f, "Missing ')'");
1016                }
1017        } else {
1018                e_sexp_fatal_error(f, "Missing '('");
1019        }
1020
1021        p(printf("returning list %p\n", t));
1022        return t;
1023}
1024
1025static void e_sexp_finalise(void *);
1026
1027#ifdef E_SEXP_IS_GTK_OBJECT
1028static void
1029e_sexp_class_init (ESExpClass *class)
1030{
1031        GtkObjectClass *object_class;
1032       
1033        object_class = (GtkObjectClass *) class;
1034
1035        object_class->finalize = e_sexp_finalise;
1036
1037        parent_class = gtk_type_class (gtk_object_get_type ());
1038}
1039#endif
1040
1041/* 'builtin' functions */
1042static struct {
1043        char *name;
1044        ESExpFunc *func;
1045        int type;               /* set to 1 if a function can perform shortcut evaluation, or
1046                                   doesn't execute everything, 0 otherwise */
1047} symbols[] = {
1048        { "and", (ESExpFunc *)term_eval_and, 1 },
1049        { "or", (ESExpFunc *)term_eval_or, 1 },
1050        { "not", (ESExpFunc *)term_eval_not, 0 },
1051        { "<", (ESExpFunc *)term_eval_lt, 1 },
1052        { ">", (ESExpFunc *)term_eval_gt, 1 },
1053        { "=", (ESExpFunc *)term_eval_eq, 1 },
1054        { "+", (ESExpFunc *)term_eval_plus, 0 },
1055        { "-", (ESExpFunc *)term_eval_sub, 0 },
1056        { "cast-int", (ESExpFunc *)term_eval_castint, 0 },
1057        { "cast-string", (ESExpFunc *)term_eval_caststring, 0 },
1058        { "if", (ESExpFunc *)term_eval_if, 1 },
1059        { "begin", (ESExpFunc *)term_eval_begin, 1 },
1060};
1061
1062static void
1063free_symbol(void *key, void *value, void *data)
1064{
1065        struct _ESExpSymbol *s = value;
1066
1067        g_free(s->name);
1068        g_free(s);
1069}
1070
1071static void
1072e_sexp_finalise(void *o)
1073{
1074        ESExp *s = (ESExp *)o;
1075
1076        if (s->tree) {
1077                parse_term_free(s, s->tree);
1078                s->tree = NULL;
1079        }
1080
1081        e_memchunk_destroy(s->term_chunks);
1082        e_memchunk_destroy(s->result_chunks);
1083
1084        g_scanner_scope_foreach_symbol(s->scanner, 0, free_symbol, 0);
1085        g_scanner_destroy(s->scanner);
1086
1087#ifdef E_SEXP_IS_GTK_OBJECT
1088        ((GtkObjectClass *)(parent_class))->finalize((GtkObject *)o);
1089#endif
1090}
1091
1092static void
1093e_sexp_init (ESExp *s)
1094{
1095        int i;
1096
1097        s->scanner = g_scanner_new(&scanner_config);
1098        s->term_chunks = e_memchunk_new(16, sizeof(struct _ESExpTerm));
1099        s->result_chunks = e_memchunk_new(16, sizeof(struct _ESExpResult));
1100
1101        /* load in builtin symbols? */
1102        for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++) {
1103                if (symbols[i].type == 1) {
1104                        e_sexp_add_ifunction(s, 0, symbols[i].name, (ESExpIFunc *)symbols[i].func, &symbols[i]);
1105                } else {
1106                        e_sexp_add_function(s, 0, symbols[i].name, symbols[i].func, &symbols[i]);
1107                }
1108        }
1109
1110#ifndef E_SEXP_IS_GTK_OBJECT
1111        s->refcount = 1;
1112#endif
1113}
1114
1115#ifdef E_SEXP_IS_GTK_OBJECT
1116guint
1117e_sexp_get_type (void)
1118{
1119        static guint type = 0;
1120       
1121        if (!type) {
1122                GtkTypeInfo type_info = {
1123                        "ESExp",
1124                        sizeof (ESExp),
1125                        sizeof (ESExpClass),
1126                        (GtkClassInitFunc) e_sexp_class_init,
1127                        (GtkObjectInitFunc) e_sexp_init,
1128                        (GtkArgSetFunc) NULL,
1129                        (GtkArgGetFunc) NULL
1130                };
1131               
1132                type = gtk_type_unique (gtk_object_get_type (), &type_info);
1133        }
1134       
1135        return type;
1136}
1137#endif
1138
1139ESExp *
1140e_sexp_new (void)
1141{
1142#ifdef E_SEXP_IS_GTK_OBJECT
1143        ESExp *f = E_SEXP ( gtk_type_new (e_sexp_get_type ()));
1144#else
1145        ESExp *f = g_malloc0(sizeof(*f));
1146        e_sexp_init(f);
1147#endif
1148
1149        return f;
1150}
1151
1152#ifndef E_SEXP_IS_GTK_OBJECT
1153void            e_sexp_ref              (ESExp *f)
1154{
1155        f->refcount++;
1156}
1157
1158void            e_sexp_unref            (ESExp *f)
1159{
1160        f->refcount--;
1161        if (f->refcount == 0) {
1162                e_sexp_finalise(f);
1163                g_free(f);
1164        }
1165}
1166#endif
1167
1168void
1169e_sexp_add_function(ESExp *f, int scope, char *name, ESExpFunc *func, void *data)
1170{
1171        struct _ESExpSymbol *s;
1172
1173        g_return_if_fail(FILTER_IS_SEXP(f));
1174        g_return_if_fail(name != NULL);
1175
1176        s = g_malloc0(sizeof(*s));
1177        s->name = g_strdup(name);
1178        s->f.func = func;
1179        s->type = ESEXP_TERM_FUNC;
1180        s->data = data;
1181        g_scanner_scope_add_symbol(f->scanner, scope, s->name, s);
1182}
1183
1184void
1185e_sexp_add_ifunction(ESExp *f, int scope, char *name, ESExpIFunc *ifunc, void *data)
1186{
1187        struct _ESExpSymbol *s;
1188
1189        g_return_if_fail(FILTER_IS_SEXP(f));
1190        g_return_if_fail(name != NULL);
1191
1192        s = g_malloc0(sizeof(*s));
1193        s->name = g_strdup(name);
1194        s->f.ifunc = ifunc;
1195        s->type = ESEXP_TERM_IFUNC;
1196        s->data = data;
1197        g_scanner_scope_add_symbol(f->scanner, scope, s->name, s);
1198}
1199
1200void
1201e_sexp_add_variable(ESExp *f, int scope, char *name, ESExpTerm *value)
1202{
1203        struct _ESExpSymbol *s;
1204
1205        g_return_if_fail(FILTER_IS_SEXP(f));
1206        g_return_if_fail(name != NULL);
1207
1208        s = g_malloc0(sizeof(*s));
1209        s->name = g_strdup(name);
1210        s->type = ESEXP_TERM_VAR;
1211        s->data = value;
1212        g_scanner_scope_add_symbol(f->scanner, scope, s->name, s);
1213}
1214
1215void
1216e_sexp_remove_symbol(ESExp *f, int scope, char *name)
1217{
1218        int oldscope;
1219        struct _ESExpSymbol *s;
1220
1221        g_return_if_fail(FILTER_IS_SEXP(f));
1222        g_return_if_fail(name != NULL);
1223
1224        oldscope = g_scanner_set_scope(f->scanner, scope);
1225        s = g_scanner_lookup_symbol(f->scanner, name);
1226        g_scanner_scope_remove_symbol(f->scanner, scope, name);
1227        g_scanner_set_scope(f->scanner, oldscope);
1228        if (s) {
1229                g_free(s->name);
1230                g_free(s);
1231        }
1232}
1233
1234int
1235e_sexp_set_scope(ESExp *f, int scope)
1236{
1237        g_return_val_if_fail(FILTER_IS_SEXP(f), 0);
1238
1239        return g_scanner_set_scope(f->scanner, scope);
1240}
1241
1242void
1243e_sexp_input_text(ESExp *f, const char *text, int len)
1244{
1245        g_return_if_fail(FILTER_IS_SEXP(f));
1246        g_return_if_fail(text != NULL);
1247
1248        g_scanner_input_text(f->scanner, text, len);
1249}
1250
1251void
1252e_sexp_input_file (ESExp *f, int fd)
1253{
1254        g_return_if_fail(FILTER_IS_SEXP(f));
1255
1256        g_scanner_input_file(f->scanner, fd);
1257}
1258
1259/* returns -1 on error */
1260int
1261e_sexp_parse(ESExp *f)
1262{
1263        g_return_val_if_fail(FILTER_IS_SEXP(f), -1);
1264
1265        if (setjmp(f->failenv)) {
1266                g_warning("Error in parsing: %s", f->error);
1267                return -1;
1268        }
1269
1270        if (f->tree)
1271                parse_term_free(f, f->tree);
1272
1273        f->tree = parse_value (f);
1274
1275        return 0;
1276}
1277
1278/* returns NULL on error */
1279struct _ESExpResult *
1280e_sexp_eval(ESExp *f)
1281{
1282        g_return_val_if_fail(FILTER_IS_SEXP(f), NULL);
1283        g_return_val_if_fail(f->tree != NULL, NULL);
1284
1285        if (setjmp(f->failenv)) {
1286                g_warning("Error in execution: %s", f->error);
1287                return NULL;
1288        }
1289
1290        return e_sexp_term_eval(f, f->tree);
1291}
1292
1293/**
1294 * e_sexp_encode_bool:
1295 * @s:
1296 * @state:
1297 *
1298 * Encode a bool into an s-expression @s.  Bools are
1299 * encoded using #t #f syntax.
1300 **/
1301void
1302e_sexp_encode_bool(GString *s, gboolean state)
1303{
1304        if (state)
1305                g_string_append(s, " #t");
1306        else
1307                g_string_append(s, " #f");
1308}
1309
1310/**
1311 * e_sexp_encode_string:
1312 * @s: Destination string.
1313 * @string: String expression.
1314 *
1315 * Add a c string @string to the s-expression stored in
1316 * the gstring @s.  Quotes are added, and special characters
1317 * are escaped appropriately.
1318 **/
1319void
1320e_sexp_encode_string(GString *s, const char *string)
1321{
1322        char c;
1323        const char *p;
1324
1325        if (string == NULL)
1326                p = "";
1327        else
1328                p = string;
1329        g_string_append(s, " \"");
1330        while ( (c = *p++) ) {
1331                if (c=='\\' || c=='\"' || c=='\'')
1332                        g_string_append_c(s, '\\');
1333                g_string_append_c(s, c);
1334        }
1335        g_string_append(s, "\"");
1336}
1337
1338#ifdef TESTER
1339int main(int argc, char **argv)
1340{
1341        ESExp *f;
1342        char *t = "(+ \"foo\" \"\\\"\" \"bar\" \"\\\\ blah \\x \")";
1343        ESExpResult *r;
1344
1345        gtk_init(&argc, &argv);
1346
1347        f = e_sexp_new();
1348
1349        e_sexp_add_variable(f, 0, "test", NULL);
1350
1351        e_sexp_input_text(f, t, strlen(t));
1352        e_sexp_parse(f);
1353
1354        if (f->tree) {
1355                parse_dump_term(f->tree, 0);
1356        }
1357
1358        r = e_sexp_eval(f);
1359        if (r) {
1360                eval_dump_result(r, 0);
1361        } else {
1362                printf("no result?|\n");
1363        }
1364
1365        return 0;
1366}
1367#endif
Note: See TracBrowser for help on using the repository browser.