libxexpr/xexpreval.c
author ali <ali@juiblex.co.uk>
Wed Oct 10 22:58:21 2012 +0100 (2012-10-10)
changeset 0 bc8c9a11cbfc
permissions -rw-r--r--
Initial version
     1 #include <stdlib.h>
     2 #include <string.h>
     3 #include <math.h>
     4 #include <xexpr.h>
     5 #include "xexprprivate.h"
     6 
     7 /**
     8  * SECTION:xexpreval
     9  * @short_description: An evaluator for the XEXPR language
    10  * @stability: Stable
    11  * @include: libxexpr/xexpr.h
    12  *
    13  * An evaluator for the
    14  * <ulink url="http://www.w3.org/TR/2000/NOTE-xexpr-20001121">XEXPR</ulink>
    15  * language.
    16  */
    17 
    18 GSList *xexpr_extensions=NULL;
    19 
    20 static XexprExtension libxexpr_extension={
    21     LIBXEXPR_NS,_xexpr_libxexpr_function_evaluate
    22 };
    23 
    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);
    27 
    28 /**
    29  * xexpr_eval_error_quark:
    30  *
    31  * Registers an error quark for the libxexpr evaluator if necessary.
    32  *
    33  * Return value: The error quark used for libxexpr evaluator errors.
    34  */
    35 GQuark xexpr_eval_error_quark(void)
    36 {
    37     static GQuark quark;
    38     if (!quark)
    39 	quark=g_quark_from_static_string("xexpr_eval_error");
    40     return quark;
    41 }
    42 
    43 /**
    44  * xexpr_register_extension:
    45  * @extension: (transfer none): an #XexprExtension
    46  *
    47  * Registers an extension to handle the evaluation of functions and retrieval
    48  * of variables in a new namespace.
    49  *
    50  * Return value: %TRUE if the extension was successfully registered
    51  */
    52 gboolean xexpr_register_extension(XexprExtension *extension)
    53 {
    54     GSList *lnk;
    55     XexprExtension *ext;
    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))
    62     {
    63 	g_static_mutex_unlock(&mutex);
    64 	return FALSE;
    65     }
    66     for(lnk=xexpr_extensions;lnk;lnk=lnk->next)
    67     {
    68 	ext=lnk->data;
    69 	if (!strcmp(ext->ns,extension->ns))
    70 	{
    71 	    g_static_mutex_unlock(&mutex);
    72 	    return FALSE;
    73 	}
    74     }
    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);
    79     return TRUE;
    80 }
    81 
    82 /*
    83  * Returned constant should be freed iff evaluate is TRUE
    84  */
    85 static XexprConstant *xexpr_get_argument(Xexpr *xexpr,GSList *bindings,
    86   GSList **args,const char *func,const char *id,gboolean evaluate,GError **err)
    87 {
    88     XexprConstant *arg;
    89     arg=xexpr_bindings_get(bindings,id);
    90     if (!arg)
    91     {
    92 	if (*args)
    93 	{
    94 	    arg=(*args)->data;
    95 	    *args=(*args)->next;
    96 	}
    97 	else
    98 	{
    99 	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
   100 	      "Missing \"%s\" argument to \"%s\"",id,func);
   101 	    return NULL;
   102 	}
   103     }
   104     if (arg && evaluate)
   105 	arg=xexpr_constant_evaluate(xexpr,arg,err);
   106     return arg;
   107 }
   108 
   109 static XexprConstant *xexpr_do_define(Xexpr *xexpr,GSList *bindings,
   110   GSList *args,GError **err)
   111 {
   112     int i;
   113     gchar **vector=NULL;
   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);
   118     if (!name)
   119 	return NULL;
   120     if (name->type!=XEXPR_TYPE_STRING)
   121     {
   122 	args=g_slist_prepend(NULL,name);
   123 	arg=xexpr_do_string(xexpr,NULL,args,NULL);
   124 	g_slist_free(args);
   125 	if (arg)
   126 	{
   127 	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
   128 	      "Attempt to define a function with a non-string name \"%s\"",
   129 	      arg->u.string);
   130 	    xexpr_constant_free(arg);
   131 	}
   132 	else
   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);
   136 	return NULL;
   137     }
   138     else if (!_xexpr_validate_id(name->u.string,err) ||
   139       !xexpr_defineable_id(name->u.string,err))
   140     {
   141 	xexpr_constant_free(name);
   142 	return NULL;
   143     }
   144     params=xexpr_bindings_get(bindings,"args");
   145     if (params)
   146     {
   147 	params=xexpr_constant_evaluate(xexpr,params,err);
   148 	if (params->type!=XEXPR_TYPE_STRING)
   149 	{
   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);
   154 	    return NULL;
   155 	}
   156 	vector=g_strsplit_set(params->u.string," \t\n\r",-1);
   157 	for(i=0;vector[i];i++)
   158 	{
   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')
   162 	    {
   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);
   167 		g_strfreev(vector);
   168 		g_slist_free(parameters);
   169 		return NULL;
   170 	    }
   171 	    parameters=g_slist_prepend(parameters,vector[i]);
   172 	}
   173 	parameters=g_slist_reverse(parameters);
   174     }
   175     value=xexpr_new_function(parameters,args);
   176     g_slist_free(parameters);
   177     if (vector)
   178 	g_strfreev(vector);
   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);
   184     return value;
   185 }
   186 
   187 static XexprConstant *xexpr_do_print(Xexpr *xexpr,GSList *bindings,GSList *args,
   188   GError **err)
   189 {
   190     gboolean newline=FALSE;
   191     GSList *lnk;
   192     XexprConstant *arg;
   193     arg=xexpr_bindings_get(bindings,"newline");
   194     if (arg && arg->type==XEXPR_TYPE_STRING && !strcmp(arg->u.string,"true"))
   195 	newline=TRUE;
   196     for(lnk=args;lnk;lnk=lnk->next)
   197     {
   198 	arg=lnk->data;
   199 	switch(arg->type)
   200 	{
   201 	    case XEXPR_TYPE_FUNCTION:
   202 		/*
   203 		 * http://www.w3.org/TR/xexpr/#id-0003 implies that
   204 		 * function objects are ignored in <print>.
   205 		 */
   206 		break;
   207 	    case XEXPR_TYPE_INVOCATION:
   208 		printf("<%s/>",arg->u.invocation->function);
   209 		break;
   210 	    case XEXPR_TYPE_STRING:
   211 		fputs(arg->u.string,stdout);
   212 		break;
   213 	    case XEXPR_TYPE_INTEGER:
   214 		printf("%lld",arg->u.integer);
   215 		break;
   216 	    case XEXPR_TYPE_NUMBER:
   217 		printf("%lg",arg->u.number);
   218 		break;
   219 	}
   220     }
   221     if (newline)
   222 	putchar('\n');
   223     return xexpr_new_invocation(NULL,"true",NULL,NULL);
   224 }
   225 
   226 static XexprConstant *xexpr_do_println(Xexpr *xexpr,GSList *bindings,
   227   GSList *args,GError **err)
   228 {
   229     putchar('\n');
   230     return xexpr_new_invocation(NULL,"true",NULL,NULL);
   231 }
   232 
   233 static XexprConstant *xexpr_do_get(Xexpr *xexpr,GSList *bindings,
   234   GSList *args,GError **err)
   235 {
   236     XexprConstant *name,*value;
   237     name=xexpr_get_argument(xexpr,bindings,&args,"get","name",FALSE,err);
   238     if (!name)
   239 	return NULL;
   240     if (name->type==XEXPR_TYPE_STRING)
   241 	value=xexpr_var_get(xexpr,name->u.string);
   242     else
   243 	value=NULL;
   244     if (value)
   245 	value=xexpr_constant_dup(value);
   246     else
   247 	value=xexpr_new_invocation(NULL,"nil",NULL,NULL);
   248     return value;
   249 }
   250 
   251 static XexprConstant *xexpr_do_set(Xexpr *xexpr,GSList *bindings,
   252   GSList *args,GError **err)
   253 {
   254     XexprConstant *name,*value;
   255     name=xexpr_get_argument(xexpr,bindings,&args,"set","name",FALSE,err);
   256     if (!name)
   257 	return NULL;
   258     if (name->type!=XEXPR_TYPE_STRING)
   259     {
   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);
   263 	return NULL;
   264     }
   265     else if (!_xexpr_validate_id(name->u.string,err) ||
   266       !xexpr_defineable_id(name->u.string,err))
   267     {
   268 	xexpr_constant_free(name);
   269 	return NULL;
   270     }
   271     value=xexpr_get_argument(xexpr,bindings,&args,"set","value",FALSE,err);
   272     if (!value)
   273 	return NULL;
   274     xexpr_var_set(xexpr,name->u.string,value);
   275     return xexpr_constant_dup(value);
   276 }
   277 
   278 static XexprConstant *xexpr_do_expr(Xexpr *xexpr,GSList *bindings,GSList *args,
   279   GError **err)
   280 {
   281     if (!args)
   282 	return xexpr_new_invocation(NULL,"nil",NULL,NULL);
   283     while(args->next)
   284 	args=args->next;
   285     return xexpr_constant_dup(args->data);
   286 }
   287 
   288 static XexprConstant *xexpr_do_return(Xexpr *xexpr,GSList *bindings,
   289   GSList *args,GError **err)
   290 {
   291     XexprConstant *retval;
   292     if (!args)
   293 	retval=xexpr_new_invocation(NULL,"nil",NULL,NULL);
   294     while(args->next)
   295 	args=args->next;
   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));
   299 }
   300 
   301 static XexprConstant *xexpr_do_string(Xexpr *xexpr,GSList *bindings,
   302   GSList *args,GError **err)
   303 {
   304     XexprConstant *arg;
   305     GString *str=g_string_new(NULL);
   306     while(args)
   307     {
   308 	arg=args->data;
   309 	switch(arg->type)
   310 	{
   311 	    case XEXPR_TYPE_FUNCTION:
   312 		g_warn_if_reached();
   313 		break;
   314 	    case XEXPR_TYPE_INVOCATION:
   315 		g_string_append_printf(str,"<%s/>",arg->u.invocation->function);
   316 		break;
   317 	    case XEXPR_TYPE_STRING:
   318 		g_string_append(str,arg->u.string);
   319 		break;
   320 	    case XEXPR_TYPE_INTEGER:
   321 		g_string_append_printf(str,"%lld",arg->u.integer);
   322 		break;
   323 	    case XEXPR_TYPE_NUMBER:
   324 		g_string_append_printf(str,"%lg",arg->u.number);
   325 		break;
   326 	}
   327 	args=args->next;
   328     }
   329     return xexpr_new_string_take_ownership(g_string_free(str,FALSE));
   330 }
   331 
   332 static XexprConstant *xexpr_do_integer(Xexpr *xexpr,GSList *bindings,
   333   GSList *args,GError **err)
   334 {
   335     XexprConstant *arg;
   336     double d;
   337     long long int value=0;
   338     while(args)
   339     {
   340 	arg=args->data;
   341 	switch(arg->type)
   342 	{
   343 	    case XEXPR_TYPE_FUNCTION:
   344 		g_warn_if_reached();
   345 		break;
   346 	    case XEXPR_TYPE_INVOCATION:
   347 		g_warn_if_reached();
   348 		break;
   349 	    case XEXPR_TYPE_STRING:
   350 		value=g_ascii_strtoll(arg->u.string,NULL,0);
   351 		if (value==LLONG_MIN || value==LLONG_MAX)
   352 		{
   353 		    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
   354 		      "Integer overflow on %s",arg->u.string);
   355 		    return NULL;
   356 		}
   357 		break;
   358 	    case XEXPR_TYPE_INTEGER:
   359 		value=arg->u.integer;
   360 		break;
   361 	    case XEXPR_TYPE_NUMBER:
   362 		if (!isfinite(arg->u.number))
   363 		{
   364 		    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
   365 		      "%lg is not finite",arg->u.number);
   366 		    return NULL;
   367 		}
   368 		d=nearbyint(arg->u.number);
   369 		if (d<=LLONG_MIN || d>=LLONG_MAX)
   370 		{
   371 		    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
   372 		      "Integer overflow on %lg",arg->u.number);
   373 		    return NULL;
   374 		}
   375 		value=(long long int)d;
   376 		break;
   377 	}
   378 	args=args->next;
   379     }
   380     return xexpr_new_integer(value);
   381 }
   382 
   383 static XexprConstant *xexpr_do_float(Xexpr *xexpr,GSList *bindings,
   384   GSList *args,GError **err)
   385 {
   386     XexprConstant *arg;
   387     double value=0.0/0.0;
   388     while(args)
   389     {
   390 	arg=args->data;
   391 	switch(arg->type)
   392 	{
   393 	    case XEXPR_TYPE_FUNCTION:
   394 		g_warn_if_reached();
   395 		break;
   396 	    case XEXPR_TYPE_INVOCATION:
   397 		g_warn_if_reached();
   398 		break;
   399 	    case XEXPR_TYPE_STRING:
   400 		value=g_ascii_strtod(arg->u.string,NULL);
   401 		if (value==HUGE_VAL || value==-HUGE_VAL)
   402 		{
   403 		    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
   404 		      "Numeric overflow on %s",arg->u.string);
   405 		    return NULL;
   406 		}
   407 		break;
   408 	    case XEXPR_TYPE_INTEGER:
   409 		if (arg->u.integer<-DBL_MAX || arg->u.integer>DBL_MAX)
   410 		{
   411 		    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
   412 		      "Numeric overflow on %lld",arg->u.integer);
   413 		    return NULL;
   414 		}
   415 		value=(double)arg->u.integer;
   416 		break;
   417 	    case XEXPR_TYPE_NUMBER:
   418 		value=arg->u.number;
   419 		break;
   420 	}
   421 	args=args->next;
   422     }
   423     return xexpr_new_number(value);
   424 }
   425 
   426 static XexprConstant *xexpr_do_true(Xexpr *xexpr,GSList *bindings,GSList *args,
   427   GError **err)
   428 {
   429     return xexpr_new_invocation(NULL,"true",NULL,NULL);
   430 }
   431 
   432 static XexprConstant *xexpr_do_false(Xexpr *xexpr,GSList *bindings,GSList *args,
   433   GError **err)
   434 {
   435     return xexpr_new_invocation(NULL,"false",NULL,NULL);
   436 }
   437 
   438 static XexprConstant *xexpr_do_nil(Xexpr *xexpr,GSList *bindings,GSList *args,
   439   GError **err)
   440 {
   441     return xexpr_new_invocation(NULL,"nil",NULL,NULL);
   442 }
   443 
   444 typedef struct xexpr_accumulator {
   445     gboolean first;
   446     Xexpr *xexpr;
   447     GSList *args;
   448     const char *result_binding;
   449     XexprConstant *arg,*result;
   450 } XexprAccumulator;
   451 
   452 static gboolean xexpr_accumulator_init(XexprAccumulator *accumulator,
   453   Xexpr *xexpr,GSList *args,gboolean bind_result,GError **err)
   454 {
   455     XexprConstant *arg;
   456     accumulator->xexpr=xexpr;
   457     accumulator->args=args;
   458     accumulator->arg=NULL;
   459     accumulator->first=TRUE;
   460     if (!accumulator->args)
   461     {
   462 	accumulator->result_binding=NULL;
   463 	accumulator->result=xexpr_new_invocation(NULL,"nil",NULL,NULL);
   464 	return TRUE;
   465     }
   466     arg=accumulator->args->data;
   467     /*
   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
   475      *
   476      * Note that since the value accumulates:
   477      *	<add x="1"><x/><x/><x/></add>
   478      * results in 4 rather than 3.
   479      */
   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;
   483     else
   484 	accumulator->result_binding=NULL;
   485     accumulator->result=xexpr_constant_evaluate(xexpr,arg,err);
   486     while(accumulator->result && accumulator->result->type==XEXPR_TYPE_FUNCTION)
   487     {
   488 	arg=xexpr_constant_evaluate(xexpr,accumulator->result,err);
   489 	xexpr_constant_free(accumulator->result);
   490 	accumulator->result=arg;
   491     }
   492     return !!accumulator->result;
   493 }
   494 
   495 static gboolean xexpr_accumulator_next(XexprAccumulator *accumulator)
   496 {
   497     if (accumulator->result_binding && !accumulator->first)
   498     {
   499 	xexpr_var_set(accumulator->xexpr,accumulator->result_binding,
   500 	  accumulator->result);
   501 	if (xexpr_is_tracing(accumulator->xexpr,accumulator->result_binding))
   502 	{
   503 	    printf("\nChanged variable %s\n",accumulator->result_binding);
   504 	    xexpr_stack_dump(accumulator->xexpr,stdout);
   505 	}
   506     }
   507     accumulator->args=accumulator->args->next;
   508     accumulator->first=FALSE;
   509     return !!accumulator->args;
   510 }
   511 
   512 static XexprConstant *xexpr_accumulator_get(XexprAccumulator *accumulator,
   513   GError **err)
   514 {
   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;
   520 }
   521 
   522 static XexprConstant *xexpr_accumulator_finish(XexprAccumulator *accumulator)
   523 {
   524     if (accumulator->arg)
   525 	xexpr_constant_free(accumulator->arg);
   526     return accumulator->result;
   527 }
   528 
   529 static void xexpr_accumulator_abort(XexprAccumulator *accumulator)
   530 {
   531     xexpr_constant_free(xexpr_accumulator_finish(accumulator));
   532 }
   533 
   534 static XexprConstant *xexpr_do_add(Xexpr *xexpr,GSList *bindings,GSList *args,
   535   GError **err)
   536 {
   537     XexprConstant *arg;
   538     gchar *str;
   539     XexprAccumulator accumulator;
   540     if (!xexpr_accumulator_init(&accumulator,xexpr,args,TRUE,err))
   541 	return NULL;
   542     while(xexpr_accumulator_next(&accumulator))
   543     {
   544 	arg=xexpr_accumulator_get(&accumulator,err);
   545 	if (!arg)
   546 	{
   547 	    xexpr_accumulator_abort(&accumulator);
   548 	    return NULL;
   549 	}
   550 	switch(accumulator.result->type)
   551 	{
   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);
   557 		return NULL;
   558 		break;
   559 	    case XEXPR_TYPE_STRING:
   560 		switch(arg->type)
   561 		{
   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);
   568 			return NULL;
   569 		    case XEXPR_TYPE_STRING:
   570 			str=g_strconcat(accumulator.result->u.string,
   571 			  arg->u.string,NULL);
   572 			g_free(accumulator.result->u.string);
   573 			accumulator.result->u.string=str;
   574 			break;
   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;
   580 			break;
   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;
   586 			break;
   587 		}
   588 		break;
   589 	    case XEXPR_TYPE_INTEGER:
   590 		if (arg->type==XEXPR_TYPE_INTEGER)
   591 		{
   592 		    accumulator.result->u.integer+=arg->u.integer;
   593 		    break;
   594 		}
   595 		else if (arg->type==XEXPR_TYPE_NUMBER)
   596 		{
   597 		    accumulator.result->type=XEXPR_TYPE_NUMBER;
   598 		    accumulator.result->u.number=accumulator.result->u.integer;
   599 		}
   600 		/* Fall through */
   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;
   606 		else
   607 		{
   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);
   611 		    return NULL;
   612 		}
   613 		break;
   614 	}
   615     }
   616     return xexpr_accumulator_finish(&accumulator);
   617 }
   618 
   619 static XexprConstant *xexpr_do_subtract(Xexpr *xexpr,GSList *bindings,
   620   GSList *args,GError **err)
   621 {
   622     XexprConstant *arg;
   623     XexprAccumulator accumulator;
   624     if (!xexpr_accumulator_init(&accumulator,xexpr,args,TRUE,err))
   625 	return NULL;
   626     while(xexpr_accumulator_next(&accumulator))
   627     {
   628 	arg=xexpr_accumulator_get(&accumulator,err);
   629 	if (!arg)
   630 	{
   631 	    xexpr_accumulator_abort(&accumulator);
   632 	    return NULL;
   633 	}
   634 	if (arg->type!=XEXPR_TYPE_INTEGER && arg->type!=XEXPR_TYPE_NUMBER)
   635 	{
   636 invalid_args:
   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);
   640 	    return NULL;
   641 	}
   642 	switch(accumulator.result->type)
   643 	{
   644 	    case XEXPR_TYPE_INTEGER:
   645 		if (arg->type==XEXPR_TYPE_INTEGER)
   646 		{
   647 		    accumulator.result->u.integer-=arg->u.integer;
   648 		    break;
   649 		}
   650 		else
   651 		{
   652 		    accumulator.result->type=XEXPR_TYPE_NUMBER;
   653 		    accumulator.result->u.number=accumulator.result->u.integer;
   654 		}
   655 		/* Fall through */
   656 	    case XEXPR_TYPE_NUMBER:
   657 		if (accumulator.arg->type==XEXPR_TYPE_INTEGER)
   658 		    accumulator.result->u.number-=arg->u.integer;
   659 		else
   660 		    accumulator.result->u.number-=arg->u.number;
   661 		break;
   662 	    default:
   663 		goto invalid_args;
   664 	}
   665     }
   666     return xexpr_accumulator_finish(&accumulator);
   667 }
   668 
   669 static XexprConstant *xexpr_do_multiply(Xexpr *xexpr,GSList *bindings,
   670   GSList *args,GError **err)
   671 {
   672     XexprConstant *arg;
   673     XexprAccumulator accumulator;
   674     if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err))
   675 	return NULL;
   676     while(xexpr_accumulator_next(&accumulator))
   677     {
   678 	arg=xexpr_accumulator_get(&accumulator,err);
   679 	if (!arg)
   680 	{
   681 	    xexpr_accumulator_abort(&accumulator);
   682 	    return NULL;
   683 	}
   684 	if (arg->type!=XEXPR_TYPE_INTEGER && arg->type!=XEXPR_TYPE_NUMBER)
   685 	{
   686 	    GString *str=g_string_new(NULL);
   687 invalid_args:
   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",
   691 	      str->str);
   692 	    g_string_free(str,TRUE);
   693 	    xexpr_accumulator_abort(&accumulator);
   694 	    return NULL;
   695 	}
   696 	switch(accumulator.result->type)
   697 	{
   698 	    case XEXPR_TYPE_INTEGER:
   699 		if (arg->type==XEXPR_TYPE_INTEGER)
   700 		{
   701 		    accumulator.result->u.integer*=arg->u.integer;
   702 		    break;
   703 		}
   704 		else
   705 		{
   706 		    accumulator.result->type=XEXPR_TYPE_NUMBER;
   707 		    accumulator.result->u.number=accumulator.result->u.integer;
   708 		}
   709 		/* Fall through */
   710 	    case XEXPR_TYPE_NUMBER:
   711 		if (arg->type==XEXPR_TYPE_INTEGER)
   712 		    accumulator.result->u.number*=arg->u.integer;
   713 		else
   714 		    accumulator.result->u.number*=arg->u.number;
   715 		break;
   716 	    default:
   717 		goto invalid_args;
   718 	}
   719     }
   720     return xexpr_accumulator_finish(&accumulator);
   721 }
   722 
   723 static XexprConstant *xexpr_do_divide(Xexpr *xexpr,GSList *bindings,
   724   GSList *args,GError **err)
   725 {
   726     XexprConstant *arg;
   727     long long int r;
   728     XexprAccumulator accumulator;
   729     if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err))
   730 	return NULL;
   731     while(xexpr_accumulator_next(&accumulator))
   732     {
   733 	arg=xexpr_accumulator_get(&accumulator,err);
   734 	if (!arg)
   735 	{
   736 	    xexpr_accumulator_abort(&accumulator);
   737 	    return NULL;
   738 	}
   739 	if (arg->type!=XEXPR_TYPE_INTEGER && arg->type!=XEXPR_TYPE_NUMBER)
   740 	{
   741 invalid_args:
   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);
   745 	    return NULL;
   746 	}
   747 	switch(accumulator.result->type)
   748 	{
   749 	    case XEXPR_TYPE_INTEGER:
   750 		if (arg->type==XEXPR_TYPE_INTEGER)
   751 		{
   752 		    r=accumulator.result->u.integer/arg->u.integer;
   753 		    if (r*arg->u.integer==accumulator.result->u.integer)
   754 		    {
   755 			accumulator.result->u.integer=r;
   756 			break;
   757 		    }
   758 		}
   759 		accumulator.result->type=XEXPR_TYPE_NUMBER;
   760 		accumulator.result->u.number=accumulator.result->u.integer;
   761 		/* Fall through */
   762 	    case XEXPR_TYPE_NUMBER:
   763 		if (arg->type==XEXPR_TYPE_INTEGER)
   764 		    accumulator.result->u.number/=arg->u.integer;
   765 		else
   766 		    accumulator.result->u.number/=arg->u.number;
   767 		break;
   768 	    default:
   769 		goto invalid_args;
   770 	}
   771     }
   772     return xexpr_accumulator_finish(&accumulator);
   773 }
   774 
   775 /**
   776  * xexpr_constant_cast:
   777  * @constant: an #XexprConstant to cast
   778  * @to: type to cast @constant to
   779  *
   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
   783  * precision.
   784  *
   785  * Return value: %TRUE if @constant is now of type @to.
   786  */
   787 gboolean xexpr_constant_cast(XexprConstant *constant,XexprType to)
   788 {
   789     double dummy;
   790     if (constant->type==to)
   791 	return TRUE;
   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))
   795     {
   796 	constant->type=XEXPR_TYPE_INTEGER;
   797 	constant->u.integer=constant->u.number;
   798 	return TRUE;
   799     }
   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)
   803     {
   804 	constant->type=XEXPR_TYPE_NUMBER;
   805 	constant->u.number=constant->u.integer;
   806 	return TRUE;
   807     }
   808     else
   809 	return FALSE;
   810 }
   811 
   812 static gboolean xexpr_constant_boolean(Xexpr *xexpr,XexprConstant *constant,
   813   GError **err)
   814 {
   815     gboolean retval;
   816     XexprConstant *result;
   817     switch (constant->type)
   818     {
   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:
   829 	    /*
   830 	     * See http://www.w3.org/TR/xexpr/#id-0038
   831 	     */
   832 	    result=xexpr_constant_evaluate(xexpr,constant,err);
   833 	    if (!result)
   834 		return FALSE;
   835 	    retval=xexpr_constant_boolean(xexpr,result,err);
   836 	    xexpr_constant_free(result);
   837 	    return retval;
   838     }
   839     return FALSE;
   840 }
   841 
   842 /*
   843  * Returns: 0 if equal, <0 if value1 < value2, >0 if value1 > value2,
   844  *          NaN if value1 is not comparible with value2.
   845  */
   846 static double xexpr_constant_compare(Xexpr *xexpr,XexprConstant *v1,
   847   XexprConstant *v2)
   848 {
   849     double retval=0.0/0.0;
   850     XexprConstant *value1,*value2;
   851     value1=xexpr_constant_evaluate(xexpr,v1,NULL);
   852     if (!value1)
   853 	value1=xexpr_constant_dup(v1);
   854     while(value1->type==XEXPR_TYPE_FUNCTION)
   855     {
   856 	v1=xexpr_constant_evaluate(xexpr,value1,NULL);
   857 	if (v1)
   858 	{
   859 	    xexpr_constant_free(value1);
   860 	    value1=v1;
   861 	}
   862 	else
   863 	    break;
   864     }
   865     value2=xexpr_constant_evaluate(xexpr,v2,NULL);
   866     if (!value2)
   867 	value2=xexpr_constant_dup(v2);
   868     while(value2->type==XEXPR_TYPE_FUNCTION)
   869     {
   870 	v2=xexpr_constant_evaluate(xexpr,value2,NULL);
   871 	if (v2)
   872 	{
   873 	    xexpr_constant_free(value2);
   874 	    value2=v2;
   875 	}
   876 	else
   877 	    break;
   878     }
   879     if (value1->type!=value2->type)
   880     {
   881 	if (!xexpr_constant_cast(value1,value2->type) &&
   882 	  !xexpr_constant_cast(value2,value1->type))
   883 	{
   884 	    xexpr_constant_free(value1);
   885 	    xexpr_constant_free(value2);
   886 	    return 0.0/0.0;
   887 	}
   888     }
   889     switch(value1->type)
   890     {
   891 	case XEXPR_TYPE_FUNCTION:
   892 	    g_warn_if_reached();
   893 	    break;
   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);
   901 	    break;
   902 	case XEXPR_TYPE_STRING:
   903 	    retval=strcmp(value1->u.string,value2->u.string);
   904 	    break;
   905 	case XEXPR_TYPE_INTEGER:
   906 	    retval=value1->u.integer-value2->u.integer;
   907 	    break;
   908 	case XEXPR_TYPE_NUMBER:
   909 	    retval=value1->u.number-value2->u.number;
   910 	    break;
   911     }
   912     xexpr_constant_free(value1);
   913     xexpr_constant_free(value2);
   914     return retval;
   915 }
   916 
   917 static XexprConstant *xexpr_do_eq(Xexpr *xexpr,GSList *bindings,GSList *args,
   918   GError **err)
   919 {
   920     XexprConstant *arg,*standard=NULL;
   921     while(args)
   922     {
   923 	arg=args->data;
   924 	if (!standard)
   925 	    standard=arg;
   926 	else if (xexpr_constant_compare(xexpr,standard,arg))
   927 	    return xexpr_new_invocation(NULL,"false",NULL,NULL);
   928 	args=args->next;
   929     }
   930     return xexpr_new_invocation(NULL,"true",NULL,NULL);
   931 }
   932 
   933 static XexprConstant *xexpr_do_neq(Xexpr *xexpr,GSList *bindings,GSList *args,
   934   GError **err)
   935 {
   936     XexprConstant *arg;
   937     GSList *lnk;
   938     while(args)
   939     {
   940 	arg=args->data;
   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);
   944 	args=args->next;
   945     }
   946     return xexpr_new_invocation(NULL,"true",NULL,NULL);
   947 }
   948 
   949 static XexprConstant *xexpr_do_leq(Xexpr *xexpr,GSList *bindings,GSList *args,
   950   GError **err)
   951 {
   952     XexprConstant *arg,*standard=NULL;
   953     while(args)
   954     {
   955 	arg=args->data;
   956 	if (standard && !(xexpr_constant_compare(xexpr,standard,arg)<=0))
   957 	    return xexpr_new_invocation(NULL,"false",NULL,NULL);
   958 	standard=arg;
   959 	args=args->next;
   960     }
   961     return xexpr_new_invocation(NULL,"true",NULL,NULL);
   962 }
   963 
   964 static XexprConstant *xexpr_do_geq(Xexpr *xexpr,GSList *bindings,GSList *args,
   965   GError **err)
   966 {
   967     XexprConstant *arg,*standard=NULL;
   968     while(args)
   969     {
   970 	arg=args->data;
   971 	if (standard && !(xexpr_constant_compare(xexpr,standard,arg)>=0))
   972 	    return xexpr_new_invocation(NULL,"false",NULL,NULL);
   973 	standard=arg;
   974 	args=args->next;
   975     }
   976     return xexpr_new_invocation(NULL,"true",NULL,NULL);
   977 }
   978 
   979 static XexprConstant *xexpr_do_lt(Xexpr *xexpr,GSList *bindings,GSList *args,
   980   GError **err)
   981 {
   982     XexprConstant *arg,*standard=NULL;
   983     while(args)
   984     {
   985 	arg=args->data;
   986 	if (standard && !(xexpr_constant_compare(xexpr,standard,arg)<0))
   987 	    return xexpr_new_invocation(NULL,"false",NULL,NULL);
   988 	standard=arg;
   989 	args=args->next;
   990     }
   991     return xexpr_new_invocation(NULL,"true",NULL,NULL);
   992 }
   993 
   994 static XexprConstant *xexpr_do_gt(Xexpr *xexpr,GSList *bindings,GSList *args,
   995   GError **err)
   996 {
   997     XexprConstant *arg,*standard=NULL;
   998     while(args)
   999     {
  1000 	arg=args->data;
  1001 	if (standard && !(xexpr_constant_compare(xexpr,standard,arg)>0))
  1002 	    return xexpr_new_invocation(NULL,"false",NULL,NULL);
  1003 	standard=arg;
  1004 	args=args->next;
  1005     }
  1006     return xexpr_new_invocation(NULL,"true",NULL,NULL);
  1007 }
  1008 
  1009 static XexprConstant *xexpr_do_and(Xexpr *xexpr,GSList *bindings,GSList *args,
  1010   GError **err)
  1011 {
  1012     GError *tmp_err=NULL;
  1013     XexprConstant *arg;
  1014     XexprAccumulator accumulator;
  1015     if (!args)
  1016 	return xexpr_new_invocation(NULL,"true",NULL,NULL);
  1017     if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err))
  1018 	return NULL;
  1019     if (!xexpr_constant_boolean(xexpr,accumulator.result,&tmp_err))
  1020     {
  1021 	xexpr_accumulator_abort(&accumulator);
  1022 	if (tmp_err)
  1023 	{
  1024 	    g_propagate_error(err,tmp_err);
  1025 	    return NULL;
  1026 	}
  1027 	else
  1028 	    return xexpr_new_invocation(NULL,"false",NULL,NULL);
  1029     }
  1030     while(xexpr_accumulator_next(&accumulator))
  1031     {
  1032 	arg=xexpr_accumulator_get(&accumulator,err);
  1033 	if (!arg)
  1034 	{
  1035 	    xexpr_accumulator_abort(&accumulator);
  1036 	    return NULL;
  1037 	}
  1038 	if (!xexpr_constant_boolean(xexpr,arg,&tmp_err))
  1039 	{
  1040 	    xexpr_accumulator_abort(&accumulator);
  1041 	    if (tmp_err)
  1042 	    {
  1043 		g_propagate_error(err,tmp_err);
  1044 		return NULL;
  1045 	    }
  1046 	    else
  1047 		return xexpr_new_invocation(NULL,"false",NULL,NULL);
  1048 	}
  1049     }
  1050     xexpr_accumulator_abort(&accumulator);
  1051     return xexpr_new_invocation(NULL,"true",NULL,NULL);
  1052 }
  1053 
  1054 static XexprConstant *xexpr_do_or(Xexpr *xexpr,GSList *bindings,GSList *args,
  1055   GError **err)
  1056 {
  1057     GError *tmp_err=NULL;
  1058     XexprConstant *arg;
  1059     XexprAccumulator accumulator;
  1060     if (!args)
  1061 	return xexpr_new_invocation(NULL,"true",NULL,NULL);
  1062     if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err))
  1063 	return NULL;
  1064     if (xexpr_constant_boolean(xexpr,accumulator.result,&tmp_err))
  1065     {
  1066 	xexpr_accumulator_abort(&accumulator);
  1067 	return xexpr_new_invocation(NULL,"true",NULL,NULL);
  1068     }
  1069     else if (tmp_err)
  1070     {
  1071 	xexpr_accumulator_abort(&accumulator);
  1072 	g_propagate_error(err,tmp_err);
  1073 	return NULL;
  1074     }
  1075     while(xexpr_accumulator_next(&accumulator))
  1076     {
  1077 	arg=xexpr_accumulator_get(&accumulator,err);
  1078 	if (!arg)
  1079 	{
  1080 	    xexpr_accumulator_abort(&accumulator);
  1081 	    return NULL;
  1082 	}
  1083 	if (xexpr_constant_boolean(xexpr,arg,&tmp_err))
  1084 	{
  1085 	    xexpr_accumulator_abort(&accumulator);
  1086 	    return xexpr_new_invocation(NULL,"true",NULL,NULL);
  1087 	}
  1088 	else if (tmp_err)
  1089 	{
  1090 	    xexpr_accumulator_abort(&accumulator);
  1091 	    g_propagate_error(err,tmp_err);
  1092 	    return NULL;
  1093 	}
  1094     }
  1095     xexpr_accumulator_abort(&accumulator);
  1096     return xexpr_new_invocation(NULL,"false",NULL,NULL);
  1097 }
  1098 
  1099 /*
  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>.
  1103  */
  1104 static XexprConstant *xexpr_do_not(Xexpr *xexpr,GSList *bindings,GSList *args,
  1105   GError **err)
  1106 {
  1107     gboolean test;
  1108     XexprConstant *result;
  1109     if (!args)
  1110 	return xexpr_new_invocation(NULL,"true",NULL,NULL);
  1111     result=xexpr_do_and(xexpr,bindings,args,err);
  1112     if (!result)
  1113 	return NULL;
  1114     test=xexpr_constant_boolean(xexpr,result,NULL);
  1115     xexpr_constant_free(result);
  1116     return xexpr_new_invocation(NULL,test?"false":"true",NULL,NULL);
  1117 }
  1118 
  1119 static XexprConstant *xexpr_do_if(Xexpr *xexpr,GSList *bindings,GSList *args,
  1120   GError **err)
  1121 {
  1122     GError *tmp_err=NULL;
  1123     gboolean test;
  1124     XexprConstant *arg;
  1125     if (g_slist_length(args)<2)
  1126     {
  1127 	g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  1128 	  "<if> requires at least 2 arguments to be passed");
  1129 	return NULL;
  1130     }
  1131     arg=xexpr_constant_evaluate(xexpr,args->data,err);
  1132     if (!arg)
  1133 	return NULL;
  1134     test=xexpr_constant_boolean(xexpr,arg,&tmp_err);
  1135     if (tmp_err)
  1136     {
  1137 	g_propagate_error(err,tmp_err);
  1138 	return NULL;
  1139     }
  1140     xexpr_constant_free(arg);
  1141     if (test)
  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);
  1145     else
  1146 	return xexpr_new_invocation(NULL,"nil",NULL,NULL);
  1147 }
  1148 
  1149 static XexprConstant *xexpr_do_switch(Xexpr *xexpr,GSList *bindings,
  1150   GSList *args,GError **err)
  1151 {
  1152     GError *tmp_err=NULL;
  1153     gboolean test;
  1154     XexprConstant *case_arg,*arg;
  1155     GSList *lnk;
  1156     while(args)
  1157     {
  1158 	case_arg=args->data;
  1159 	if (case_arg->type!=XEXPR_TYPE_INVOCATION ||
  1160 	  strcmp(case_arg->u.invocation->function,"case"))
  1161 	{
  1162 	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  1163 	      "<switch> requires a list of <case> expressions");
  1164 	    return NULL;
  1165 	}
  1166 	lnk=case_arg->u.invocation->constants;
  1167 	if (!lnk)
  1168 	{
  1169 	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  1170 	      "<case> requires a test expression");
  1171 	    return NULL;
  1172 	}
  1173 	arg=xexpr_constant_evaluate(xexpr,lnk->data,err);
  1174 	if (!arg)
  1175 	    return NULL;
  1176 	test=xexpr_constant_boolean(xexpr,arg,&tmp_err);
  1177 	if (tmp_err)
  1178 	{
  1179 	    g_propagate_error(err,tmp_err);
  1180 	    return NULL;
  1181 	}
  1182 	xexpr_constant_free(arg);
  1183 	if (test)
  1184 	{
  1185 	    arg=NULL;
  1186 	    while(lnk)
  1187 	    {
  1188 		if (arg)
  1189 		    xexpr_constant_free(arg);
  1190 		arg=xexpr_constant_evaluate(xexpr,lnk->data,err);
  1191 		if (!arg)
  1192 		    return NULL;
  1193 		lnk=lnk->next;
  1194 	    }
  1195 	    if (!arg)
  1196 	       arg=xexpr_new_invocation(NULL,"nil",NULL,NULL);
  1197 	    return arg;
  1198 	}
  1199 	args=args->next;
  1200     }
  1201     return xexpr_new_invocation(NULL,"nil",NULL,NULL);
  1202 }
  1203 
  1204 static XexprConstant *xexpr_do_while(Xexpr *xexpr,GSList *bindings,GSList *args,
  1205   GError **err)
  1206 {
  1207     GError *tmp_err=NULL;
  1208     gboolean test;
  1209     XexprConstant *arg,*result;
  1210     if (g_slist_length(args)!=2)
  1211     {
  1212 	g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  1213 	  "<while> takes 2 arguments");
  1214 	return NULL;
  1215     }
  1216     result=xexpr_new_invocation(NULL,"nil",NULL,NULL);
  1217     do
  1218     {
  1219 	arg=xexpr_constant_evaluate(xexpr,args->data,err);
  1220 	if (!arg)
  1221 	{
  1222 	    xexpr_constant_free(result);
  1223 	    return NULL;
  1224 	}
  1225 	test=xexpr_constant_boolean(xexpr,arg,&tmp_err);
  1226 	if (tmp_err)
  1227 	{
  1228 	    g_propagate_error(err,tmp_err);
  1229 	    return NULL;
  1230 	}
  1231 	xexpr_constant_free(arg);
  1232 	if (test)
  1233 	{
  1234 	    xexpr_constant_free(result);
  1235 	    result=xexpr_constant_evaluate(xexpr,args->next->data,err);
  1236 	    if (!result)
  1237 		return NULL;
  1238 	}
  1239     } while(test);
  1240     return result;
  1241 }
  1242 
  1243 static XexprConstant *xexpr_do_do(Xexpr *xexpr,GSList *bindings,GSList *args,
  1244   GError **err)
  1245 {
  1246     GError *tmp_err=NULL;
  1247     gboolean test;
  1248     XexprConstant *arg,*result;
  1249     if (g_slist_length(args)!=2)
  1250     {
  1251 	g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  1252 	  "<do> takes 2 arguments");
  1253 	return NULL;
  1254     }
  1255     result=NULL;
  1256     do
  1257     {
  1258 	if (result)
  1259 	    xexpr_constant_free(result);
  1260 	result=xexpr_constant_evaluate(xexpr,args->data,err);
  1261 	if (!result)
  1262 	    return NULL;
  1263 	arg=xexpr_constant_evaluate(xexpr,args->next->data,err);
  1264 	if (!arg)
  1265 	{
  1266 	    xexpr_constant_free(result);
  1267 	    return NULL;
  1268 	}
  1269 	test=xexpr_constant_boolean(xexpr,arg,&tmp_err);
  1270 	if (tmp_err)
  1271 	{
  1272 	    g_propagate_error(err,tmp_err);
  1273 	    return NULL;
  1274 	}
  1275 	xexpr_constant_free(arg);
  1276     } while(test);
  1277     return result;
  1278 }
  1279 
  1280 static struct xexpr_builtin {
  1281     char *id;
  1282     gboolean evaluate_args;
  1283     XexprConstant *(*func)(Xexpr *xexpr,GSList *bindings,GSList *args,
  1284       GError **err);
  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 },
  1317 };
  1318 
  1319 static gboolean xexpr_defineable_id(const char *id,GError **err)
  1320 {
  1321     int i;
  1322     for(i=0;i<G_N_ELEMENTS(xexpr_builtins);i++)
  1323 	if (!strcmp(xexpr_builtins[i].id,id))
  1324 	{
  1325 	    g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_EVAL_ERROR_FAILED,
  1326 	      "Can't define reserved XEXPR ID \"%s\"",id);
  1327 	    return FALSE;
  1328 	}
  1329     return TRUE;
  1330 }
  1331 
  1332 static XexprConstant *xexpr_closure(Xexpr *xexpr,XexprConstant *constant,
  1333   GError **err)
  1334 {
  1335     GSList *lnk;
  1336     XexprConstant *result,*tmp;
  1337     g_return_val_if_fail(constant->type==XEXPR_TYPE_FUNCTION,NULL);
  1338     result=NULL;
  1339     for(lnk=constant->u.function->constants;lnk;lnk=lnk->next)
  1340     {
  1341 	if (result)
  1342 	    xexpr_constant_free(result);
  1343 	result=xexpr_constant_evaluate(xexpr,lnk->data,err);
  1344 	if (!result)
  1345 	    return NULL;
  1346 	if (result->type==XEXPR_TYPE_INVOCATION &&
  1347 	  !strcmp(result->u.invocation->function,"return"))
  1348 	{
  1349 	    lnk=g_slist_last(result->u.invocation->constants);
  1350 	    tmp=xexpr_constant_dup(lnk->data);
  1351 	    xexpr_constant_free(result);
  1352 	    result=tmp;
  1353 	    break;
  1354 	}
  1355     }
  1356     if (!result)
  1357        result=xexpr_new_invocation(NULL,"nil",NULL,NULL);
  1358     return result;
  1359 }
  1360 
  1361 static XexprConstant *xexpr_function_evaluate(Xexpr *xexpr,const char *ns,
  1362   const char *id,GSList *bindings,GSList *args,GError **err)
  1363 {
  1364     int builtin;
  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;
  1371     if (ns)
  1372     {
  1373 	for(lnk=xexpr_extensions;lnk;lnk=lnk->next)
  1374 	{
  1375 	    ext=lnk->data;
  1376 	    if (!strcmp(ext->ns,ns))
  1377 		return ext->function_evaluate(xexpr,ns,id,bindings,args,err);
  1378 	}
  1379 	g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  1380 	  "Unknown namespace \"%s\"",ns);
  1381 	return NULL;
  1382     }
  1383     for(builtin=0;builtin<G_N_ELEMENTS(xexpr_builtins);builtin++)
  1384 	if (!strcmp(xexpr_builtins[builtin].id,id))
  1385 	{
  1386 	    evaluate_args=xexpr_builtins[builtin].evaluate_args;
  1387 	    break;
  1388 	}
  1389     if (builtin==G_N_ELEMENTS(xexpr_builtins))
  1390     {
  1391 	function_def=xexpr_var_get(xexpr,id);
  1392 	if (!function_def)
  1393 	{
  1394 	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  1395 	      "Undefined function: \"%s\"",id);
  1396 	    return NULL;
  1397 	}
  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);
  1401 	evaluate_args=TRUE;
  1402     }
  1403     else
  1404     {
  1405 	function_def=NULL;
  1406 	unbound_parameters=NULL;
  1407     }
  1408     for(lnk=bindings;lnk;lnk=lnk->next)
  1409     {
  1410 	binding=lnk->data;
  1411 	actual=g_slist_find_custom(unbound_parameters,binding->id,
  1412 	  (GCompareFunc)strcmp);
  1413 	if (actual)
  1414 	    unbound_parameters=g_slist_delete_link(unbound_parameters,actual);
  1415 	xexpr_var_new(xexpr,binding->id,binding->value);
  1416     }
  1417     if (evaluate_args)
  1418     {
  1419 	for(lnk=unbound_parameters;lnk;lnk=lnk->next)
  1420 	{
  1421 	    unbound_parameter=lnk->data;
  1422 	    value=xexpr_var_get(xexpr,unbound_parameter);
  1423 	    if (value)
  1424 		xexpr_var_new(xexpr,unbound_parameter,value);
  1425 	    else
  1426 	    {
  1427 		value=xexpr_new_invocation(NULL,"nil",NULL,NULL);
  1428 		xexpr_var_new(xexpr,unbound_parameter,value);
  1429 		xexpr_constant_free(value);
  1430 	    }
  1431 	}
  1432     }
  1433     while(unbound_parameters)
  1434     {
  1435 	unbound_parameter=unbound_parameters->data;
  1436 	if (unbound_args)
  1437 	{
  1438 	    if (evaluate_args)
  1439 	    {
  1440 		value=xexpr_constant_evaluate(xexpr,unbound_args->data,err);
  1441 		if (!value)
  1442 		{
  1443 		    g_slist_free(unbound_parameters);
  1444 		    return NULL;
  1445 		}
  1446 		xexpr_var_set(xexpr,unbound_parameter,value);
  1447 		xexpr_constant_free(value);
  1448 	    }
  1449 	    else
  1450 	    {
  1451 		value=unbound_args->data;
  1452 		xexpr_var_new(xexpr,unbound_parameter,value);
  1453 	    }
  1454 	    unbound_args=unbound_args->next;
  1455 	    unbound_parameters=
  1456 	      g_slist_delete_link(unbound_parameters,unbound_parameters);
  1457 	}
  1458 	else
  1459 	{
  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);
  1464 	    return NULL;
  1465 	}
  1466     }
  1467     if (evaluate_args)
  1468     {
  1469 	args=NULL;
  1470 	while(unbound_args)
  1471 	{
  1472 	    value=xexpr_constant_evaluate(xexpr,unbound_args->data,err);
  1473 	    if (!value)
  1474 		return NULL;
  1475 	    args=g_slist_prepend(args,value);
  1476 	    unbound_args=unbound_args->next;
  1477 	}
  1478 	args=g_slist_reverse(args);
  1479     }
  1480     if (function_def)
  1481 	result=xexpr_closure(xexpr,function_def,err);
  1482     else
  1483 	result=xexpr_builtins[builtin].func(xexpr,bindings,args,err);
  1484     if (evaluate_args)
  1485     {
  1486 	g_slist_foreach(args,(GFunc)xexpr_constant_free,NULL);
  1487 	g_slist_free(args);
  1488     }
  1489     return result;
  1490 }
  1491 
  1492 /**
  1493  * xexpr_constant_evaluate:
  1494  * @xexpr: an #Xexpr
  1495  * @constant: the #XexprConstant to evaluate
  1496  * @err: (allow-none): location to store error, or %NULL
  1497  *
  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 &lt;define&gt; 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 &lt;nil&gt;.
  1505  *
  1506  * The returned expresion should be freed with xexpr_constant_free()
  1507  * when no longer needed.
  1508  *
  1509  * Return value: (transfer full): The evaluated result, or %NULL on error
  1510  */
  1511 XexprConstant *xexpr_constant_evaluate(Xexpr *xexpr,XexprConstant *constant,
  1512   GError **err)
  1513 {
  1514     GSList *lnk;
  1515     XexprConstant *result,*tmp;
  1516     switch(constant->type)
  1517     {
  1518 	case XEXPR_TYPE_FUNCTION:
  1519 	    /*
  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.
  1527 	     */
  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);
  1535 	    return result;
  1536 	    break;
  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);
  1545 	    return result;
  1546 	    break;
  1547 	case XEXPR_TYPE_STRING:
  1548 	    return xexpr_new_string(constant->u.string,-1);
  1549 	    break;
  1550 	case XEXPR_TYPE_INTEGER:
  1551 	    return xexpr_new_integer(constant->u.integer);
  1552 	    break;
  1553 	case XEXPR_TYPE_NUMBER:
  1554 	    return xexpr_new_number(constant->u.number);
  1555 	    break;
  1556     }
  1557     return NULL;
  1558 }
  1559 
  1560 /**
  1561  * xexpr_evaluate:
  1562  * @xexpr: an #Xexpr to evaluate
  1563  * @err: (allow-none): location to store error, or %NULL
  1564  *
  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 &lt;define&gt; 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 &lt;nil&gt;.
  1572  *
  1573  * The returned expresion should be freed with xexpr_free()
  1574  * when no longer needed.
  1575  *
  1576  * Return value: (transfer full): The evaluated result, or %NULL on error
  1577  */
  1578 Xexpr *xexpr_evaluate(Xexpr *xexpr,GError **err)
  1579 {
  1580     Xexpr *results;
  1581     XexprConstant *constant,*result;
  1582     GSList *lnk;
  1583     results=xexpr_sub(xexpr);
  1584     for(lnk=xexpr->constants;lnk;lnk=lnk->next)
  1585     {
  1586 	constant=lnk->data;
  1587 	result=xexpr_constant_evaluate(xexpr,constant,err);
  1588 	if (!result)
  1589 	{
  1590 	    xexpr_free(results);
  1591 	    return NULL;
  1592 	}
  1593 	else
  1594 	    results->constants=g_slist_prepend(results->constants,result);
  1595     }
  1596     results->constants=g_slist_reverse(results->constants);
  1597     return results;
  1598 }
  1599 
  1600 /**
  1601  * xexpr_test:
  1602  * @xexpr: an #Xexpr to test
  1603  * @err: (allow-none): location to store error, or %NULL
  1604  *
  1605  * Test an expression by looking at the last constant in the expression.
  1606  * Numerical constants are treated as &lt;true&gt; if they are non-zero,
  1607  * string constants are treated as &lt;true&gt; if they are non-empty,
  1608  * function invocations are treated as &lt;true&gt; unless they are
  1609  * &lt;false&gt; or &lt;nil&gt;, function definitions are recursively
  1610  * evaluated before they are tested.
  1611  *
  1612  * Return value: %TRUE if the expression is equivalent to &lt;true&gt;.
  1613  */
  1614 gboolean xexpr_test(Xexpr *xexpr,GError **err)
  1615 {
  1616     GSList *lnk;
  1617     XexprConstant *constant;
  1618     lnk=g_slist_last(xexpr->constants);
  1619     constant=lnk->data;
  1620     return xexpr_constant_boolean(xexpr,constant,err);
  1621 }