2 * Copyright 2000 Ximian (www.ximian.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 int = (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.
98 #define p(x) /* parse debug */
99 #define r(x) /* run debug */
100 #define d(x) /* general debug */
103 static struct _ESExpTerm * parse_list(ESExp *f, int gotbrace);
104 static struct _ESExpTerm * parse_value(ESExp *f);
106 static void parse_dump_term(struct _ESExpTerm *t, int depth);
108 #ifdef E_SEXP_IS_G_OBJECT
109 static GObjectClass *parent_class;
112 static const GScannerConfig scanner_config =
114 ( " \t\r\n") /* cset_skip_characters */,
117 G_CSET_A_2_Z) /* cset_identifier_first */,
122 G_CSET_LATINC ) /* cset_identifier_nth */,
123 ( ";\n" ) /* cpair_comment_single */,
125 FALSE /* case_sensitive */,
127 TRUE /* skip_comment_multi */,
128 TRUE /* skip_comment_single */,
129 TRUE /* scan_comment_multi */,
130 TRUE /* scan_identifier */,
131 TRUE /* scan_identifier_1char */,
132 FALSE /* scan_identifier_NULL */,
133 TRUE /* scan_symbols */,
134 FALSE /* scan_binary */,
135 TRUE /* scan_octal */,
136 TRUE /* scan_float */,
138 FALSE /* scan_hex_dollar */,
139 TRUE /* scan_string_sq */,
140 TRUE /* scan_string_dq */,
141 TRUE /* numbers_2_int */,
142 FALSE /* int_2_float */,
143 FALSE /* identifier_2_string */,
144 TRUE /* char_2_token */,
145 FALSE /* symbol_2_token */,
146 FALSE /* scope_0_fallback */,
149 /* jumps back to the caller of f->failenv, only to be called from inside a callback */
151 e_sexp_fatal_error(struct _ESExp *f, char *why, ...)
159 f->error = g_strdup_vprintf(why, args);
162 longjmp(f->failenv, 1);
166 e_sexp_error(struct _ESExp *f)
171 struct _ESExpResult *
172 e_sexp_result_new(struct _ESExp *f, int type)
174 struct _ESExpResult *r = e_memchunk_alloc0(f->result_chunks);
180 e_sexp_result_free(struct _ESExp *f, struct _ESExpResult *t)
186 case ESEXP_RES_ARRAY_PTR:
187 g_ptr_array_free(t->value.ptrarray, TRUE);
193 case ESEXP_RES_STRING:
194 g_free(t->value.string);
196 case ESEXP_RES_UNDEFINED:
199 g_assert_not_reached();
201 e_memchunk_free(f->result_chunks, t);
204 /* used in normal functions if they have to abort, and free their arguments */
206 e_sexp_resultv_free(struct _ESExp *f, int argc, struct _ESExpResult **argv)
210 for (i=0;i<argc;i++) {
211 e_sexp_result_free(f, argv[i]);
215 /* implementations for the builtin functions */
217 /* can you tell, i dont like glib? */
218 /* we can only itereate a hashtable from a called function */
219 struct _glib_sux_donkeys {
224 /* ok, store any values that are in all sets */
226 g_lib_sux_htand(char *key, int value, struct _glib_sux_donkeys *fuckup)
228 if (value == fuckup->count) {
229 g_ptr_array_add(fuckup->uids, key);
233 /* or, store all unique values */
235 g_lib_sux_htor(char *key, int value, struct _glib_sux_donkeys *fuckup)
237 g_ptr_array_add(fuckup->uids, key);
241 term_eval_and(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
243 struct _ESExpResult *r, *r1;
244 GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
245 struct _glib_sux_donkeys lambdafoo;
250 r(printf("( and\n"));
252 r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
254 for (i=0;bool && i<argc;i++) {
255 r1 = e_sexp_term_eval(f, argv[i]);
258 if (type != r1->type) {
259 e_sexp_result_free(f, r);
260 e_sexp_result_free(f, r1);
261 g_hash_table_destroy(ht);
262 e_sexp_fatal_error(f, "Invalid types in AND");
263 } else if (r1->type == ESEXP_RES_ARRAY_PTR) {
267 a1 = (char **)r1->value.ptrarray->pdata;
268 l1 = r1->value.ptrarray->len;
272 ptr = g_hash_table_lookup(ht, a1[j]);
273 n = GPOINTER_TO_INT(ptr);
274 g_hash_table_insert(ht, a1[j], GINT_TO_POINTER(n+1));
276 } else if (r1->type == ESEXP_RES_BOOL) {
277 bool = bool && r1->value.bool;
279 e_sexp_result_free(f, r1);
282 if (type == ESEXP_RES_ARRAY_PTR) {
283 lambdafoo.count = argc;
284 lambdafoo.uids = g_ptr_array_new();
285 g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htand, &lambdafoo);
286 r->type = ESEXP_RES_ARRAY_PTR;
287 r->value.ptrarray = lambdafoo.uids;
288 } else if (type == ESEXP_RES_BOOL) {
289 r->type = ESEXP_RES_BOOL;
290 r->value.bool = bool;
293 g_hash_table_destroy(ht);
299 term_eval_or(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
301 struct _ESExpResult *r, *r1;
302 GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
303 struct _glib_sux_donkeys lambdafoo;
310 r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
312 for (i=0;!bool && i<argc;i++) {
313 r1 = e_sexp_term_eval(f, argv[i]);
316 if (r1->type != type) {
317 e_sexp_result_free(f, r);
318 e_sexp_result_free(f, r1);
319 g_hash_table_destroy(ht);
320 e_sexp_fatal_error(f, "Invalid types in OR");
321 } else if (r1->type == ESEXP_RES_ARRAY_PTR) {
325 a1 = (char **)r1->value.ptrarray->pdata;
326 l1 = r1->value.ptrarray->len;
328 g_hash_table_insert(ht, a1[j], (void *)1);
330 } else if (r1->type == ESEXP_RES_BOOL) {
331 bool |= r1->value.bool;
333 e_sexp_result_free(f, r1);
336 if (type == ESEXP_RES_ARRAY_PTR) {
337 lambdafoo.count = argc;
338 lambdafoo.uids = g_ptr_array_new();
339 g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htor, &lambdafoo);
340 r->type = ESEXP_RES_ARRAY_PTR;
341 r->value.ptrarray = lambdafoo.uids;
342 } else if (type == ESEXP_RES_BOOL) {
343 r->type = ESEXP_RES_BOOL;
344 r->value.bool = bool;
346 g_hash_table_destroy(ht);
352 term_eval_not(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
358 if (argv[0]->type == ESEXP_RES_BOOL
359 && argv[0]->value.bool)
362 r = e_sexp_result_new(f, ESEXP_RES_BOOL);
367 /* this should support all arguments ...? */
369 term_eval_lt(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
371 struct _ESExpResult *r, *r1, *r2;
373 r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
376 r1 = e_sexp_term_eval(f, argv[0]);
377 r2 = e_sexp_term_eval(f, argv[1]);
378 if (r1->type != r2->type) {
379 e_sexp_result_free(f, r1);
380 e_sexp_result_free(f, r2);
381 e_sexp_result_free(f, r);
382 e_sexp_fatal_error(f, "Incompatible types in compare <");
383 } else if (r1->type == ESEXP_RES_INT) {
384 r->type = ESEXP_RES_BOOL;
385 r->value.bool = r1->value.number < r2->value.number;
386 } else if (r1->type == ESEXP_RES_TIME) {
387 r->type = ESEXP_RES_BOOL;
388 r->value.bool = r1->value.time < r2->value.time;
389 } else if (r1->type == ESEXP_RES_STRING) {
390 r->type = ESEXP_RES_BOOL;
391 r->value.bool = strcmp(r1->value.string, r2->value.string) < 0;
393 e_sexp_result_free(f, r1);
394 e_sexp_result_free(f, r2);
399 /* this should support all arguments ...? */
401 term_eval_gt(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
403 struct _ESExpResult *r, *r1, *r2;
405 r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
408 r1 = e_sexp_term_eval(f, argv[0]);
409 r2 = e_sexp_term_eval(f, argv[1]);
410 if (r1->type != r2->type) {
411 e_sexp_result_free(f, r1);
412 e_sexp_result_free(f, r2);
413 e_sexp_result_free(f, r);
414 e_sexp_fatal_error(f, "Incompatible types in compare >");
415 } else if (r1->type == ESEXP_RES_INT) {
416 r->type = ESEXP_RES_BOOL;
417 r->value.bool = r1->value.number > r2->value.number;
418 } else if (r1->type == ESEXP_RES_TIME) {
419 r->type = ESEXP_RES_BOOL;
420 r->value.bool = r1->value.time > r2->value.time;
421 } else if (r1->type == ESEXP_RES_STRING) {
422 r->type = ESEXP_RES_BOOL;
423 r->value.bool = strcmp(r1->value.string, r2->value.string) > 0;
425 e_sexp_result_free(f, r1);
426 e_sexp_result_free(f, r2);
431 /* this should support all arguments ...? */
433 term_eval_eq(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
435 struct _ESExpResult *r, *r1, *r2;
437 r = e_sexp_result_new(f, ESEXP_RES_BOOL);
440 r1 = e_sexp_term_eval(f, argv[0]);
441 r2 = e_sexp_term_eval(f, argv[1]);
442 if (r1->type != r2->type) {
443 r->value.bool = FALSE;
444 } else if (r1->type == ESEXP_RES_INT) {
445 r->value.bool = r1->value.number == r2->value.number;
446 } else if (r1->type == ESEXP_RES_BOOL) {
447 r->value.bool = r1->value.bool == r2->value.bool;
448 } else if (r1->type == ESEXP_RES_TIME) {
449 r->value.bool = r1->value.time == r2->value.time;
450 } else if (r1->type == ESEXP_RES_STRING) {
451 r->value.bool = strcmp(r1->value.string, r2->value.string) == 0;
453 e_sexp_result_free(f, r1);
454 e_sexp_result_free(f, r2);
460 term_eval_plus(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
462 struct _ESExpResult *r=NULL;
467 type = argv[0]->type;
469 case ESEXP_RES_INT: {
470 int total = argv[0]->value.number;
471 for (i=1;i<argc && argv[i]->type == ESEXP_RES_INT;i++) {
472 total += argv[i]->value.number;
475 e_sexp_resultv_free(f, argc, argv);
476 e_sexp_fatal_error(f, "Invalid types in (+ ints)");
478 r = e_sexp_result_new(f, ESEXP_RES_INT);
479 r->value.number = total;
481 case ESEXP_RES_STRING: {
482 GString *s = g_string_new(argv[0]->value.string);
483 for (i=1;i<argc && argv[i]->type == ESEXP_RES_STRING;i++) {
484 g_string_append(s, argv[i]->value.string);
487 e_sexp_resultv_free(f, argc, argv);
488 e_sexp_fatal_error(f, "Invalid types in (+ strings)");
490 r = e_sexp_result_new(f, ESEXP_RES_STRING);
491 r->value.string = s->str;
492 g_string_free(s, FALSE);
494 case ESEXP_RES_TIME: {
497 total = argv[0]->value.time;
499 for (i = 1; i < argc && argv[i]->type == ESEXP_RES_TIME; i++)
500 total += argv[i]->value.time;
503 e_sexp_resultv_free (f, argc, argv);
504 e_sexp_fatal_error (f, "Invalid types in (+ time_t)");
507 r = e_sexp_result_new (f, ESEXP_RES_TIME);
508 r->value.time = total;
514 r = e_sexp_result_new(f, ESEXP_RES_INT);
521 term_eval_sub(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
523 struct _ESExpResult *r=NULL;
528 type = argv[0]->type;
530 case ESEXP_RES_INT: {
531 int total = argv[0]->value.number;
532 for (i=1;i<argc && argv[i]->type == ESEXP_RES_INT;i++) {
533 total -= argv[i]->value.number;
536 e_sexp_resultv_free(f, argc, argv);
537 e_sexp_fatal_error(f, "Invalid types in -");
539 r = e_sexp_result_new(f, ESEXP_RES_INT);
540 r->value.number = total;
542 case ESEXP_RES_TIME: {
545 total = argv[0]->value.time;
547 for (i = 1; i < argc && argv[i]->type == ESEXP_RES_TIME; i++)
548 total -= argv[i]->value.time;
551 e_sexp_resultv_free (f, argc, argv);
552 e_sexp_fatal_error (f, "Invalid types in (- time_t)");
555 r = e_sexp_result_new (f, ESEXP_RES_TIME);
556 r->value.time = total;
562 r = e_sexp_result_new(f, ESEXP_RES_INT);
570 term_eval_castint(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
572 struct _ESExpResult *r;
575 e_sexp_fatal_error(f, "Incorrect argument count to (int )");
577 r = e_sexp_result_new(f, ESEXP_RES_INT);
578 switch (argv[0]->type) {
580 r->value.number = argv[0]->value.number;
583 r->value.number = argv[0]->value.bool != 0;
585 case ESEXP_RES_STRING:
586 r->value.number = strtoul(argv[0]->value.string, NULL, 10);
589 e_sexp_result_free(f, r);
590 e_sexp_fatal_error(f, "Invalid type in (cast-int )");
598 term_eval_caststring(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
600 struct _ESExpResult *r;
603 e_sexp_fatal_error(f, "Incorrect argument count to (cast-string )");
605 r = e_sexp_result_new(f, ESEXP_RES_STRING);
606 switch (argv[0]->type) {
608 r->value.string = g_strdup_printf("%d", argv[0]->value.number);
611 r->value.string = g_strdup_printf("%d", argv[0]->value.bool != 0);
613 case ESEXP_RES_STRING:
614 r->value.string = g_strdup(argv[0]->value.string);
617 e_sexp_result_free(f, r);
618 e_sexp_fatal_error(f, "Invalid type in (int )");
624 /* implements 'if' function */
626 term_eval_if(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
628 struct _ESExpResult *r;
631 if (argc >=2 && argc<=3) {
632 r = e_sexp_term_eval(f, argv[0]);
633 doit = (r->type == ESEXP_RES_BOOL && r->value.bool);
634 e_sexp_result_free(f, r);
636 return e_sexp_term_eval(f, argv[1]);
638 return e_sexp_term_eval(f, argv[2]);
641 return e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
644 /* implements 'begin' statement */
646 term_eval_begin(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
648 struct _ESExpResult *r=NULL;
651 for (i=0;i<argc;i++) {
653 e_sexp_result_free(f, r);
654 r = e_sexp_term_eval(f, argv[i]);
659 return e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
663 /* this must only be called from inside term evaluation callbacks! */
664 struct _ESExpResult *
665 e_sexp_term_eval(struct _ESExp *f, struct _ESExpTerm *t)
667 struct _ESExpResult *r = NULL;
669 struct _ESExpResult **argv;
671 g_return_val_if_fail(t != NULL, NULL);
673 r(printf("eval term :\n"));
674 r(parse_dump_term(t, 0));
677 case ESEXP_TERM_STRING:
678 r(printf(" (string \"%s\")\n", t->value.string));
679 r = e_sexp_result_new(f, ESEXP_RES_STRING);
680 /* erk, this shoul;dn't need to strdup this ... */
681 r->value.string = g_strdup(t->value.string);
684 r(printf(" (int %d)\n", t->value.number));
685 r = e_sexp_result_new(f, ESEXP_RES_INT);
686 r->value.number = t->value.number;
688 case ESEXP_TERM_BOOL:
689 r(printf(" (int %d)\n", t->value.number));
690 r = e_sexp_result_new(f, ESEXP_RES_BOOL);
691 r->value.bool = t->value.bool;
693 case ESEXP_TERM_TIME:
694 r(printf(" (time_t %d)\n", t->value.time));
695 r = e_sexp_result_new (f, ESEXP_RES_TIME);
696 r->value.time = t->value.time;
698 case ESEXP_TERM_IFUNC:
699 if (t->value.func.sym->f.ifunc)
700 r = t->value.func.sym->f.ifunc(f, t->value.func.termcount, t->value.func.terms, t->value.func.sym->data);
702 case ESEXP_TERM_FUNC:
703 /* first evaluate all arguments to result types */
704 argv = alloca(sizeof(argv[0]) * t->value.func.termcount);
705 for (i=0;i<t->value.func.termcount;i++) {
706 argv[i] = e_sexp_term_eval(f, t->value.func.terms[i]);
708 /* call the function */
709 if (t->value.func.sym->f.func)
710 r = t->value.func.sym->f.func(f, t->value.func.termcount, argv, t->value.func.sym->data);
712 e_sexp_resultv_free(f, t->value.func.termcount, argv);
715 e_sexp_fatal_error(f, "Unknown type in parse tree: %d", t->type);
719 r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
726 eval_dump_result(ESExpResult *r, int depth)
731 printf("null result???\n");
735 for (i=0;i<depth;i++)
739 case ESEXP_RES_ARRAY_PTR:
740 printf("array pointers\n");
743 printf("int: %d\n", r->value.number);
745 case ESEXP_RES_STRING:
746 printf("string: '%s'\n", r->value.string);
749 printf("bool: %c\n", r->value.bool?'t':'f');
752 printf("time_t: %ld\n", (long) r->value.time);
754 case ESEXP_RES_UNDEFINED:
755 printf(" <undefined>\n");
763 parse_dump_term(struct _ESExpTerm *t, int depth)
768 printf("null term??\n");
772 for (i=0;i<depth;i++)
776 case ESEXP_TERM_STRING:
777 printf(" \"%s\"", t->value.string);
780 printf(" %d", t->value.number);
782 case ESEXP_TERM_BOOL:
783 printf(" #%c", t->value.bool?'t':'f');
785 case ESEXP_TERM_TIME:
786 printf(" %ld", (long) t->value.time);
788 case ESEXP_TERM_IFUNC:
789 case ESEXP_TERM_FUNC:
790 printf(" (function %s\n", t->value.func.sym->name);
791 /*printf(" [%d] ", t->value.func.termcount);*/
792 for (i=0;i<t->value.func.termcount;i++) {
793 parse_dump_term(t->value.func.terms[i], depth+1);
795 for (i=0;i<depth;i++)
800 printf(" (variable %s )\n", t->value.var->name);
803 printf("unknown type: %d\n", t->type);
813 static struct _ESExpTerm *
814 parse_term_new(struct _ESExp *f, int type)
816 struct _ESExpTerm *s = e_memchunk_alloc0(f->term_chunks);
822 parse_term_free(struct _ESExp *f, struct _ESExpTerm *t)
832 case ESEXP_TERM_BOOL:
833 case ESEXP_TERM_TIME:
837 case ESEXP_TERM_STRING:
838 g_free(t->value.string);
841 case ESEXP_TERM_FUNC:
842 case ESEXP_TERM_IFUNC:
843 for (i=0;i<t->value.func.termcount;i++) {
844 parse_term_free(f, t->value.func.terms[i]);
846 g_free(t->value.func.terms);
850 printf("parse_term_free: unknown type: %d\n", t->type);
852 e_memchunk_free(f->term_chunks, t);
855 static struct _ESExpTerm **
856 parse_values(ESExp *f, int *len)
859 struct _ESExpTerm **terms;
861 GScanner *gs = f->scanner;
862 GSList *list = NULL, *l;
864 p(printf("parsing values\n"));
866 while ( (token = g_scanner_peek_next_token(gs)) != G_TOKEN_EOF
868 list = g_slist_prepend(list, parse_value(f));
872 /* go over the list, and put them backwards into the term array */
873 terms = g_malloc(size * sizeof(*terms));
875 for (i=size-1;i>=0;i--) {
883 p(printf("found %d subterms\n", size));
886 p(printf("done parsing values\n"));
890 static struct _ESExpTerm *
891 parse_value(ESExp *f)
893 int token, negative = FALSE;
894 struct _ESExpTerm *t = NULL;
895 GScanner *gs = f->scanner;
896 struct _ESExpSymbol *s;
898 p(printf("parsing value\n"));
900 token = g_scanner_get_next_token(gs);
904 case G_TOKEN_LEFT_PAREN:
905 p(printf("got brace, its a list!\n"));
906 return parse_list(f, TRUE);
908 p(printf("got string '%s'\n", g_scanner_cur_value(gs).v_string));
909 t = parse_term_new(f, ESEXP_TERM_STRING);
910 t->value.string = g_strdup(g_scanner_cur_value(gs).v_string);
913 p(printf ("got negative int?\n"));
914 token = g_scanner_get_next_token (gs);
915 if (token != G_TOKEN_INT) {
916 e_sexp_fatal_error (f, "Invalid format for a integer value");
921 /* fall through... */
923 t = parse_term_new(f, ESEXP_TERM_INT);
924 t->value.number = g_scanner_cur_value(gs).v_int;
926 t->value.number = -t->value.number;
927 p(printf("got int %d\n", t->value.number));
932 p(printf("got bool?\n"));
933 token = g_scanner_get_next_token(gs);
934 if (token != G_TOKEN_IDENTIFIER) {
935 e_sexp_fatal_error (f, "Invalid format for a boolean value");
939 str = g_scanner_cur_value (gs).v_identifier;
941 g_assert (str != NULL);
942 if (!(strlen (str) == 1 && (str[0] == 't' || str[0] == 'f'))) {
943 e_sexp_fatal_error (f, "Invalid format for a boolean value");
947 t = parse_term_new(f, ESEXP_TERM_BOOL);
948 t->value.bool = (str[0] == 't');
951 s = g_scanner_cur_value(gs).v_symbol;
952 p(printf("got symbol '%s'\n", s->name));
954 case ESEXP_TERM_FUNC:
955 case ESEXP_TERM_IFUNC:
956 /* this is basically invalid, since we can't use function
957 pointers, but let the runtime catch it ... */
958 t = parse_term_new(f, s->type);
959 t->value.func.sym = s;
960 t->value.func.terms = parse_values(f, &t->value.func.termcount);
963 t = parse_term_new(f, s->type);
967 e_sexp_fatal_error(f, "Invalid symbol type: %s: %d", s->name, s->type);
970 case G_TOKEN_IDENTIFIER:
971 p(printf("got unknown identifider '%s'\n", g_scanner_cur_value(gs).v_identifier));
972 e_sexp_fatal_error(f, "Unknown identifier: %s", g_scanner_cur_value(gs).v_identifier);
975 e_sexp_fatal_error(f, "Unexpected token encountered: %d", token);
977 p(printf("done parsing value\n"));
981 /* FIXME: this needs some robustification */
982 static struct _ESExpTerm *
983 parse_list(ESExp *f, int gotbrace)
986 struct _ESExpTerm *t = NULL;
987 GScanner *gs = f->scanner;
989 p(printf("parsing list\n"));
993 token = g_scanner_get_next_token(gs);
995 token = g_scanner_get_next_token(gs);
997 case G_TOKEN_SYMBOL: {
998 struct _ESExpSymbol *s;
1000 s = g_scanner_cur_value(gs).v_symbol;
1001 p(printf("got funciton: %s\n", s->name));
1002 t = parse_term_new(f, s->type);
1003 p(printf("created new list %p\n", t));
1004 /* if we have a variable, find out its base type */
1005 while (s->type == ESEXP_TERM_VAR) {
1006 s = ((ESExpTerm *)(s->data))->value.var;
1008 if (s->type == ESEXP_TERM_FUNC
1009 || s->type == ESEXP_TERM_IFUNC) {
1010 t->value.func.sym = s;
1011 t->value.func.terms = parse_values(f, &t->value.func.termcount);
1013 parse_term_free(f, t);
1014 e_sexp_fatal_error(f, "Trying to call variable as function: %s", s->name);
1017 case G_TOKEN_IDENTIFIER:
1018 e_sexp_fatal_error(f, "Unknown identifier: %s", g_scanner_cur_value(gs).v_identifier);
1021 e_sexp_fatal_error(f, "Unexpected token encountered: %d", token);
1023 token = g_scanner_get_next_token(gs);
1025 e_sexp_fatal_error(f, "Missing ')'");
1028 e_sexp_fatal_error(f, "Missing '('");
1031 p(printf("returning list %p\n", t));
1035 static void e_sexp_finalise(void *);
1037 #ifdef E_SEXP_IS_G_OBJECT
1039 e_sexp_class_init (ESExpClass *klass)
1041 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1043 object_class->finalize = e_sexp_finalise;
1045 parent_class = g_type_class_ref (g_object_get_type ());
1049 /* 'builtin' functions */
1050 static const struct {
1053 int type; /* set to 1 if a function can perform shortcut evaluation, or
1054 doesn't execute everything, 0 otherwise */
1056 { "and", (ESExpFunc *)term_eval_and, 1 },
1057 { "or", (ESExpFunc *)term_eval_or, 1 },
1058 { "not", (ESExpFunc *)term_eval_not, 0 },
1059 { "<", (ESExpFunc *)term_eval_lt, 1 },
1060 { ">", (ESExpFunc *)term_eval_gt, 1 },
1061 { "=", (ESExpFunc *)term_eval_eq, 1 },
1062 { "+", (ESExpFunc *)term_eval_plus, 0 },
1063 { "-", (ESExpFunc *)term_eval_sub, 0 },
1064 { "cast-int", (ESExpFunc *)term_eval_castint, 0 },
1065 { "cast-string", (ESExpFunc *)term_eval_caststring, 0 },
1066 { "if", (ESExpFunc *)term_eval_if, 1 },
1067 { "begin", (ESExpFunc *)term_eval_begin, 1 },
1071 free_symbol(void *key, void *value, void *data)
1073 struct _ESExpSymbol *s = value;
1080 e_sexp_finalise(void *o)
1082 ESExp *s = (ESExp *)o;
1085 parse_term_free(s, s->tree);
1089 e_memchunk_destroy(s->term_chunks);
1090 e_memchunk_destroy(s->result_chunks);
1092 g_scanner_scope_foreach_symbol(s->scanner, 0, free_symbol, NULL);
1093 g_scanner_destroy(s->scanner);
1095 #ifdef E_SEXP_IS_G_OBJECT
1096 G_OBJECT_CLASS (parent_class)->finalize (o);
1101 e_sexp_init (ESExp *s)
1105 s->scanner = g_scanner_new(&scanner_config);
1106 s->term_chunks = e_memchunk_new(16, sizeof(struct _ESExpTerm));
1107 s->result_chunks = e_memchunk_new(16, sizeof(struct _ESExpResult));
1109 /* load in builtin symbols? */
1110 for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++) {
1111 if (symbols[i].type == 1) {
1112 e_sexp_add_ifunction(s, 0, symbols[i].name, (ESExpIFunc *)symbols[i].func, (void *)&symbols[i]);
1114 e_sexp_add_function(s, 0, symbols[i].name, symbols[i].func, (void *)&symbols[i]);
1118 #ifndef E_SEXP_IS_G_OBJECT
1123 #ifdef E_SEXP_IS_G_OBJECT
1125 e_sexp_get_type (void)
1127 static GType type = 0;
1130 static const GTypeInfo info = {
1131 sizeof (ESExpClass),
1132 NULL, /* base_class_init */
1133 NULL, /* base_class_finalize */
1134 (GClassInitFunc) e_sexp_class_init,
1135 NULL, /* class_finalize */
1136 NULL, /* class_data */
1138 0, /* n_preallocs */
1139 (GInstanceInitFunc) e_sexp_init,
1142 type = g_type_register_static (G_TYPE_OBJECT, "ESExp", &info, 0);
1152 #ifdef E_SEXP_IS_G_OBJECT
1153 ESExp *f = (ESexp *) g_object_new (E_TYPE_SEXP, NULL);
1155 ESExp *f = g_malloc0 (sizeof (ESExp));
1162 #ifndef E_SEXP_IS_G_OBJECT
1164 e_sexp_ref (ESExp *f)
1170 e_sexp_unref (ESExp *f)
1173 if (f->refcount == 0) {
1181 e_sexp_add_function(ESExp *f, int scope, char *name, ESExpFunc *func, void *data)
1183 struct _ESExpSymbol *s;
1185 g_return_if_fail (IS_E_SEXP (f));
1186 g_return_if_fail (name != NULL);
1188 e_sexp_remove_symbol (f, scope, name);
1190 s = g_malloc0(sizeof(*s));
1191 s->name = g_strdup(name);
1193 s->type = ESEXP_TERM_FUNC;
1195 g_scanner_scope_add_symbol(f->scanner, scope, s->name, s);
1199 e_sexp_add_ifunction(ESExp *f, int scope, char *name, ESExpIFunc *ifunc, void *data)
1201 struct _ESExpSymbol *s;
1203 g_return_if_fail (IS_E_SEXP (f));
1204 g_return_if_fail (name != NULL);
1206 e_sexp_remove_symbol (f, scope, name);
1208 s = g_malloc0(sizeof(*s));
1209 s->name = g_strdup(name);
1211 s->type = ESEXP_TERM_IFUNC;
1213 g_scanner_scope_add_symbol(f->scanner, scope, s->name, s);
1217 e_sexp_add_variable(ESExp *f, int scope, char *name, ESExpTerm *value)
1219 struct _ESExpSymbol *s;
1221 g_return_if_fail (IS_E_SEXP (f));
1222 g_return_if_fail (name != NULL);
1224 s = g_malloc0(sizeof(*s));
1225 s->name = g_strdup(name);
1226 s->type = ESEXP_TERM_VAR;
1228 g_scanner_scope_add_symbol(f->scanner, scope, s->name, s);
1232 e_sexp_remove_symbol(ESExp *f, int scope, char *name)
1235 struct _ESExpSymbol *s;
1237 g_return_if_fail (IS_E_SEXP (f));
1238 g_return_if_fail (name != NULL);
1240 oldscope = g_scanner_set_scope(f->scanner, scope);
1241 s = g_scanner_lookup_symbol(f->scanner, name);
1242 g_scanner_scope_remove_symbol(f->scanner, scope, name);
1243 g_scanner_set_scope(f->scanner, oldscope);
1251 e_sexp_set_scope(ESExp *f, int scope)
1253 g_return_val_if_fail (IS_E_SEXP (f), 0);
1255 return g_scanner_set_scope(f->scanner, scope);
1259 e_sexp_input_text(ESExp *f, const char *text, int len)
1261 g_return_if_fail (IS_E_SEXP (f));
1262 g_return_if_fail (text != NULL);
1264 g_scanner_input_text(f->scanner, text, len);
1268 e_sexp_input_file (ESExp *f, int fd)
1270 g_return_if_fail (IS_E_SEXP (f));
1272 g_scanner_input_file(f->scanner, fd);
1275 /* returns -1 on error */
1277 e_sexp_parse(ESExp *f)
1279 g_return_val_if_fail (IS_E_SEXP (f), -1);
1281 if (setjmp(f->failenv)) {
1282 g_warning("Error in parsing: %s", f->error);
1287 parse_term_free(f, f->tree);
1289 f->tree = parse_value (f);
1294 /* returns NULL on error */
1295 struct _ESExpResult *
1296 e_sexp_eval(ESExp *f)
1298 g_return_val_if_fail (IS_E_SEXP (f), NULL);
1299 g_return_val_if_fail (f->tree != NULL, NULL);
1301 if (setjmp(f->failenv)) {
1302 g_warning("Error in execution: %s", f->error);
1306 return e_sexp_term_eval(f, f->tree);
1310 * e_sexp_encode_bool:
1314 * Encode a bool into an s-expression @s. Bools are
1315 * encoded using #t #f syntax.
1318 e_sexp_encode_bool(GString *s, gboolean state)
1321 g_string_append(s, " #t");
1323 g_string_append(s, " #f");
1327 * e_sexp_encode_string:
1328 * @s: Destination string.
1329 * @string: String expression.
1331 * Add a c string @string to the s-expression stored in
1332 * the gstring @s. Quotes are added, and special characters
1333 * are escaped appropriately.
1336 e_sexp_encode_string(GString *s, const char *string)
1345 g_string_append(s, " \"");
1346 while ( (c = *p++) ) {
1347 if (c=='\\' || c=='\"' || c=='\'')
1348 g_string_append_c(s, '\\');
1349 g_string_append_c(s, c);
1351 g_string_append(s, "\"");
1355 int main(int argc, char **argv)
1358 char *t = "(+ \"foo\" \"\\\"\" \"bar\" \"\\\\ blah \\x \")";
1365 e_sexp_add_variable(f, 0, "test", NULL);
1367 e_sexp_input_text(f, t, strlen(t));
1371 parse_dump_term(f->tree, 0);
1376 eval_dump_result(r, 0);
1378 printf("no result?|\n");