libxexpr/xexprtypes.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
ali@0
     1
#include <stdlib.h>
ali@0
     2
#include <string.h>
ali@0
     3
#include <math.h>
ali@0
     4
#include <xexpr.h>
ali@0
     5
#include "xexprprivate.h"
ali@0
     6
ali@0
     7
/**
ali@0
     8
 * SECTION:xexprtypes
ali@0
     9
 * @short_description: Types defined in libxexpr
ali@0
    10
 * @stability: Stable
ali@0
    11
 * @include: libxexpr/xexpr.h
ali@0
    12
 *
ali@0
    13
 * The various types defined in libxexpr and the functions that support them.
ali@0
    14
 */
ali@0
    15
ali@0
    16
static XexprEnvironment *xexpr_environment_new(const char *function,
ali@0
    17
  XexprEnvironment *outer);
ali@0
    18
ali@0
    19
/**
ali@0
    20
 * xexpr_binding_free:
ali@0
    21
 * @binding: an #XexprBinding
ali@0
    22
 *
ali@0
    23
 * Frees the memory allocated for the #XexprBinding.
ali@0
    24
 */
ali@0
    25
void xexpr_binding_free(XexprBinding *binding)
ali@0
    26
{
ali@0
    27
    g_free(binding->id);
ali@0
    28
    xexpr_constant_free(binding->value);
ali@0
    29
    g_slice_free(XexprBinding,binding);
ali@0
    30
}
ali@0
    31
ali@0
    32
/**
ali@0
    33
 * xexpr_environment_free:
ali@0
    34
 * @environment: an #XexprEnvironment
ali@0
    35
 *
ali@0
    36
 * Frees the memory allocated for the #XexprEnvironment.
ali@0
    37
 */
ali@0
    38
static void xexpr_environment_free(XexprEnvironment *environment)
ali@0
    39
{
ali@0
    40
    g_warn_if_fail(environment->refcount==1);
ali@0
    41
    if (environment->outer)
ali@0
    42
	environment->outer->refcount--;
ali@0
    43
    g_free(environment->function);
ali@0
    44
    g_slist_foreach(environment->bindings,(GFunc)xexpr_binding_free,NULL);
ali@0
    45
    g_slist_free(environment->bindings);
ali@0
    46
    g_slice_free(XexprEnvironment,environment);
ali@0
    47
}
ali@0
    48
ali@0
    49
/*
ali@0
    50
 * xexpr_invocation_free:
ali@0
    51
 * @invocation: an #XexprInvocation
ali@0
    52
 *
ali@0
    53
 * Frees the memory allocated for the #XexprInvocation.
ali@0
    54
 */
ali@0
    55
static void xexpr_invocation_free(XexprInvocation *invocation)
ali@0
    56
{
ali@0
    57
    g_free(invocation->function);
ali@0
    58
    g_slist_foreach(invocation->bindings,(GFunc)xexpr_binding_free,NULL);
ali@0
    59
    g_slist_free(invocation->bindings);
ali@0
    60
    g_slist_foreach(invocation->constants,(GFunc)xexpr_constant_free,NULL);
ali@0
    61
    g_slist_free(invocation->constants);
ali@0
    62
    g_slice_free(XexprInvocation,invocation);
ali@0
    63
}
ali@0
    64
ali@0
    65
/*
ali@0
    66
 * xexpr_function_free:
ali@0
    67
 * @function: an #XexprFunction
ali@0
    68
 *
ali@0
    69
 * Frees the memory allocated for the #XexprFunction.
ali@0
    70
 */
ali@0
    71
static void xexpr_function_free(XexprFunction *function)
ali@0
    72
{
ali@0
    73
    g_slist_foreach(function->args,(GFunc)g_free,NULL);
ali@0
    74
    g_slist_free(function->args);
ali@0
    75
    g_slist_foreach(function->constants,(GFunc)xexpr_constant_free,NULL);
ali@0
    76
    g_slist_free(function->constants);
ali@0
    77
    g_slice_free(XexprFunction,function);
ali@0
    78
}
ali@0
    79
ali@0
    80
/**
ali@0
    81
 * xexpr_constant_free:
ali@0
    82
 * @constant: an #XexprConstant
ali@0
    83
 *
ali@0
    84
 * Frees the memory allocated for the #XexprConstant.
ali@0
    85
 */
ali@0
    86
void xexpr_constant_free(XexprConstant *constant)
ali@0
    87
{
ali@0
    88
    switch(constant->type)
ali@0
    89
    {
ali@0
    90
	case XEXPR_TYPE_INVOCATION:
ali@0
    91
	    xexpr_invocation_free(constant->u.invocation);
ali@0
    92
	    break;
ali@0
    93
	case XEXPR_TYPE_FUNCTION:
ali@0
    94
	    xexpr_function_free(constant->u.function);
ali@0
    95
	    break;
ali@0
    96
	case XEXPR_TYPE_STRING:
ali@0
    97
	    g_free(constant->u.string);
ali@0
    98
	    break;
ali@0
    99
	case XEXPR_TYPE_INTEGER:
ali@0
   100
	case XEXPR_TYPE_NUMBER:
ali@0
   101
	    break;
ali@0
   102
    }
ali@0
   103
    g_slice_free(XexprConstant,constant);
ali@0
   104
}
ali@0
   105
ali@0
   106
/**
ali@0
   107
 * xexpr_free:
ali@0
   108
 * @xexpr: an #Xexpr
ali@0
   109
 *
ali@0
   110
 * Frees the memory allocated for the #Xexpr.
ali@0
   111
 */
ali@0
   112
void xexpr_free(Xexpr *xexpr)
ali@0
   113
{
ali@0
   114
    g_slist_foreach(xexpr->tracing,(GFunc)g_free,NULL);
ali@0
   115
    g_slist_free(xexpr->tracing);
ali@0
   116
    g_slist_foreach(xexpr->constants,(GFunc)xexpr_constant_free,NULL);
ali@0
   117
    g_slist_free(xexpr->constants);
ali@0
   118
    g_slice_free(Xexpr,xexpr);
ali@0
   119
}
ali@0
   120
ali@0
   121
/**
ali@0
   122
 * xexpr_new:
ali@0
   123
 *
ali@0
   124
 * Creates a new #Xexpr.
ali@0
   125
 *
ali@0
   126
 * Returns: the new #Xexpr
ali@0
   127
 */
ali@0
   128
Xexpr *xexpr_new(void)
ali@0
   129
{
ali@0
   130
    xexpr_register_extension(NULL);
ali@0
   131
    return g_slice_new0(Xexpr);
ali@0
   132
}
ali@0
   133
ali@0
   134
/**
ali@0
   135
 * xexpr_sub:
ali@0
   136
 * @xexpr: an #Xexpr to copy the initial options from
ali@0
   137
 *
ali@0
   138
 * Creates a new #Xexpr, copying options from @xexpr.
ali@0
   139
 *
ali@0
   140
 * Returns: the new #Xexpr
ali@0
   141
 */
ali@0
   142
Xexpr *xexpr_sub(Xexpr *xexpr)
ali@0
   143
{
ali@0
   144
    GSList *lnk;
ali@0
   145
    Xexpr *sub=xexpr_new();
ali@0
   146
    sub->tracing=g_slist_copy(xexpr->tracing);
ali@0
   147
    for(lnk=sub->tracing;lnk;lnk=lnk->next)
ali@0
   148
	lnk->data=g_strdup(lnk->data);
ali@0
   149
    return sub;
ali@0
   150
}
ali@0
   151
ali@0
   152
/**
ali@0
   153
 * xexpr_is_tracing:
ali@0
   154
 * @xexpr: an #Xexpr
ali@0
   155
 * @id: the symbol to test for
ali@0
   156
 *
ali@0
   157
 * Checks if a symbol is currently being traced, returning %TRUE if it is.
ali@0
   158
 *
ali@0
   159
 * Returns: %TRUE if @id is being traced
ali@0
   160
 */
ali@0
   161
gboolean xexpr_is_tracing(Xexpr *xexpr,const char *id)
ali@0
   162
{
ali@0
   163
    return !!g_slist_find_custom(xexpr->tracing,id,(GCompareFunc)g_strcmp0);
ali@0
   164
}
ali@0
   165
ali@0
   166
/**
ali@0
   167
 * xexpr_start_tracing:
ali@0
   168
 * @xexpr: an #Xexpr
ali@0
   169
 * @id: the symbol to trace
ali@0
   170
 *
ali@0
   171
 * Adds @id to the set of symbols to trace.
ali@0
   172
 *
ali@0
   173
 * When variables with the name of a traced symbol are created or changed,
ali@0
   174
 * the evaluator will output a suitable tracing message and a stack dump.
ali@0
   175
 *
ali@0
   176
 * <example>
ali@0
   177
 *   <title>Example Tracing Output</title>
ali@0
   178
 *   <screen>
ali@0
   179
 *     Created new variable x in frame \#0
ali@0
   180
 *     \#0  test1 (x = &lt;nil/&gt;)
ali@0
   181
 *     \#1  eq ()
ali@0
   182
 *     \#2  if ()
ali@0
   183
 *     \#3  and ()
ali@0
   184
 *     \#4  expr ()
ali@0
   185
 *     
ali@0
   186
 *     Set variable x
ali@0
   187
 *     \#0  test1 (x = &lt;integer&gt;1&lt;/integer&gt;)
ali@0
   188
 *     \#1  eq ()
ali@0
   189
 *     \#2  if ()
ali@0
   190
 *     \#3  and ()
ali@0
   191
 *     \#4  expr ()
ali@0
   192
 *   </screen>
ali@0
   193
 * </example>
ali@0
   194
 */
ali@0
   195
void xexpr_start_tracing(Xexpr *xexpr,const char *id)
ali@0
   196
{
ali@0
   197
    if (!xexpr_is_tracing(xexpr,id))
ali@0
   198
	xexpr->tracing=g_slist_prepend(xexpr->tracing,g_strdup(id));
ali@0
   199
}
ali@0
   200
ali@0
   201
/**
ali@0
   202
 * xexpr_get_environment:
ali@0
   203
 * @xexpr: an #Xexpr
ali@0
   204
 *
ali@0
   205
 * Gets the #XexprEnvironment of the given #Xexpr.
ali@0
   206
 *
ali@0
   207
 * Returns: (transfer none): the innermost environment
ali@0
   208
 */
ali@0
   209
XexprEnvironment *xexpr_get_environment(Xexpr *xexpr)
ali@0
   210
{
ali@0
   211
    if (!xexpr->environment)
ali@0
   212
	xexpr->environment=xexpr_environment_new(NULL,NULL);
ali@0
   213
    return xexpr->environment;
ali@0
   214
}
ali@0
   215
ali@0
   216
/**
ali@0
   217
 * xexpr_set_constants_take_ownership:
ali@0
   218
 * @xexpr: an #Xexpr
ali@0
   219
 * @constants: (transfer full) (element-type XexprConstant): A list of 
ali@0
   220
 *   constants to use, replacing any existing constants
ali@0
   221
 *
ali@0
   222
 * Sets the list of constants which make up the expression.
ali@0
   223
 */
ali@0
   224
void xexpr_set_constants_take_ownership(Xexpr *xexpr,GSList *constants)
ali@0
   225
{
ali@0
   226
    g_slist_foreach(xexpr->constants,(GFunc)xexpr_constant_free,NULL);
ali@0
   227
    g_slist_free(xexpr->constants);
ali@0
   228
    xexpr->constants=constants;
ali@0
   229
}
ali@0
   230
ali@0
   231
/**
ali@0
   232
 * xexpr_set_constants:
ali@0
   233
 * @xexpr: an #Xexpr
ali@0
   234
 * @constants: (transfer none) (element-type XexprConstant): A list of 
ali@0
   235
 *   constants to use, replacing any existing constants
ali@0
   236
 *
ali@0
   237
 * Sets the list of constants which make up the expression.
ali@0
   238
 */
ali@0
   239
void xexpr_set_constants(Xexpr *xexpr,GSList *constants)
ali@0
   240
{
ali@0
   241
    GSList *lnk,*copy=NULL;
ali@0
   242
    for(lnk=constants;lnk;lnk=lnk->next)
ali@0
   243
	copy=g_slist_prepend(copy,xexpr_constant_dup(lnk->data));
ali@0
   244
    copy=g_slist_reverse(copy);
ali@0
   245
    xexpr_set_constants_take_ownership(xexpr,copy);
ali@0
   246
}
ali@0
   247
ali@0
   248
void _xexpr_push_environment(Xexpr *xexpr,const char *id)
ali@0
   249
{
ali@0
   250
    xexpr->environment=xexpr_environment_new(id,xexpr_get_environment(xexpr));
ali@0
   251
}
ali@0
   252
ali@0
   253
void _xexpr_pop_environment(Xexpr *xexpr)
ali@0
   254
{
ali@0
   255
    XexprEnvironment *outer=xexpr->environment->outer;
ali@0
   256
    if (outer)
ali@0
   257
    {
ali@0
   258
	xexpr_environment_free(xexpr->environment);
ali@0
   259
	xexpr->environment=outer;
ali@0
   260
    }
ali@0
   261
}
ali@0
   262
ali@0
   263
/**
ali@0
   264
 * xexpr_new_invocation_take_ownership:
ali@0
   265
 * @ns: (transfer full): the namespace to which @function belongs, or %NULL
ali@0
   266
 * @function: (transfer full): the name of the function to be invoked
ali@0
   267
 * @bindings: (transfer full) (element-type XexprBinding): the pre-bound
ali@0
   268
 *   arguments
ali@0
   269
 * @constants: (transfer full) (element-type XexprConstant): the other
ali@0
   270
 *   arguments
ali@0
   271
 *
ali@0
   272
 * Create a new #XexprConstant that invokes @function with pre-bound arguments
ali@0
   273
 * @bindings and with @constants as further arguments. Functions with named
ali@0
   274
 * parameters will use the pre-bound arguments first if present, otherwise
ali@0
   275
 * the other arguments will be bound to the unbound parameters as needed.
ali@0
   276
 *
ali@0
   277
 * @ns should be %NULL, the empty string or %XEXPR_NS for XEXPR functions.
ali@0
   278
 *
ali@0
   279
 * Returns: (transfer full): the new #XexprConstant
ali@0
   280
 */
ali@0
   281
XexprConstant *xexpr_new_invocation_take_ownership(char *ns,char *function,
ali@0
   282
  GSList *bindings,GSList *constants)
ali@0
   283
{
ali@0
   284
    XexprConstant *constant;
ali@0
   285
    constant=g_slice_new(XexprConstant);
ali@0
   286
    constant->type=XEXPR_TYPE_INVOCATION;
ali@0
   287
    constant->u.invocation=g_slice_new(XexprInvocation);
ali@0
   288
    if (ns && (!*ns || !strcmp(ns,XEXPR_NS)))
ali@0
   289
    {
ali@0
   290
	g_free(ns);
ali@0
   291
	ns=NULL;
ali@0
   292
    }
ali@0
   293
    constant->u.invocation->ns=ns;
ali@0
   294
    constant->u.invocation->function=function;
ali@0
   295
    constant->u.invocation->bindings=bindings;
ali@0
   296
    constant->u.invocation->constants=constants;
ali@0
   297
    return constant;
ali@0
   298
}
ali@0
   299
ali@0
   300
/**
ali@0
   301
 * xexpr_new_invocation:
ali@0
   302
 * @ns: (transfer none): the namespace to which @function belongs, or %NULL
ali@0
   303
 * @function: (transfer none): the name of the function to be invoked
ali@0
   304
 * @bindings: (transfer none) (element-type XexprBinding): the pre-bound
ali@0
   305
 *   arguments
ali@0
   306
 * @constants: (transfer none) (element-type XexprConstant): the other
ali@0
   307
 *   arguments
ali@0
   308
 *
ali@0
   309
 * Create a new #XexprConstant that invokes @function with pre-bound arguments
ali@0
   310
 * @bindings and with @constants as further arguments. Functions with named
ali@0
   311
 * parameters will use the pre-bound arguments first if present, otherwise
ali@0
   312
 * the other arguments will be bound to the unbound parameters as needed.
ali@0
   313
 *
ali@0
   314
 * @ns should be %NULL, the empty string or %XEXPR_NS for XEXPR functions.
ali@0
   315
 *
ali@0
   316
 * Returns: (transfer full): the new #XexprConstant
ali@0
   317
 */
ali@0
   318
XexprConstant *xexpr_new_invocation(const char *ns,const char *function,
ali@0
   319
  GSList *bindings,GSList *constants)
ali@0
   320
{
ali@0
   321
    GSList *list,*lnk;
ali@0
   322
    list=g_slist_copy(constants);
ali@0
   323
    for(lnk=list;lnk;lnk=lnk->next)
ali@0
   324
	lnk->data=xexpr_constant_dup(lnk->data);
ali@0
   325
    if (ns && (!*ns || !strcmp(ns,XEXPR_NS)))
ali@0
   326
	ns=NULL;
ali@0
   327
    return xexpr_new_invocation_take_ownership(g_strdup(ns),g_strdup(function),
ali@0
   328
      xexpr_bindings_dup(bindings),list);
ali@0
   329
}
ali@0
   330
ali@0
   331
/**
ali@0
   332
 * xexpr_new_function_take_ownership:
ali@0
   333
 * @args: (transfer full) (element-type utf8): the parameter names
ali@0
   334
 * @constants: (transfer full) (element-type XexprConstant): the constants
ali@0
   335
 *   which will be evaluated when the function is invoked
ali@0
   336
 *
ali@0
   337
 * Create a new #XexprConstant that defines an unnamed function. Creating a
ali@0
   338
 * function definition is the first step in defining a function. The second
ali@0
   339
 * step is to bind the definition to a name, eg., using xexpr_var_new().
ali@0
   340
 *
ali@0
   341
 * Returns: (transfer full): the new #XexprConstant
ali@0
   342
 */
ali@0
   343
XexprConstant *xexpr_new_function_take_ownership(GSList *args,GSList *constants)
ali@0
   344
{
ali@0
   345
    XexprConstant *constant;
ali@0
   346
    constant=g_slice_new(XexprConstant);
ali@0
   347
    constant->type=XEXPR_TYPE_FUNCTION;
ali@0
   348
    constant->u.function=g_slice_new(XexprFunction);
ali@0
   349
    constant->u.function->args=args;
ali@0
   350
    constant->u.function->constants=constants;
ali@0
   351
    return constant;
ali@0
   352
}
ali@0
   353
ali@0
   354
/**
ali@0
   355
 * xexpr_new_function:
ali@0
   356
 * @args: (transfer none) (element-type utf8): the parameter names
ali@0
   357
 * @constants: (transfer none) (element-type XexprConstant): the constants
ali@0
   358
 *   which will be evaluated when the function is invoked
ali@0
   359
 *
ali@0
   360
 * Create a new #XexprConstant that defines an unnamed function. Creating a
ali@0
   361
 * function definition is the first step in defining a function. The second
ali@0
   362
 * step is to bind the definition to a name, eg., using xexpr_var_new().
ali@0
   363
 *
ali@0
   364
 * Returns: (transfer full): the new #XexprConstant
ali@0
   365
 */
ali@0
   366
XexprConstant *xexpr_new_function(GSList *args,GSList *constants)
ali@0
   367
{
ali@0
   368
    GSList *lnk;
ali@0
   369
    args=g_slist_copy(args);
ali@0
   370
    for(lnk=args;lnk;lnk=lnk->next)
ali@0
   371
	lnk->data=g_strdup(lnk->data);
ali@0
   372
    constants=g_slist_copy(constants);
ali@0
   373
    for(lnk=constants;lnk;lnk=lnk->next)
ali@0
   374
	lnk->data=xexpr_constant_dup(lnk->data);
ali@0
   375
    return xexpr_new_function_take_ownership(args,constants);
ali@0
   376
}
ali@0
   377
ali@0
   378
/**
ali@0
   379
 * xexpr_new_string_take_ownership:
ali@0
   380
 * @s: (transfer full): the string
ali@0
   381
 *
ali@0
   382
 * Create a new #XexprConstant that consists of the given string.
ali@0
   383
 *
ali@0
   384
 * Returns: (transfer full): the new #XexprConstant
ali@0
   385
 */
ali@0
   386
XexprConstant *xexpr_new_string_take_ownership(char *s)
ali@0
   387
{
ali@0
   388
    XexprConstant *constant;
ali@0
   389
    constant=g_slice_new(XexprConstant);
ali@0
   390
    constant->type=XEXPR_TYPE_STRING;
ali@0
   391
    constant->u.string=s;
ali@0
   392
    return constant;
ali@0
   393
}
ali@0
   394
ali@0
   395
/**
ali@0
   396
 * xexpr_new_string:
ali@0
   397
 * @s: (transfer none): the string
ali@0
   398
 * @len: length of @s to use, or -1 to treat @s as nul-terminated
ali@0
   399
 *
ali@0
   400
 * Create a new #XexprConstant that consists of the given string.
ali@0
   401
 *
ali@0
   402
 * Returns: (transfer full): the new #XexprConstant
ali@0
   403
 */
ali@0
   404
XexprConstant *xexpr_new_string(const char *s,gssize len)
ali@0
   405
{
ali@0
   406
    if (len<0)
ali@0
   407
	len=strlen(s);
ali@0
   408
    return xexpr_new_string_take_ownership(g_strndup(s,len));
ali@0
   409
}
ali@0
   410
ali@0
   411
/**
ali@0
   412
 * xexpr_new_integer:
ali@0
   413
 * @integer: the integer
ali@0
   414
 *
ali@0
   415
 * Create a new #XexprConstant that consists of the given integer.
ali@0
   416
 *
ali@0
   417
 * Returns: (transfer full): the new #XexprConstant
ali@0
   418
 */
ali@0
   419
XexprConstant *xexpr_new_integer(long long int integer)
ali@0
   420
{
ali@0
   421
    XexprConstant *constant;
ali@0
   422
    constant=g_slice_new(XexprConstant);
ali@0
   423
    constant->type=XEXPR_TYPE_INTEGER;
ali@0
   424
    constant->u.integer=integer;
ali@0
   425
    return constant;
ali@0
   426
}
ali@0
   427
ali@0
   428
/**
ali@0
   429
 * xexpr_new_number:
ali@0
   430
 * @number: the number
ali@0
   431
 *
ali@0
   432
 * Create a new #XexprConstant that consists of the given floating-point number.
ali@0
   433
 *
ali@0
   434
 * Returns: (transfer full): the new #XexprConstant
ali@0
   435
 */
ali@0
   436
XexprConstant *xexpr_new_number(double number)
ali@0
   437
{
ali@0
   438
    XexprConstant *constant;
ali@0
   439
    constant=g_slice_new(XexprConstant);
ali@0
   440
    constant->type=XEXPR_TYPE_NUMBER;
ali@0
   441
    constant->u.number=number;
ali@0
   442
    return constant;
ali@0
   443
}
ali@0
   444
ali@0
   445
static XexprEnvironment *xexpr_environment_new(const char *function,
ali@0
   446
  XexprEnvironment *outer)
ali@0
   447
{
ali@0
   448
    XexprEnvironment *environment=g_slice_new0(XexprEnvironment);
ali@0
   449
    environment->function=g_strdup(function);
ali@0
   450
    environment->refcount=1;
ali@0
   451
    environment->outer=outer;
ali@0
   452
    if (outer)
ali@0
   453
	outer->refcount++;
ali@0
   454
    return environment;
ali@0
   455
}
ali@0
   456
ali@0
   457
/**
ali@0
   458
 * xexpr_environment_foreach:
ali@0
   459
 * @environment: an #XexprEnvironment
ali@0
   460
 * @func: the function to call with each active variable
ali@0
   461
 * @user_data: user data to pass to the function
ali@0
   462
 *
ali@0
   463
 * Calls a function for each active variable in an #XexprEnvironment.
ali@0
   464
 */
ali@0
   465
void xexpr_environment_foreach(XexprEnvironment *environment,GTraverseFunc func,
ali@0
   466
  gpointer user_data)
ali@0
   467
{
ali@0
   468
    GSList *lnk;
ali@0
   469
    GSList *environments=NULL;
ali@0
   470
    GTree *active;
ali@0
   471
    XexprBinding *binding;
ali@0
   472
    while(environment)
ali@0
   473
    {
ali@0
   474
	environments=g_slist_prepend(environments,environment);
ali@0
   475
	environment=environment->outer;
ali@0
   476
    }
ali@0
   477
    active=g_tree_new((GCompareFunc)strcmp);
ali@0
   478
    while(environments)
ali@0
   479
    {
ali@0
   480
	environment=environments->data;
ali@0
   481
	environments=g_slist_delete_link(environments,environments);
ali@0
   482
	for(lnk=environment->bindings;lnk;lnk=lnk->next)
ali@0
   483
	{
ali@0
   484
	    binding=lnk->data;
ali@0
   485
	    g_tree_insert(active,binding->id,binding->value);
ali@0
   486
	}
ali@0
   487
    }
ali@0
   488
    g_tree_foreach(active,func,user_data);
ali@0
   489
    g_tree_destroy(active);
ali@0
   490
}
ali@0
   491
ali@0
   492
/**
ali@0
   493
 * xexpr_bindings_get:
ali@0
   494
 * @bindings: (transfer none) (element-type XexprBinding): the bindings to
ali@0
   495
 *   search
ali@0
   496
 * @id: the symbol to search for
ali@0
   497
 *
ali@0
   498
 * Look for a binding of symbol @id in @bindings and return the value if
ali@0
   499
 * found.
ali@0
   500
 *
ali@0
   501
 * Returns: (transfer none): the found #XexprConstant or %NULL
ali@0
   502
 */
ali@0
   503
XexprConstant *xexpr_bindings_get(GSList *bindings,const char *id)
ali@0
   504
{
ali@0
   505
    GSList *lnk;
ali@0
   506
    XexprBinding *binding;
ali@0
   507
    for(lnk=bindings;lnk;lnk=lnk->next)
ali@0
   508
    {
ali@0
   509
	binding=lnk->data;
ali@0
   510
	if (!strcmp(binding->id,id))
ali@0
   511
	    return binding->value;
ali@0
   512
    }
ali@0
   513
    return NULL;
ali@0
   514
}
ali@0
   515
ali@0
   516
/**
ali@0
   517
 * xexpr_bindings_set:
ali@0
   518
 * @bindings: (transfer none) (element-type XexprBinding): the bindings to
ali@0
   519
 *   update
ali@0
   520
 * @id: an existing symbol to set
ali@0
   521
 * @value: (transfer none): the new value
ali@0
   522
 *
ali@0
   523
 * Update an existing binding of symbol @id in @bindings with the new value
ali@0
   524
 * @value. If no existing binding is found, return %FALSE.
ali@0
   525
 *
ali@0
   526
 * Returns: %TRUE if @id was found and updated
ali@0
   527
 */
ali@0
   528
gboolean xexpr_bindings_set(GSList *bindings,const char *id,
ali@0
   529
  XexprConstant *value)
ali@0
   530
{
ali@0
   531
    GSList *lnk;
ali@0
   532
    XexprBinding *binding;
ali@0
   533
    for(lnk=bindings;lnk;lnk=lnk->next)
ali@0
   534
    {
ali@0
   535
	binding=lnk->data;
ali@0
   536
	if (!strcmp(binding->id,id))
ali@0
   537
	{
ali@0
   538
	    xexpr_constant_free(binding->value);
ali@0
   539
	    binding->value=xexpr_constant_dup(value);
ali@0
   540
	    return TRUE;
ali@0
   541
	}
ali@0
   542
    }
ali@0
   543
    return FALSE;
ali@0
   544
}
ali@0
   545
ali@0
   546
/**
ali@0
   547
 * xexpr_bindings_new:
ali@0
   548
 * @bindings: (transfer full) (element-type XexprBinding): the bindings to
ali@0
   549
 *   modify
ali@0
   550
 * @id: a symbol to set or create
ali@0
   551
 * @value: (transfer none): the new value
ali@0
   552
 *
ali@0
   553
 * Update an existing binding of symbol @id or create a new one in @bindings
ali@0
   554
 * with the new value @value.
ali@0
   555
 *
ali@0
   556
 * Returns: (transfer full) (element-type XexprBinding): the new bindings list
ali@0
   557
 */
ali@0
   558
GSList *xexpr_bindings_new(GSList *bindings,const char *id,XexprConstant *value)
ali@0
   559
{
ali@0
   560
    XexprBinding *binding;
ali@0
   561
    if (!xexpr_bindings_set(bindings,id,value))
ali@0
   562
    {
ali@0
   563
	binding=g_slice_new(XexprBinding);
ali@0
   564
	binding->id=g_strdup(id);
ali@0
   565
	binding->value=xexpr_constant_dup(value);
ali@0
   566
	bindings=g_slist_prepend(bindings,binding);
ali@0
   567
    }
ali@0
   568
    return bindings;
ali@0
   569
}
ali@0
   570
ali@0
   571
/**
ali@0
   572
 * xexpr_var_get:
ali@0
   573
 * @xexpr: an #Xexpr
ali@0
   574
 * @id: a symbol to look up
ali@0
   575
 *
ali@0
   576
 * Look for a definition of symbol @id in @xexpr and return its value. If
ali@0
   577
 * no definition exists, return %NULL.
ali@0
   578
 *
ali@0
   579
 * Returns: (transfer none): the bound value, or %NULL if not found.
ali@0
   580
 */
ali@0
   581
XexprConstant *xexpr_var_get(Xexpr *xexpr,const char *id)
ali@0
   582
{
ali@0
   583
    XexprConstant *value=NULL;
ali@0
   584
    XexprEnvironment *environment=xexpr_get_environment(xexpr);
ali@0
   585
    while(environment && !value)
ali@0
   586
    {
ali@0
   587
	value=xexpr_bindings_get(environment->bindings,id);
ali@0
   588
	environment=environment->outer;
ali@0
   589
    }
ali@0
   590
    return value;
ali@0
   591
}
ali@0
   592
ali@0
   593
/**
ali@0
   594
 * xexpr_var_new:
ali@0
   595
 * @xexpr: an #Xexpr
ali@0
   596
 * @id: a symbol to set or create
ali@0
   597
 * @value: (transfer none): the new value
ali@0
   598
 *
ali@0
   599
 * Update an existing binding of symbol @id in the innermost environment of
ali@0
   600
 * @xexpr or create a new one with the new value @value.
ali@0
   601
 */
ali@0
   602
void xexpr_var_new(Xexpr *xexpr,const char *id,XexprConstant *value)
ali@0
   603
{
ali@0
   604
    XexprEnvironment *environment=xexpr_get_environment(xexpr);
ali@0
   605
    environment->bindings=xexpr_bindings_new(environment->bindings,id,value);
ali@0
   606
    if (xexpr_is_tracing(xexpr,id))
ali@0
   607
    {
ali@0
   608
	printf("\nCreated new variable %s in frame #0\n",id);
ali@0
   609
	xexpr_stack_dump(xexpr,stdout);
ali@0
   610
    }
ali@0
   611
}
ali@0
   612
ali@0
   613
/**
ali@0
   614
 * xexpr_var_set:
ali@0
   615
 * @xexpr: an #Xexpr
ali@0
   616
 * @id: a symbol to set or create
ali@0
   617
 * @value: (transfer none): the new value
ali@0
   618
 *
ali@0
   619
 * Update the active binding of symbol @id in @xexpr if such exists or create 
ali@0
   620
 * create a new one in the outermost environment with the new value @value.
ali@0
   621
 */
ali@0
   622
void xexpr_var_set(Xexpr *xexpr,const char *id,XexprConstant *value)
ali@0
   623
{
ali@0
   624
    XexprEnvironment *environment=xexpr_get_environment(xexpr);
ali@0
   625
    while(environment)
ali@0
   626
    {
ali@0
   627
	if (xexpr_bindings_set(environment->bindings,id,value))
ali@0
   628
	{
ali@0
   629
	    if (xexpr_is_tracing(xexpr,id))
ali@0
   630
	    {
ali@0
   631
		printf("\nSet variable %s\n",id);
ali@0
   632
		xexpr_stack_dump(xexpr,stdout);
ali@0
   633
	    }
ali@0
   634
	    return;
ali@0
   635
	}
ali@0
   636
	if (environment->outer)
ali@0
   637
	    environment=environment->outer;
ali@0
   638
	else
ali@0
   639
	    break;
ali@0
   640
    }
ali@0
   641
    environment->bindings=xexpr_bindings_new(environment->bindings,id,value);
ali@0
   642
    if (xexpr_is_tracing(xexpr,id))
ali@0
   643
    {
ali@0
   644
	printf("\nCreated new global variable %s\n",id);
ali@0
   645
	xexpr_stack_dump(xexpr,stdout);
ali@0
   646
    }
ali@0
   647
}
ali@0
   648
ali@0
   649
/**
ali@0
   650
 * xexpr_constant_dup:
ali@0
   651
 * @constant: an #XexprConstant to duplicate
ali@0
   652
 *
ali@0
   653
 * Duplicate @constant.
ali@0
   654
 *
ali@0
   655
 * Returns: (transfer full): the new #XexprConstant
ali@0
   656
 */
ali@0
   657
XexprConstant *xexpr_constant_dup(XexprConstant *constant)
ali@0
   658
{
ali@0
   659
    switch(constant->type)
ali@0
   660
    {
ali@0
   661
	case XEXPR_TYPE_INVOCATION:
ali@0
   662
	    return xexpr_new_invocation(constant->u.invocation->ns,
ali@0
   663
	      constant->u.invocation->function,constant->u.invocation->bindings,
ali@0
   664
	      constant->u.invocation->constants);
ali@0
   665
	    break;
ali@0
   666
	case XEXPR_TYPE_FUNCTION:
ali@0
   667
	    return xexpr_new_function(constant->u.function->args,
ali@0
   668
	      constant->u.function->constants);
ali@0
   669
	    break;
ali@0
   670
	case XEXPR_TYPE_STRING:
ali@0
   671
	    return xexpr_new_string(constant->u.string,-1);
ali@0
   672
	    break;
ali@0
   673
	case XEXPR_TYPE_INTEGER:
ali@0
   674
	    return xexpr_new_integer(constant->u.integer);
ali@0
   675
	    break;
ali@0
   676
	case XEXPR_TYPE_NUMBER:
ali@0
   677
	    return xexpr_new_number(constant->u.number);
ali@0
   678
	    break;
ali@0
   679
    }
ali@0
   680
    return NULL;
ali@0
   681
}
ali@0
   682
ali@0
   683
/**
ali@0
   684
 * xexpr_bindings_dup:
ali@0
   685
 * @bindings: (transfer none) (element-type XexprBinding): a list of bindings
ali@0
   686
 *   to duplicate
ali@0
   687
 *
ali@0
   688
 * Duplicate @bindings.
ali@0
   689
 *
ali@0
   690
 * Returns: (transfer full) (element-type XexprBinging): the new bindings list
ali@0
   691
 */
ali@0
   692
GSList *xexpr_bindings_dup(GSList *bindings)
ali@0
   693
{
ali@0
   694
    GSList *lnk,*list=NULL;
ali@0
   695
    XexprBinding *binding,*dup;
ali@0
   696
    for(lnk=bindings;lnk;lnk=lnk->next)
ali@0
   697
    {
ali@0
   698
	binding=lnk->data;
ali@0
   699
	dup=g_slice_new(XexprBinding);
ali@0
   700
	dup->id=g_strdup(binding->id);
ali@0
   701
	dup->value=xexpr_constant_dup(binding->value);
ali@0
   702
	list=g_slist_prepend(list,dup);
ali@0
   703
    }
ali@0
   704
    return g_slist_reverse(list);
ali@0
   705
}