5 #include "xexprprivate.h"
9 * @short_description: An evaluator for the XEXPR language
11 * @include: libxexpr/xexpr.h
13 * An evaluator for the
14 * <ulink url="http://www.w3.org/TR/2000/NOTE-xexpr-20001121">XEXPR</ulink>
18 GSList *xexpr_extensions=NULL;
20 static XexprExtension libxexpr_extension={
21 LIBXEXPR_NS,_xexpr_libxexpr_function_evaluate
24 static XexprConstant *xexpr_do_string(Xexpr *xexpr,GSList *bindings,
25 GSList *args,GError **err);
26 static gboolean xexpr_defineable_id(const char *id,GError **err);
29 * xexpr_eval_error_quark:
31 * Registers an error quark for the libxexpr evaluator if necessary.
33 * Return value: The error quark used for libxexpr evaluator errors.
35 GQuark xexpr_eval_error_quark(void)
39 quark=g_quark_from_static_string("xexpr_eval_error");
44 * xexpr_register_extension:
45 * @extension: (transfer none): an #XexprExtension
47 * Registers an extension to handle the evaluation of functions and retrieval
48 * of variables in a new namespace.
50 * Return value: %TRUE if the extension was successfully registered
52 gboolean xexpr_register_extension(XexprExtension *extension)
56 static GStaticMutex mutex=G_STATIC_MUTEX_INIT;
57 g_static_mutex_lock(&mutex);
58 if (!xexpr_extensions)
59 xexpr_extensions=g_slist_prepend(xexpr_extensions,&libxexpr_extension);
60 if (!extension || !extension->ns || !*extension->ns ||
61 !strcmp(extension->ns,XEXPR_NS))
63 g_static_mutex_unlock(&mutex);
66 for(lnk=xexpr_extensions;lnk;lnk=lnk->next)
69 if (!strcmp(ext->ns,extension->ns))
71 g_static_mutex_unlock(&mutex);
75 extension=g_memdup(extension,sizeof(*extension));
76 extension->ns=g_strdup(extension->ns);
77 xexpr_extensions=g_slist_prepend(xexpr_extensions,extension);
78 g_static_mutex_unlock(&mutex);
83 * Returned constant should be freed iff evaluate is TRUE
85 static XexprConstant *xexpr_get_argument(Xexpr *xexpr,GSList *bindings,
86 GSList **args,const char *func,const char *id,gboolean evaluate,GError **err)
89 arg=xexpr_bindings_get(bindings,id);
99 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
100 "Missing \"%s\" argument to \"%s\"",id,func);
105 arg=xexpr_constant_evaluate(xexpr,arg,err);
109 static XexprConstant *xexpr_do_define(Xexpr *xexpr,GSList *bindings,
110 GSList *args,GError **err)
114 GSList *parameters=NULL;
115 XexprConstant *name,*params,*value,*arg;
116 XexprEnvironment *frame;
117 name=xexpr_get_argument(xexpr,bindings,&args,"define","name",TRUE,err);
120 if (name->type!=XEXPR_TYPE_STRING)
122 args=g_slist_prepend(NULL,name);
123 arg=xexpr_do_string(xexpr,NULL,args,NULL);
127 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
128 "Attempt to define a function with a non-string name \"%s\"",
130 xexpr_constant_free(arg);
133 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
134 "Attempt to define a function with a non-string name");
135 xexpr_constant_free(name);
138 else if (!_xexpr_validate_id(name->u.string,err) ||
139 !xexpr_defineable_id(name->u.string,err))
141 xexpr_constant_free(name);
144 params=xexpr_bindings_get(bindings,"args");
147 params=xexpr_constant_evaluate(xexpr,params,err);
148 if (params->type!=XEXPR_TYPE_STRING)
150 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
151 "Attempt to define a function with non-string argument names");
152 xexpr_constant_free(params);
153 xexpr_constant_free(name);
156 vector=g_strsplit_set(params->u.string," \t\n\r",-1);
157 for(i=0;vector[i];i++)
159 if (vector[i][0]>='0' && vector[i][0]<='9' ||
160 (vector[i][0]=='+' || vector[i][0]=='-') &&
161 vector[i][1]>='0' && vector[i][1]<='9')
163 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
164 "Attempt to define a function with non-string argument names");
165 xexpr_constant_free(params);
166 xexpr_constant_free(name);
168 g_slist_free(parameters);
171 parameters=g_slist_prepend(parameters,vector[i]);
173 parameters=g_slist_reverse(parameters);
175 value=xexpr_new_function(parameters,args);
176 g_slist_free(parameters);
179 frame=xexpr->environment;
180 xexpr->environment=frame->outer;
181 xexpr_var_new(xexpr,name->u.string,value);
182 xexpr->environment=frame;
183 xexpr_constant_free(name);
187 static XexprConstant *xexpr_do_print(Xexpr *xexpr,GSList *bindings,GSList *args,
190 gboolean newline=FALSE;
193 arg=xexpr_bindings_get(bindings,"newline");
194 if (arg && arg->type==XEXPR_TYPE_STRING && !strcmp(arg->u.string,"true"))
196 for(lnk=args;lnk;lnk=lnk->next)
201 case XEXPR_TYPE_FUNCTION:
203 * http://www.w3.org/TR/xexpr/#id-0003 implies that
204 * function objects are ignored in <print>.
207 case XEXPR_TYPE_INVOCATION:
208 printf("<%s/>",arg->u.invocation->function);
210 case XEXPR_TYPE_STRING:
211 fputs(arg->u.string,stdout);
213 case XEXPR_TYPE_INTEGER:
214 printf("%lld",arg->u.integer);
216 case XEXPR_TYPE_NUMBER:
217 printf("%lg",arg->u.number);
223 return xexpr_new_invocation(NULL,"true",NULL,NULL);
226 static XexprConstant *xexpr_do_println(Xexpr *xexpr,GSList *bindings,
227 GSList *args,GError **err)
230 return xexpr_new_invocation(NULL,"true",NULL,NULL);
233 static XexprConstant *xexpr_do_get(Xexpr *xexpr,GSList *bindings,
234 GSList *args,GError **err)
236 XexprConstant *name,*value;
237 name=xexpr_get_argument(xexpr,bindings,&args,"get","name",FALSE,err);
240 if (name->type==XEXPR_TYPE_STRING)
241 value=xexpr_var_get(xexpr,name->u.string);
245 value=xexpr_constant_dup(value);
247 value=xexpr_new_invocation(NULL,"nil",NULL,NULL);
251 static XexprConstant *xexpr_do_set(Xexpr *xexpr,GSList *bindings,
252 GSList *args,GError **err)
254 XexprConstant *name,*value;
255 name=xexpr_get_argument(xexpr,bindings,&args,"set","name",FALSE,err);
258 if (name->type!=XEXPR_TYPE_STRING)
260 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
261 "Attempt to bind a value a non-string name");
262 xexpr_constant_free(name);
265 else if (!_xexpr_validate_id(name->u.string,err) ||
266 !xexpr_defineable_id(name->u.string,err))
268 xexpr_constant_free(name);
271 value=xexpr_get_argument(xexpr,bindings,&args,"set","value",FALSE,err);
274 xexpr_var_set(xexpr,name->u.string,value);
275 return xexpr_constant_dup(value);
278 static XexprConstant *xexpr_do_expr(Xexpr *xexpr,GSList *bindings,GSList *args,
282 return xexpr_new_invocation(NULL,"nil",NULL,NULL);
285 return xexpr_constant_dup(args->data);
288 static XexprConstant *xexpr_do_return(Xexpr *xexpr,GSList *bindings,
289 GSList *args,GError **err)
291 XexprConstant *retval;
293 retval=xexpr_new_invocation(NULL,"nil",NULL,NULL);
296 retval=xexpr_constant_dup(args->data);
297 return xexpr_new_invocation_take_ownership(NULL,g_strdup("return"),NULL,
298 g_slist_prepend(NULL,retval));
301 static XexprConstant *xexpr_do_string(Xexpr *xexpr,GSList *bindings,
302 GSList *args,GError **err)
305 GString *str=g_string_new(NULL);
311 case XEXPR_TYPE_FUNCTION:
314 case XEXPR_TYPE_INVOCATION:
315 g_string_append_printf(str,"<%s/>",arg->u.invocation->function);
317 case XEXPR_TYPE_STRING:
318 g_string_append(str,arg->u.string);
320 case XEXPR_TYPE_INTEGER:
321 g_string_append_printf(str,"%lld",arg->u.integer);
323 case XEXPR_TYPE_NUMBER:
324 g_string_append_printf(str,"%lg",arg->u.number);
329 return xexpr_new_string_take_ownership(g_string_free(str,FALSE));
332 static XexprConstant *xexpr_do_integer(Xexpr *xexpr,GSList *bindings,
333 GSList *args,GError **err)
337 long long int value=0;
343 case XEXPR_TYPE_FUNCTION:
346 case XEXPR_TYPE_INVOCATION:
349 case XEXPR_TYPE_STRING:
350 value=g_ascii_strtoll(arg->u.string,NULL,0);
351 if (value==LLONG_MIN || value==LLONG_MAX)
353 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
354 "Integer overflow on %s",arg->u.string);
358 case XEXPR_TYPE_INTEGER:
359 value=arg->u.integer;
361 case XEXPR_TYPE_NUMBER:
362 if (!isfinite(arg->u.number))
364 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
365 "%lg is not finite",arg->u.number);
368 d=nearbyint(arg->u.number);
369 if (d<=LLONG_MIN || d>=LLONG_MAX)
371 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
372 "Integer overflow on %lg",arg->u.number);
375 value=(long long int)d;
380 return xexpr_new_integer(value);
383 static XexprConstant *xexpr_do_float(Xexpr *xexpr,GSList *bindings,
384 GSList *args,GError **err)
387 double value=0.0/0.0;
393 case XEXPR_TYPE_FUNCTION:
396 case XEXPR_TYPE_INVOCATION:
399 case XEXPR_TYPE_STRING:
400 value=g_ascii_strtod(arg->u.string,NULL);
401 if (value==HUGE_VAL || value==-HUGE_VAL)
403 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
404 "Numeric overflow on %s",arg->u.string);
408 case XEXPR_TYPE_INTEGER:
409 if (arg->u.integer<-DBL_MAX || arg->u.integer>DBL_MAX)
411 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
412 "Numeric overflow on %lld",arg->u.integer);
415 value=(double)arg->u.integer;
417 case XEXPR_TYPE_NUMBER:
423 return xexpr_new_number(value);
426 static XexprConstant *xexpr_do_true(Xexpr *xexpr,GSList *bindings,GSList *args,
429 return xexpr_new_invocation(NULL,"true",NULL,NULL);
432 static XexprConstant *xexpr_do_false(Xexpr *xexpr,GSList *bindings,GSList *args,
435 return xexpr_new_invocation(NULL,"false",NULL,NULL);
438 static XexprConstant *xexpr_do_nil(Xexpr *xexpr,GSList *bindings,GSList *args,
441 return xexpr_new_invocation(NULL,"nil",NULL,NULL);
444 typedef struct xexpr_accumulator {
448 const char *result_binding;
449 XexprConstant *arg,*result;
452 static gboolean xexpr_accumulator_init(XexprAccumulator *accumulator,
453 Xexpr *xexpr,GSList *args,gboolean bind_result,GError **err)
456 accumulator->xexpr=xexpr;
457 accumulator->args=args;
458 accumulator->arg=NULL;
459 accumulator->first=TRUE;
460 if (!accumulator->args)
462 accumulator->result_binding=NULL;
463 accumulator->result=xexpr_new_invocation(NULL,"nil",NULL,NULL);
466 arg=accumulator->args->data;
468 * If arg invokes a function with no bindings and no arguments
469 * then the result is accumulated in the function itself.
470 * This allows constructs such as:
471 * <subtract><x/>1</subtract>
472 * as a shorthand for:
473 * <set name="x"><subtract><get><x/></get>1</subtract></set>
474 * This is implied by http://www.w3.org/TR/xexpr/#id-0045
476 * Note that since the value accumulates:
477 * <add x="1"><x/><x/><x/></add>
478 * results in 4 rather than 3.
480 if (bind_result && arg->type==XEXPR_TYPE_INVOCATION &&
481 !arg->u.invocation->bindings && !arg->u.invocation->constants)
482 accumulator->result_binding=arg->u.invocation->function;
484 accumulator->result_binding=NULL;
485 accumulator->result=xexpr_constant_evaluate(xexpr,arg,err);
486 while(accumulator->result && accumulator->result->type==XEXPR_TYPE_FUNCTION)
488 arg=xexpr_constant_evaluate(xexpr,accumulator->result,err);
489 xexpr_constant_free(accumulator->result);
490 accumulator->result=arg;
492 return !!accumulator->result;
495 static gboolean xexpr_accumulator_next(XexprAccumulator *accumulator)
497 if (accumulator->result_binding && !accumulator->first)
499 xexpr_var_set(accumulator->xexpr,accumulator->result_binding,
500 accumulator->result);
501 if (xexpr_is_tracing(accumulator->xexpr,accumulator->result_binding))
503 printf("\nChanged variable %s\n",accumulator->result_binding);
504 xexpr_stack_dump(accumulator->xexpr,stdout);
507 accumulator->args=accumulator->args->next;
508 accumulator->first=FALSE;
509 return !!accumulator->args;
512 static XexprConstant *xexpr_accumulator_get(XexprAccumulator *accumulator,
515 if (accumulator->arg)
516 xexpr_constant_free(accumulator->arg);
517 accumulator->arg=xexpr_constant_evaluate(accumulator->xexpr,
518 accumulator->args->data,err);
519 return accumulator->arg;
522 static XexprConstant *xexpr_accumulator_finish(XexprAccumulator *accumulator)
524 if (accumulator->arg)
525 xexpr_constant_free(accumulator->arg);
526 return accumulator->result;
529 static void xexpr_accumulator_abort(XexprAccumulator *accumulator)
531 xexpr_constant_free(xexpr_accumulator_finish(accumulator));
534 static XexprConstant *xexpr_do_add(Xexpr *xexpr,GSList *bindings,GSList *args,
539 XexprAccumulator accumulator;
540 if (!xexpr_accumulator_init(&accumulator,xexpr,args,TRUE,err))
542 while(xexpr_accumulator_next(&accumulator))
544 arg=xexpr_accumulator_get(&accumulator,err);
547 xexpr_accumulator_abort(&accumulator);
550 switch(accumulator.result->type)
552 case XEXPR_TYPE_INVOCATION:
553 case XEXPR_TYPE_FUNCTION:
554 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
555 "Attempt to perform arithmetic op on a function");
556 xexpr_accumulator_abort(&accumulator);
559 case XEXPR_TYPE_STRING:
562 case XEXPR_TYPE_FUNCTION:
563 case XEXPR_TYPE_INVOCATION:
564 g_set_error(err,XEXPR_EVAL_ERROR,
565 XEXPR_EVAL_ERROR_FAILED,
566 "Attempt to perform arithmetic op on a function");
567 xexpr_accumulator_abort(&accumulator);
569 case XEXPR_TYPE_STRING:
570 str=g_strconcat(accumulator.result->u.string,
572 g_free(accumulator.result->u.string);
573 accumulator.result->u.string=str;
575 case XEXPR_TYPE_INTEGER:
576 str=g_strdup_printf("%s%lld",
577 accumulator.result->u.string,arg->u.integer);
578 g_free(accumulator.result->u.string);
579 accumulator.result->u.string=str;
581 case XEXPR_TYPE_NUMBER:
582 str=g_strdup_printf("%s%lg",
583 accumulator.result->u.string,arg->u.number);
584 g_free(accumulator.result->u.string);
585 accumulator.result->u.string=str;
589 case XEXPR_TYPE_INTEGER:
590 if (arg->type==XEXPR_TYPE_INTEGER)
592 accumulator.result->u.integer+=arg->u.integer;
595 else if (arg->type==XEXPR_TYPE_NUMBER)
597 accumulator.result->type=XEXPR_TYPE_NUMBER;
598 accumulator.result->u.number=accumulator.result->u.integer;
601 case XEXPR_TYPE_NUMBER:
602 if (arg->type==XEXPR_TYPE_INTEGER)
603 accumulator.result->u.number+=arg->u.integer;
604 else if (arg->type==XEXPR_TYPE_NUMBER)
605 accumulator.result->u.number+=arg->u.number;
608 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
609 "Attempt to add non-numeric to numeric quantity");
610 xexpr_accumulator_abort(&accumulator);
616 return xexpr_accumulator_finish(&accumulator);
619 static XexprConstant *xexpr_do_subtract(Xexpr *xexpr,GSList *bindings,
620 GSList *args,GError **err)
623 XexprAccumulator accumulator;
624 if (!xexpr_accumulator_init(&accumulator,xexpr,args,TRUE,err))
626 while(xexpr_accumulator_next(&accumulator))
628 arg=xexpr_accumulator_get(&accumulator,err);
631 xexpr_accumulator_abort(&accumulator);
634 if (arg->type!=XEXPR_TYPE_INTEGER && arg->type!=XEXPR_TYPE_NUMBER)
637 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
638 "Attempt to perform subtraction on a non-numeric quantity");
639 xexpr_accumulator_abort(&accumulator);
642 switch(accumulator.result->type)
644 case XEXPR_TYPE_INTEGER:
645 if (arg->type==XEXPR_TYPE_INTEGER)
647 accumulator.result->u.integer-=arg->u.integer;
652 accumulator.result->type=XEXPR_TYPE_NUMBER;
653 accumulator.result->u.number=accumulator.result->u.integer;
656 case XEXPR_TYPE_NUMBER:
657 if (accumulator.arg->type==XEXPR_TYPE_INTEGER)
658 accumulator.result->u.number-=arg->u.integer;
660 accumulator.result->u.number-=arg->u.number;
666 return xexpr_accumulator_finish(&accumulator);
669 static XexprConstant *xexpr_do_multiply(Xexpr *xexpr,GSList *bindings,
670 GSList *args,GError **err)
673 XexprAccumulator accumulator;
674 if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err))
676 while(xexpr_accumulator_next(&accumulator))
678 arg=xexpr_accumulator_get(&accumulator,err);
681 xexpr_accumulator_abort(&accumulator);
684 if (arg->type!=XEXPR_TYPE_INTEGER && arg->type!=XEXPR_TYPE_NUMBER)
686 GString *str=g_string_new(NULL);
688 xexpr_constant_dump_string(arg,str);
689 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
690 "Attempt to perform multiply on a non-numeric quantity: %s",
692 g_string_free(str,TRUE);
693 xexpr_accumulator_abort(&accumulator);
696 switch(accumulator.result->type)
698 case XEXPR_TYPE_INTEGER:
699 if (arg->type==XEXPR_TYPE_INTEGER)
701 accumulator.result->u.integer*=arg->u.integer;
706 accumulator.result->type=XEXPR_TYPE_NUMBER;
707 accumulator.result->u.number=accumulator.result->u.integer;
710 case XEXPR_TYPE_NUMBER:
711 if (arg->type==XEXPR_TYPE_INTEGER)
712 accumulator.result->u.number*=arg->u.integer;
714 accumulator.result->u.number*=arg->u.number;
720 return xexpr_accumulator_finish(&accumulator);
723 static XexprConstant *xexpr_do_divide(Xexpr *xexpr,GSList *bindings,
724 GSList *args,GError **err)
728 XexprAccumulator accumulator;
729 if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err))
731 while(xexpr_accumulator_next(&accumulator))
733 arg=xexpr_accumulator_get(&accumulator,err);
736 xexpr_accumulator_abort(&accumulator);
739 if (arg->type!=XEXPR_TYPE_INTEGER && arg->type!=XEXPR_TYPE_NUMBER)
742 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
743 "Attempt to perform divide on a non-numeric quantity");
744 xexpr_accumulator_abort(&accumulator);
747 switch(accumulator.result->type)
749 case XEXPR_TYPE_INTEGER:
750 if (arg->type==XEXPR_TYPE_INTEGER)
752 r=accumulator.result->u.integer/arg->u.integer;
753 if (r*arg->u.integer==accumulator.result->u.integer)
755 accumulator.result->u.integer=r;
759 accumulator.result->type=XEXPR_TYPE_NUMBER;
760 accumulator.result->u.number=accumulator.result->u.integer;
762 case XEXPR_TYPE_NUMBER:
763 if (arg->type==XEXPR_TYPE_INTEGER)
764 accumulator.result->u.number/=arg->u.integer;
766 accumulator.result->u.number/=arg->u.number;
772 return xexpr_accumulator_finish(&accumulator);
776 * xexpr_constant_cast:
777 * @constant: an #XexprConstant to cast
778 * @to: type to cast @constant to
780 * Attempt to perform an implicit cast of @constant to the given type @to.
781 * Implicit casting can only be performed between the two numeric types
782 * and then only where the quantity can be represented without loss of
785 * Return value: %TRUE if @constant is now of type @to.
787 gboolean xexpr_constant_cast(XexprConstant *constant,XexprType to)
790 if (constant->type==to)
792 if (constant->type==XEXPR_TYPE_NUMBER && to==XEXPR_TYPE_INTEGER &&
793 constant->u.number>=LLONG_MIN && constant->u.number<=LLONG_MAX &&
794 !modf(constant->u.number,&dummy))
796 constant->type=XEXPR_TYPE_INTEGER;
797 constant->u.integer=constant->u.number;
800 else if (constant->type==XEXPR_TYPE_INTEGER && to==XEXPR_TYPE_NUMBER &&
801 constant->u.integer+1.0!=(double)constant->u.integer &&
802 constant->u.integer-1.0!=(double)constant->u.integer)
804 constant->type=XEXPR_TYPE_NUMBER;
805 constant->u.number=constant->u.integer;
812 static gboolean xexpr_constant_boolean(Xexpr *xexpr,XexprConstant *constant,
816 XexprConstant *result;
817 switch (constant->type)
819 case XEXPR_TYPE_NUMBER:
820 return !(constant->u.number==0);
821 case XEXPR_TYPE_INTEGER:
822 return !!constant->u.integer;
823 case XEXPR_TYPE_STRING:
824 return !!*constant->u.string;
825 case XEXPR_TYPE_INVOCATION:
826 return strcmp(constant->u.invocation->function,"false") &&
827 strcmp(constant->u.invocation->function,"nil");
828 case XEXPR_TYPE_FUNCTION:
830 * See http://www.w3.org/TR/xexpr/#id-0038
832 result=xexpr_constant_evaluate(xexpr,constant,err);
835 retval=xexpr_constant_boolean(xexpr,result,err);
836 xexpr_constant_free(result);
843 * Returns: 0 if equal, <0 if value1 < value2, >0 if value1 > value2,
844 * NaN if value1 is not comparible with value2.
846 static double xexpr_constant_compare(Xexpr *xexpr,XexprConstant *v1,
849 double retval=0.0/0.0;
850 XexprConstant *value1,*value2;
851 value1=xexpr_constant_evaluate(xexpr,v1,NULL);
853 value1=xexpr_constant_dup(v1);
854 while(value1->type==XEXPR_TYPE_FUNCTION)
856 v1=xexpr_constant_evaluate(xexpr,value1,NULL);
859 xexpr_constant_free(value1);
865 value2=xexpr_constant_evaluate(xexpr,v2,NULL);
867 value2=xexpr_constant_dup(v2);
868 while(value2->type==XEXPR_TYPE_FUNCTION)
870 v2=xexpr_constant_evaluate(xexpr,value2,NULL);
873 xexpr_constant_free(value2);
879 if (value1->type!=value2->type)
881 if (!xexpr_constant_cast(value1,value2->type) &&
882 !xexpr_constant_cast(value2,value1->type))
884 xexpr_constant_free(value1);
885 xexpr_constant_free(value2);
891 case XEXPR_TYPE_FUNCTION:
894 case XEXPR_TYPE_INVOCATION:
895 g_warn_if_fail(value1->u.invocation->bindings==NULL);
896 g_warn_if_fail(value2->u.invocation->bindings==NULL);
897 g_warn_if_fail(value1->u.invocation->constants==NULL);
898 g_warn_if_fail(value2->u.invocation->constants==NULL);
899 retval=strcmp(value1->u.invocation->function,
900 value2->u.invocation->function);
902 case XEXPR_TYPE_STRING:
903 retval=strcmp(value1->u.string,value2->u.string);
905 case XEXPR_TYPE_INTEGER:
906 retval=value1->u.integer-value2->u.integer;
908 case XEXPR_TYPE_NUMBER:
909 retval=value1->u.number-value2->u.number;
912 xexpr_constant_free(value1);
913 xexpr_constant_free(value2);
917 static XexprConstant *xexpr_do_eq(Xexpr *xexpr,GSList *bindings,GSList *args,
920 XexprConstant *arg,*standard=NULL;
926 else if (xexpr_constant_compare(xexpr,standard,arg))
927 return xexpr_new_invocation(NULL,"false",NULL,NULL);
930 return xexpr_new_invocation(NULL,"true",NULL,NULL);
933 static XexprConstant *xexpr_do_neq(Xexpr *xexpr,GSList *bindings,GSList *args,
941 for(lnk=args->next;lnk;lnk=lnk->next)
942 if (!xexpr_constant_compare(xexpr,arg,lnk->data))
943 return xexpr_new_invocation(NULL,"false",NULL,NULL);
946 return xexpr_new_invocation(NULL,"true",NULL,NULL);
949 static XexprConstant *xexpr_do_leq(Xexpr *xexpr,GSList *bindings,GSList *args,
952 XexprConstant *arg,*standard=NULL;
956 if (standard && !(xexpr_constant_compare(xexpr,standard,arg)<=0))
957 return xexpr_new_invocation(NULL,"false",NULL,NULL);
961 return xexpr_new_invocation(NULL,"true",NULL,NULL);
964 static XexprConstant *xexpr_do_geq(Xexpr *xexpr,GSList *bindings,GSList *args,
967 XexprConstant *arg,*standard=NULL;
971 if (standard && !(xexpr_constant_compare(xexpr,standard,arg)>=0))
972 return xexpr_new_invocation(NULL,"false",NULL,NULL);
976 return xexpr_new_invocation(NULL,"true",NULL,NULL);
979 static XexprConstant *xexpr_do_lt(Xexpr *xexpr,GSList *bindings,GSList *args,
982 XexprConstant *arg,*standard=NULL;
986 if (standard && !(xexpr_constant_compare(xexpr,standard,arg)<0))
987 return xexpr_new_invocation(NULL,"false",NULL,NULL);
991 return xexpr_new_invocation(NULL,"true",NULL,NULL);
994 static XexprConstant *xexpr_do_gt(Xexpr *xexpr,GSList *bindings,GSList *args,
997 XexprConstant *arg,*standard=NULL;
1001 if (standard && !(xexpr_constant_compare(xexpr,standard,arg)>0))
1002 return xexpr_new_invocation(NULL,"false",NULL,NULL);
1006 return xexpr_new_invocation(NULL,"true",NULL,NULL);
1009 static XexprConstant *xexpr_do_and(Xexpr *xexpr,GSList *bindings,GSList *args,
1012 GError *tmp_err=NULL;
1014 XexprAccumulator accumulator;
1016 return xexpr_new_invocation(NULL,"true",NULL,NULL);
1017 if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err))
1019 if (!xexpr_constant_boolean(xexpr,accumulator.result,&tmp_err))
1021 xexpr_accumulator_abort(&accumulator);
1024 g_propagate_error(err,tmp_err);
1028 return xexpr_new_invocation(NULL,"false",NULL,NULL);
1030 while(xexpr_accumulator_next(&accumulator))
1032 arg=xexpr_accumulator_get(&accumulator,err);
1035 xexpr_accumulator_abort(&accumulator);
1038 if (!xexpr_constant_boolean(xexpr,arg,&tmp_err))
1040 xexpr_accumulator_abort(&accumulator);
1043 g_propagate_error(err,tmp_err);
1047 return xexpr_new_invocation(NULL,"false",NULL,NULL);
1050 xexpr_accumulator_abort(&accumulator);
1051 return xexpr_new_invocation(NULL,"true",NULL,NULL);
1054 static XexprConstant *xexpr_do_or(Xexpr *xexpr,GSList *bindings,GSList *args,
1057 GError *tmp_err=NULL;
1059 XexprAccumulator accumulator;
1061 return xexpr_new_invocation(NULL,"true",NULL,NULL);
1062 if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err))
1064 if (xexpr_constant_boolean(xexpr,accumulator.result,&tmp_err))
1066 xexpr_accumulator_abort(&accumulator);
1067 return xexpr_new_invocation(NULL,"true",NULL,NULL);
1071 xexpr_accumulator_abort(&accumulator);
1072 g_propagate_error(err,tmp_err);
1075 while(xexpr_accumulator_next(&accumulator))
1077 arg=xexpr_accumulator_get(&accumulator,err);
1080 xexpr_accumulator_abort(&accumulator);
1083 if (xexpr_constant_boolean(xexpr,arg,&tmp_err))
1085 xexpr_accumulator_abort(&accumulator);
1086 return xexpr_new_invocation(NULL,"true",NULL,NULL);
1090 xexpr_accumulator_abort(&accumulator);
1091 g_propagate_error(err,tmp_err);
1095 xexpr_accumulator_abort(&accumulator);
1096 return xexpr_new_invocation(NULL,"false",NULL,NULL);
1100 * <not> is a misnomer, http://www.w3.org/TR/xexpr/#id-0040
1101 * makes it clear that, except in the trivial case of no arguments,
1102 * <not> is simply the negation of <and>.
1104 static XexprConstant *xexpr_do_not(Xexpr *xexpr,GSList *bindings,GSList *args,
1108 XexprConstant *result;
1110 return xexpr_new_invocation(NULL,"true",NULL,NULL);
1111 result=xexpr_do_and(xexpr,bindings,args,err);
1114 test=xexpr_constant_boolean(xexpr,result,NULL);
1115 xexpr_constant_free(result);
1116 return xexpr_new_invocation(NULL,test?"false":"true",NULL,NULL);
1119 static XexprConstant *xexpr_do_if(Xexpr *xexpr,GSList *bindings,GSList *args,
1122 GError *tmp_err=NULL;
1125 if (g_slist_length(args)<2)
1127 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
1128 "<if> requires at least 2 arguments to be passed");
1131 arg=xexpr_constant_evaluate(xexpr,args->data,err);
1134 test=xexpr_constant_boolean(xexpr,arg,&tmp_err);
1137 g_propagate_error(err,tmp_err);
1140 xexpr_constant_free(arg);
1142 return xexpr_constant_evaluate(xexpr,args->next->data,err);
1143 else if (args->next->next)
1144 return xexpr_constant_evaluate(xexpr,args->next->next->data,err);
1146 return xexpr_new_invocation(NULL,"nil",NULL,NULL);
1149 static XexprConstant *xexpr_do_switch(Xexpr *xexpr,GSList *bindings,
1150 GSList *args,GError **err)
1152 GError *tmp_err=NULL;
1154 XexprConstant *case_arg,*arg;
1158 case_arg=args->data;
1159 if (case_arg->type!=XEXPR_TYPE_INVOCATION ||
1160 strcmp(case_arg->u.invocation->function,"case"))
1162 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
1163 "<switch> requires a list of <case> expressions");
1166 lnk=case_arg->u.invocation->constants;
1169 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
1170 "<case> requires a test expression");
1173 arg=xexpr_constant_evaluate(xexpr,lnk->data,err);
1176 test=xexpr_constant_boolean(xexpr,arg,&tmp_err);
1179 g_propagate_error(err,tmp_err);
1182 xexpr_constant_free(arg);
1189 xexpr_constant_free(arg);
1190 arg=xexpr_constant_evaluate(xexpr,lnk->data,err);
1196 arg=xexpr_new_invocation(NULL,"nil",NULL,NULL);
1201 return xexpr_new_invocation(NULL,"nil",NULL,NULL);
1204 static XexprConstant *xexpr_do_while(Xexpr *xexpr,GSList *bindings,GSList *args,
1207 GError *tmp_err=NULL;
1209 XexprConstant *arg,*result;
1210 if (g_slist_length(args)!=2)
1212 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
1213 "<while> takes 2 arguments");
1216 result=xexpr_new_invocation(NULL,"nil",NULL,NULL);
1219 arg=xexpr_constant_evaluate(xexpr,args->data,err);
1222 xexpr_constant_free(result);
1225 test=xexpr_constant_boolean(xexpr,arg,&tmp_err);
1228 g_propagate_error(err,tmp_err);
1231 xexpr_constant_free(arg);
1234 xexpr_constant_free(result);
1235 result=xexpr_constant_evaluate(xexpr,args->next->data,err);
1243 static XexprConstant *xexpr_do_do(Xexpr *xexpr,GSList *bindings,GSList *args,
1246 GError *tmp_err=NULL;
1248 XexprConstant *arg,*result;
1249 if (g_slist_length(args)!=2)
1251 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
1252 "<do> takes 2 arguments");
1259 xexpr_constant_free(result);
1260 result=xexpr_constant_evaluate(xexpr,args->data,err);
1263 arg=xexpr_constant_evaluate(xexpr,args->next->data,err);
1266 xexpr_constant_free(result);
1269 test=xexpr_constant_boolean(xexpr,arg,&tmp_err);
1272 g_propagate_error(err,tmp_err);
1275 xexpr_constant_free(arg);
1280 static struct xexpr_builtin {
1282 gboolean evaluate_args;
1283 XexprConstant *(*func)(Xexpr *xexpr,GSList *bindings,GSList *args,
1285 } xexpr_builtins[]={
1286 { "define", FALSE, xexpr_do_define },
1287 { "print", TRUE, xexpr_do_print },
1288 { "println", TRUE, xexpr_do_println },
1289 { "get", TRUE, xexpr_do_get },
1290 { "set", TRUE, xexpr_do_set },
1291 { "expr", TRUE, xexpr_do_expr },
1292 { "xexpr", TRUE, xexpr_do_expr },
1293 { "return", TRUE, xexpr_do_return },
1294 { "string", TRUE, xexpr_do_string },
1295 { "integer", TRUE, xexpr_do_integer },
1296 { "float", TRUE, xexpr_do_float },
1297 { "true", TRUE, xexpr_do_true },
1298 { "false", TRUE, xexpr_do_false },
1299 { "nil", TRUE, xexpr_do_nil },
1300 { "add", FALSE, xexpr_do_add },
1301 { "subtract", FALSE, xexpr_do_subtract },
1302 { "multiply", FALSE, xexpr_do_multiply },
1303 { "divide", FALSE, xexpr_do_divide },
1304 { "eq", TRUE, xexpr_do_eq },
1305 { "neq", TRUE, xexpr_do_neq },
1306 { "leq", TRUE, xexpr_do_leq },
1307 { "geq", TRUE, xexpr_do_geq },
1308 { "lt", TRUE, xexpr_do_lt },
1309 { "gt", TRUE, xexpr_do_gt },
1310 { "and", FALSE, xexpr_do_and },
1311 { "or", FALSE, xexpr_do_or },
1312 { "not", FALSE, xexpr_do_not },
1313 { "if", FALSE, xexpr_do_if },
1314 { "switch", FALSE, xexpr_do_switch },
1315 { "while", FALSE, xexpr_do_while },
1316 { "do", FALSE, xexpr_do_do },
1319 static gboolean xexpr_defineable_id(const char *id,GError **err)
1322 for(i=0;i<G_N_ELEMENTS(xexpr_builtins);i++)
1323 if (!strcmp(xexpr_builtins[i].id,id))
1325 g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_EVAL_ERROR_FAILED,
1326 "Can't define reserved XEXPR ID \"%s\"",id);
1332 static XexprConstant *xexpr_closure(Xexpr *xexpr,XexprConstant *constant,
1336 XexprConstant *result,*tmp;
1337 g_return_val_if_fail(constant->type==XEXPR_TYPE_FUNCTION,NULL);
1339 for(lnk=constant->u.function->constants;lnk;lnk=lnk->next)
1342 xexpr_constant_free(result);
1343 result=xexpr_constant_evaluate(xexpr,lnk->data,err);
1346 if (result->type==XEXPR_TYPE_INVOCATION &&
1347 !strcmp(result->u.invocation->function,"return"))
1349 lnk=g_slist_last(result->u.invocation->constants);
1350 tmp=xexpr_constant_dup(lnk->data);
1351 xexpr_constant_free(result);
1357 result=xexpr_new_invocation(NULL,"nil",NULL,NULL);
1361 static XexprConstant *xexpr_function_evaluate(Xexpr *xexpr,const char *ns,
1362 const char *id,GSList *bindings,GSList *args,GError **err)
1365 gboolean evaluate_args;
1366 XexprBinding *binding;
1367 XexprExtension *ext;
1368 XexprConstant *value,*function_def,*result;
1369 const char *unbound_parameter;
1370 GSList *unbound_args=args,*lnk,*actual,*unbound_parameters;
1373 for(lnk=xexpr_extensions;lnk;lnk=lnk->next)
1376 if (!strcmp(ext->ns,ns))
1377 return ext->function_evaluate(xexpr,ns,id,bindings,args,err);
1379 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
1380 "Unknown namespace \"%s\"",ns);
1383 for(builtin=0;builtin<G_N_ELEMENTS(xexpr_builtins);builtin++)
1384 if (!strcmp(xexpr_builtins[builtin].id,id))
1386 evaluate_args=xexpr_builtins[builtin].evaluate_args;
1389 if (builtin==G_N_ELEMENTS(xexpr_builtins))
1391 function_def=xexpr_var_get(xexpr,id);
1394 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
1395 "Undefined function: \"%s\"",id);
1398 else if (function_def->type!=XEXPR_TYPE_FUNCTION)
1399 return xexpr_constant_evaluate(xexpr,function_def,err);
1400 unbound_parameters=g_slist_copy(function_def->u.function->args);
1406 unbound_parameters=NULL;
1408 for(lnk=bindings;lnk;lnk=lnk->next)
1411 actual=g_slist_find_custom(unbound_parameters,binding->id,
1412 (GCompareFunc)strcmp);
1414 unbound_parameters=g_slist_delete_link(unbound_parameters,actual);
1415 xexpr_var_new(xexpr,binding->id,binding->value);
1419 for(lnk=unbound_parameters;lnk;lnk=lnk->next)
1421 unbound_parameter=lnk->data;
1422 value=xexpr_var_get(xexpr,unbound_parameter);
1424 xexpr_var_new(xexpr,unbound_parameter,value);
1427 value=xexpr_new_invocation(NULL,"nil",NULL,NULL);
1428 xexpr_var_new(xexpr,unbound_parameter,value);
1429 xexpr_constant_free(value);
1433 while(unbound_parameters)
1435 unbound_parameter=unbound_parameters->data;
1440 value=xexpr_constant_evaluate(xexpr,unbound_args->data,err);
1443 g_slist_free(unbound_parameters);
1446 xexpr_var_set(xexpr,unbound_parameter,value);
1447 xexpr_constant_free(value);
1451 value=unbound_args->data;
1452 xexpr_var_new(xexpr,unbound_parameter,value);
1454 unbound_args=unbound_args->next;
1456 g_slist_delete_link(unbound_parameters,unbound_parameters);
1460 g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
1461 "No actual value to bind to parameter %s of function %s",
1462 unbound_parameter,id);
1463 g_slist_free(unbound_parameters);
1472 value=xexpr_constant_evaluate(xexpr,unbound_args->data,err);
1475 args=g_slist_prepend(args,value);
1476 unbound_args=unbound_args->next;
1478 args=g_slist_reverse(args);
1481 result=xexpr_closure(xexpr,function_def,err);
1483 result=xexpr_builtins[builtin].func(xexpr,bindings,args,err);
1486 g_slist_foreach(args,(GFunc)xexpr_constant_free,NULL);
1493 * xexpr_constant_evaluate:
1495 * @constant: the #XexprConstant to evaluate
1496 * @err: (allow-none): location to store error, or %NULL
1498 * Evaluate an XEXPR expression. Typically, an expression will evaluate to
1499 * one of the basic types: string, integer or float. However, the XEXPR
1500 * language specification states that <define> returns a function
1501 * object (ie., an #XexprConstant with type %XEXPR_TYPE_FUNCTION).
1502 * If such a function object is passed to xexpr_constant_evaluate(), then
1503 * the function definition will be evaluated. If the function takes
1504 * arguments, then these will be taken as <nil>.
1506 * The returned expresion should be freed with xexpr_constant_free()
1507 * when no longer needed.
1509 * Return value: (transfer full): The evaluated result, or %NULL on error
1511 XexprConstant *xexpr_constant_evaluate(Xexpr *xexpr,XexprConstant *constant,
1515 XexprConstant *result,*tmp;
1516 switch(constant->type)
1518 case XEXPR_TYPE_FUNCTION:
1520 * It's not clear how function objects should be evaluated.
1521 * We choose to invoke them with all arguments as <nil/>.
1522 * Note that this means that <get>x</get> will not error
1523 * out if x is defined as taking arguments whereas <x/>
1524 * will. http://www.w3.org/TR/xexpr/#id-0014 states that
1525 * these have the same effect in _most_ cases which implies
1526 * that there are differences in some cases.
1528 _xexpr_push_environment(xexpr,NULL);
1529 tmp=xexpr_new_invocation(NULL,"nil",NULL,NULL);
1530 for(lnk=constant->u.function->args;lnk;lnk=lnk->next)
1531 xexpr_var_new(xexpr,lnk->data,tmp);
1532 xexpr_constant_free(tmp);
1533 result=xexpr_closure(xexpr,constant,err);
1534 _xexpr_pop_environment(xexpr);
1537 case XEXPR_TYPE_INVOCATION:
1538 _xexpr_push_environment(xexpr,constant->u.invocation->function);
1539 result=xexpr_function_evaluate(xexpr,
1540 constant->u.invocation->ns,
1541 constant->u.invocation->function,
1542 constant->u.invocation->bindings,
1543 constant->u.invocation->constants,err);
1544 _xexpr_pop_environment(xexpr);
1547 case XEXPR_TYPE_STRING:
1548 return xexpr_new_string(constant->u.string,-1);
1550 case XEXPR_TYPE_INTEGER:
1551 return xexpr_new_integer(constant->u.integer);
1553 case XEXPR_TYPE_NUMBER:
1554 return xexpr_new_number(constant->u.number);
1562 * @xexpr: an #Xexpr to evaluate
1563 * @err: (allow-none): location to store error, or %NULL
1565 * Evaluate an XEXPR expression. Typically, an expression will evaluate to
1566 * one of the basic types: string, integer or float. However, the XEXPR
1567 * language specification states that <define> returns a function
1568 * object (ie., an #XexprConstant with type %XEXPR_TYPE_FUNCTION).
1569 * If such a function object is passed to xexpr_evaluate(), then
1570 * the function definition will be evaluated. If the function takes
1571 * arguments, then these will be taken as <nil>.
1573 * The returned expresion should be freed with xexpr_free()
1574 * when no longer needed.
1576 * Return value: (transfer full): The evaluated result, or %NULL on error
1578 Xexpr *xexpr_evaluate(Xexpr *xexpr,GError **err)
1581 XexprConstant *constant,*result;
1583 results=xexpr_sub(xexpr);
1584 for(lnk=xexpr->constants;lnk;lnk=lnk->next)
1587 result=xexpr_constant_evaluate(xexpr,constant,err);
1590 xexpr_free(results);
1594 results->constants=g_slist_prepend(results->constants,result);
1596 results->constants=g_slist_reverse(results->constants);
1602 * @xexpr: an #Xexpr to test
1603 * @err: (allow-none): location to store error, or %NULL
1605 * Test an expression by looking at the last constant in the expression.
1606 * Numerical constants are treated as <true> if they are non-zero,
1607 * string constants are treated as <true> if they are non-empty,
1608 * function invocations are treated as <true> unless they are
1609 * <false> or <nil>, function definitions are recursively
1610 * evaluated before they are tested.
1612 * Return value: %TRUE if the expression is equivalent to <true>.
1614 gboolean xexpr_test(Xexpr *xexpr,GError **err)
1617 XexprConstant *constant;
1618 lnk=g_slist_last(xexpr->constants);
1620 return xexpr_constant_boolean(xexpr,constant,err);