ali@0: #include ali@0: #include ali@0: #include ali@0: #include ali@0: #include "xexprprivate.h" ali@0: ali@0: /** ali@0: * SECTION:xexprtypes ali@0: * @short_description: Types defined in libxexpr ali@0: * @stability: Stable ali@0: * @include: libxexpr/xexpr.h ali@0: * ali@0: * The various types defined in libxexpr and the functions that support them. ali@0: */ ali@0: ali@0: static XexprEnvironment *xexpr_environment_new(const char *function, ali@0: XexprEnvironment *outer); ali@0: ali@0: /** ali@0: * xexpr_binding_free: ali@0: * @binding: an #XexprBinding ali@0: * ali@0: * Frees the memory allocated for the #XexprBinding. ali@0: */ ali@0: void xexpr_binding_free(XexprBinding *binding) ali@0: { ali@0: g_free(binding->id); ali@0: xexpr_constant_free(binding->value); ali@0: g_slice_free(XexprBinding,binding); ali@0: } ali@0: ali@0: /** ali@0: * xexpr_environment_free: ali@0: * @environment: an #XexprEnvironment ali@0: * ali@0: * Frees the memory allocated for the #XexprEnvironment. ali@0: */ ali@0: static void xexpr_environment_free(XexprEnvironment *environment) ali@0: { ali@0: g_warn_if_fail(environment->refcount==1); ali@0: if (environment->outer) ali@0: environment->outer->refcount--; ali@0: g_free(environment->function); ali@0: g_slist_foreach(environment->bindings,(GFunc)xexpr_binding_free,NULL); ali@0: g_slist_free(environment->bindings); ali@0: g_slice_free(XexprEnvironment,environment); ali@0: } ali@0: ali@0: /* ali@0: * xexpr_invocation_free: ali@0: * @invocation: an #XexprInvocation ali@0: * ali@0: * Frees the memory allocated for the #XexprInvocation. ali@0: */ ali@0: static void xexpr_invocation_free(XexprInvocation *invocation) ali@0: { ali@0: g_free(invocation->function); ali@0: g_slist_foreach(invocation->bindings,(GFunc)xexpr_binding_free,NULL); ali@0: g_slist_free(invocation->bindings); ali@0: g_slist_foreach(invocation->constants,(GFunc)xexpr_constant_free,NULL); ali@0: g_slist_free(invocation->constants); ali@0: g_slice_free(XexprInvocation,invocation); ali@0: } ali@0: ali@0: /* ali@0: * xexpr_function_free: ali@0: * @function: an #XexprFunction ali@0: * ali@0: * Frees the memory allocated for the #XexprFunction. ali@0: */ ali@0: static void xexpr_function_free(XexprFunction *function) ali@0: { ali@0: g_slist_foreach(function->args,(GFunc)g_free,NULL); ali@0: g_slist_free(function->args); ali@0: g_slist_foreach(function->constants,(GFunc)xexpr_constant_free,NULL); ali@0: g_slist_free(function->constants); ali@0: g_slice_free(XexprFunction,function); ali@0: } ali@0: ali@0: /** ali@0: * xexpr_constant_free: ali@0: * @constant: an #XexprConstant ali@0: * ali@0: * Frees the memory allocated for the #XexprConstant. ali@0: */ ali@0: void xexpr_constant_free(XexprConstant *constant) ali@0: { ali@0: switch(constant->type) ali@0: { ali@0: case XEXPR_TYPE_INVOCATION: ali@0: xexpr_invocation_free(constant->u.invocation); ali@0: break; ali@0: case XEXPR_TYPE_FUNCTION: ali@0: xexpr_function_free(constant->u.function); ali@0: break; ali@0: case XEXPR_TYPE_STRING: ali@0: g_free(constant->u.string); ali@0: break; ali@0: case XEXPR_TYPE_INTEGER: ali@0: case XEXPR_TYPE_NUMBER: ali@0: break; ali@0: } ali@0: g_slice_free(XexprConstant,constant); ali@0: } ali@0: ali@0: /** ali@0: * xexpr_free: ali@0: * @xexpr: an #Xexpr ali@0: * ali@0: * Frees the memory allocated for the #Xexpr. ali@0: */ ali@0: void xexpr_free(Xexpr *xexpr) ali@0: { ali@0: g_slist_foreach(xexpr->tracing,(GFunc)g_free,NULL); ali@0: g_slist_free(xexpr->tracing); ali@0: g_slist_foreach(xexpr->constants,(GFunc)xexpr_constant_free,NULL); ali@0: g_slist_free(xexpr->constants); ali@0: g_slice_free(Xexpr,xexpr); ali@0: } ali@0: ali@0: /** ali@0: * xexpr_new: ali@0: * ali@0: * Creates a new #Xexpr. ali@0: * ali@0: * Returns: the new #Xexpr ali@0: */ ali@0: Xexpr *xexpr_new(void) ali@0: { ali@0: xexpr_register_extension(NULL); ali@0: return g_slice_new0(Xexpr); ali@0: } ali@0: ali@0: /** ali@0: * xexpr_sub: ali@0: * @xexpr: an #Xexpr to copy the initial options from ali@0: * ali@0: * Creates a new #Xexpr, copying options from @xexpr. ali@0: * ali@0: * Returns: the new #Xexpr ali@0: */ ali@0: Xexpr *xexpr_sub(Xexpr *xexpr) ali@0: { ali@0: GSList *lnk; ali@0: Xexpr *sub=xexpr_new(); ali@0: sub->tracing=g_slist_copy(xexpr->tracing); ali@0: for(lnk=sub->tracing;lnk;lnk=lnk->next) ali@0: lnk->data=g_strdup(lnk->data); ali@0: return sub; ali@0: } ali@0: ali@0: /** ali@0: * xexpr_is_tracing: ali@0: * @xexpr: an #Xexpr ali@0: * @id: the symbol to test for ali@0: * ali@0: * Checks if a symbol is currently being traced, returning %TRUE if it is. ali@0: * ali@0: * Returns: %TRUE if @id is being traced ali@0: */ ali@0: gboolean xexpr_is_tracing(Xexpr *xexpr,const char *id) ali@0: { ali@0: return !!g_slist_find_custom(xexpr->tracing,id,(GCompareFunc)g_strcmp0); ali@0: } ali@0: ali@0: /** ali@0: * xexpr_start_tracing: ali@0: * @xexpr: an #Xexpr ali@0: * @id: the symbol to trace ali@0: * ali@0: * Adds @id to the set of symbols to trace. ali@0: * ali@0: * When variables with the name of a traced symbol are created or changed, ali@0: * the evaluator will output a suitable tracing message and a stack dump. ali@0: * ali@0: * ali@0: * Example Tracing Output ali@0: * ali@0: * Created new variable x in frame \#0 ali@0: * \#0 test1 (x = <nil/>) ali@0: * \#1 eq () ali@0: * \#2 if () ali@0: * \#3 and () ali@0: * \#4 expr () ali@0: * ali@0: * Set variable x ali@0: * \#0 test1 (x = <integer>1</integer>) ali@0: * \#1 eq () ali@0: * \#2 if () ali@0: * \#3 and () ali@0: * \#4 expr () ali@0: * ali@0: * ali@0: */ ali@0: void xexpr_start_tracing(Xexpr *xexpr,const char *id) ali@0: { ali@0: if (!xexpr_is_tracing(xexpr,id)) ali@0: xexpr->tracing=g_slist_prepend(xexpr->tracing,g_strdup(id)); ali@0: } ali@0: ali@0: /** ali@0: * xexpr_get_environment: ali@0: * @xexpr: an #Xexpr ali@0: * ali@0: * Gets the #XexprEnvironment of the given #Xexpr. ali@0: * ali@0: * Returns: (transfer none): the innermost environment ali@0: */ ali@0: XexprEnvironment *xexpr_get_environment(Xexpr *xexpr) ali@0: { ali@0: if (!xexpr->environment) ali@0: xexpr->environment=xexpr_environment_new(NULL,NULL); ali@0: return xexpr->environment; ali@0: } ali@0: ali@0: /** ali@0: * xexpr_set_constants_take_ownership: ali@0: * @xexpr: an #Xexpr ali@0: * @constants: (transfer full) (element-type XexprConstant): A list of ali@0: * constants to use, replacing any existing constants ali@0: * ali@0: * Sets the list of constants which make up the expression. ali@0: */ ali@0: void xexpr_set_constants_take_ownership(Xexpr *xexpr,GSList *constants) ali@0: { ali@0: g_slist_foreach(xexpr->constants,(GFunc)xexpr_constant_free,NULL); ali@0: g_slist_free(xexpr->constants); ali@0: xexpr->constants=constants; ali@0: } ali@0: ali@0: /** ali@0: * xexpr_set_constants: ali@0: * @xexpr: an #Xexpr ali@0: * @constants: (transfer none) (element-type XexprConstant): A list of ali@0: * constants to use, replacing any existing constants ali@0: * ali@0: * Sets the list of constants which make up the expression. ali@0: */ ali@0: void xexpr_set_constants(Xexpr *xexpr,GSList *constants) ali@0: { ali@0: GSList *lnk,*copy=NULL; ali@0: for(lnk=constants;lnk;lnk=lnk->next) ali@0: copy=g_slist_prepend(copy,xexpr_constant_dup(lnk->data)); ali@0: copy=g_slist_reverse(copy); ali@0: xexpr_set_constants_take_ownership(xexpr,copy); ali@0: } ali@0: ali@0: void _xexpr_push_environment(Xexpr *xexpr,const char *id) ali@0: { ali@0: xexpr->environment=xexpr_environment_new(id,xexpr_get_environment(xexpr)); ali@0: } ali@0: ali@0: void _xexpr_pop_environment(Xexpr *xexpr) ali@0: { ali@0: XexprEnvironment *outer=xexpr->environment->outer; ali@0: if (outer) ali@0: { ali@0: xexpr_environment_free(xexpr->environment); ali@0: xexpr->environment=outer; ali@0: } ali@0: } ali@0: ali@0: /** ali@0: * xexpr_new_invocation_take_ownership: ali@0: * @ns: (transfer full): the namespace to which @function belongs, or %NULL ali@0: * @function: (transfer full): the name of the function to be invoked ali@0: * @bindings: (transfer full) (element-type XexprBinding): the pre-bound ali@0: * arguments ali@0: * @constants: (transfer full) (element-type XexprConstant): the other ali@0: * arguments ali@0: * ali@0: * Create a new #XexprConstant that invokes @function with pre-bound arguments ali@0: * @bindings and with @constants as further arguments. Functions with named ali@0: * parameters will use the pre-bound arguments first if present, otherwise ali@0: * the other arguments will be bound to the unbound parameters as needed. ali@0: * ali@0: * @ns should be %NULL, the empty string or %XEXPR_NS for XEXPR functions. ali@0: * ali@0: * Returns: (transfer full): the new #XexprConstant ali@0: */ ali@0: XexprConstant *xexpr_new_invocation_take_ownership(char *ns,char *function, ali@0: GSList *bindings,GSList *constants) ali@0: { ali@0: XexprConstant *constant; ali@0: constant=g_slice_new(XexprConstant); ali@0: constant->type=XEXPR_TYPE_INVOCATION; ali@0: constant->u.invocation=g_slice_new(XexprInvocation); ali@0: if (ns && (!*ns || !strcmp(ns,XEXPR_NS))) ali@0: { ali@0: g_free(ns); ali@0: ns=NULL; ali@0: } ali@0: constant->u.invocation->ns=ns; ali@0: constant->u.invocation->function=function; ali@0: constant->u.invocation->bindings=bindings; ali@0: constant->u.invocation->constants=constants; ali@0: return constant; ali@0: } ali@0: ali@0: /** ali@0: * xexpr_new_invocation: ali@0: * @ns: (transfer none): the namespace to which @function belongs, or %NULL ali@0: * @function: (transfer none): the name of the function to be invoked ali@0: * @bindings: (transfer none) (element-type XexprBinding): the pre-bound ali@0: * arguments ali@0: * @constants: (transfer none) (element-type XexprConstant): the other ali@0: * arguments ali@0: * ali@0: * Create a new #XexprConstant that invokes @function with pre-bound arguments ali@0: * @bindings and with @constants as further arguments. Functions with named ali@0: * parameters will use the pre-bound arguments first if present, otherwise ali@0: * the other arguments will be bound to the unbound parameters as needed. ali@0: * ali@0: * @ns should be %NULL, the empty string or %XEXPR_NS for XEXPR functions. ali@0: * ali@0: * Returns: (transfer full): the new #XexprConstant ali@0: */ ali@0: XexprConstant *xexpr_new_invocation(const char *ns,const char *function, ali@0: GSList *bindings,GSList *constants) ali@0: { ali@0: GSList *list,*lnk; ali@0: list=g_slist_copy(constants); ali@0: for(lnk=list;lnk;lnk=lnk->next) ali@0: lnk->data=xexpr_constant_dup(lnk->data); ali@0: if (ns && (!*ns || !strcmp(ns,XEXPR_NS))) ali@0: ns=NULL; ali@0: return xexpr_new_invocation_take_ownership(g_strdup(ns),g_strdup(function), ali@0: xexpr_bindings_dup(bindings),list); ali@0: } ali@0: ali@0: /** ali@0: * xexpr_new_function_take_ownership: ali@0: * @args: (transfer full) (element-type utf8): the parameter names ali@0: * @constants: (transfer full) (element-type XexprConstant): the constants ali@0: * which will be evaluated when the function is invoked ali@0: * ali@0: * Create a new #XexprConstant that defines an unnamed function. Creating a ali@0: * function definition is the first step in defining a function. The second ali@0: * step is to bind the definition to a name, eg., using xexpr_var_new(). ali@0: * ali@0: * Returns: (transfer full): the new #XexprConstant ali@0: */ ali@0: XexprConstant *xexpr_new_function_take_ownership(GSList *args,GSList *constants) ali@0: { ali@0: XexprConstant *constant; ali@0: constant=g_slice_new(XexprConstant); ali@0: constant->type=XEXPR_TYPE_FUNCTION; ali@0: constant->u.function=g_slice_new(XexprFunction); ali@0: constant->u.function->args=args; ali@0: constant->u.function->constants=constants; ali@0: return constant; ali@0: } ali@0: ali@0: /** ali@0: * xexpr_new_function: ali@0: * @args: (transfer none) (element-type utf8): the parameter names ali@0: * @constants: (transfer none) (element-type XexprConstant): the constants ali@0: * which will be evaluated when the function is invoked ali@0: * ali@0: * Create a new #XexprConstant that defines an unnamed function. Creating a ali@0: * function definition is the first step in defining a function. The second ali@0: * step is to bind the definition to a name, eg., using xexpr_var_new(). ali@0: * ali@0: * Returns: (transfer full): the new #XexprConstant ali@0: */ ali@0: XexprConstant *xexpr_new_function(GSList *args,GSList *constants) ali@0: { ali@0: GSList *lnk; ali@0: args=g_slist_copy(args); ali@0: for(lnk=args;lnk;lnk=lnk->next) ali@0: lnk->data=g_strdup(lnk->data); ali@0: constants=g_slist_copy(constants); ali@0: for(lnk=constants;lnk;lnk=lnk->next) ali@0: lnk->data=xexpr_constant_dup(lnk->data); ali@0: return xexpr_new_function_take_ownership(args,constants); ali@0: } ali@0: ali@0: /** ali@0: * xexpr_new_string_take_ownership: ali@0: * @s: (transfer full): the string ali@0: * ali@0: * Create a new #XexprConstant that consists of the given string. ali@0: * ali@0: * Returns: (transfer full): the new #XexprConstant ali@0: */ ali@0: XexprConstant *xexpr_new_string_take_ownership(char *s) ali@0: { ali@0: XexprConstant *constant; ali@0: constant=g_slice_new(XexprConstant); ali@0: constant->type=XEXPR_TYPE_STRING; ali@0: constant->u.string=s; ali@0: return constant; ali@0: } ali@0: ali@0: /** ali@0: * xexpr_new_string: ali@0: * @s: (transfer none): the string ali@0: * @len: length of @s to use, or -1 to treat @s as nul-terminated ali@0: * ali@0: * Create a new #XexprConstant that consists of the given string. ali@0: * ali@0: * Returns: (transfer full): the new #XexprConstant ali@0: */ ali@0: XexprConstant *xexpr_new_string(const char *s,gssize len) ali@0: { ali@0: if (len<0) ali@0: len=strlen(s); ali@0: return xexpr_new_string_take_ownership(g_strndup(s,len)); ali@0: } ali@0: ali@0: /** ali@0: * xexpr_new_integer: ali@0: * @integer: the integer ali@0: * ali@0: * Create a new #XexprConstant that consists of the given integer. ali@0: * ali@0: * Returns: (transfer full): the new #XexprConstant ali@0: */ ali@0: XexprConstant *xexpr_new_integer(long long int integer) ali@0: { ali@0: XexprConstant *constant; ali@0: constant=g_slice_new(XexprConstant); ali@0: constant->type=XEXPR_TYPE_INTEGER; ali@0: constant->u.integer=integer; ali@0: return constant; ali@0: } ali@0: ali@0: /** ali@0: * xexpr_new_number: ali@0: * @number: the number ali@0: * ali@0: * Create a new #XexprConstant that consists of the given floating-point number. ali@0: * ali@0: * Returns: (transfer full): the new #XexprConstant ali@0: */ ali@0: XexprConstant *xexpr_new_number(double number) ali@0: { ali@0: XexprConstant *constant; ali@0: constant=g_slice_new(XexprConstant); ali@0: constant->type=XEXPR_TYPE_NUMBER; ali@0: constant->u.number=number; ali@0: return constant; ali@0: } ali@0: ali@0: static XexprEnvironment *xexpr_environment_new(const char *function, ali@0: XexprEnvironment *outer) ali@0: { ali@0: XexprEnvironment *environment=g_slice_new0(XexprEnvironment); ali@0: environment->function=g_strdup(function); ali@0: environment->refcount=1; ali@0: environment->outer=outer; ali@0: if (outer) ali@0: outer->refcount++; ali@0: return environment; ali@0: } ali@0: ali@0: /** ali@0: * xexpr_environment_foreach: ali@0: * @environment: an #XexprEnvironment ali@0: * @func: the function to call with each active variable ali@0: * @user_data: user data to pass to the function ali@0: * ali@0: * Calls a function for each active variable in an #XexprEnvironment. ali@0: */ ali@0: void xexpr_environment_foreach(XexprEnvironment *environment,GTraverseFunc func, ali@0: gpointer user_data) ali@0: { ali@0: GSList *lnk; ali@0: GSList *environments=NULL; ali@0: GTree *active; ali@0: XexprBinding *binding; ali@0: while(environment) ali@0: { ali@0: environments=g_slist_prepend(environments,environment); ali@0: environment=environment->outer; ali@0: } ali@0: active=g_tree_new((GCompareFunc)strcmp); ali@0: while(environments) ali@0: { ali@0: environment=environments->data; ali@0: environments=g_slist_delete_link(environments,environments); ali@0: for(lnk=environment->bindings;lnk;lnk=lnk->next) ali@0: { ali@0: binding=lnk->data; ali@0: g_tree_insert(active,binding->id,binding->value); ali@0: } ali@0: } ali@0: g_tree_foreach(active,func,user_data); ali@0: g_tree_destroy(active); ali@0: } ali@0: ali@0: /** ali@0: * xexpr_bindings_get: ali@0: * @bindings: (transfer none) (element-type XexprBinding): the bindings to ali@0: * search ali@0: * @id: the symbol to search for ali@0: * ali@0: * Look for a binding of symbol @id in @bindings and return the value if ali@0: * found. ali@0: * ali@0: * Returns: (transfer none): the found #XexprConstant or %NULL ali@0: */ ali@0: XexprConstant *xexpr_bindings_get(GSList *bindings,const char *id) ali@0: { ali@0: GSList *lnk; ali@0: XexprBinding *binding; ali@0: for(lnk=bindings;lnk;lnk=lnk->next) ali@0: { ali@0: binding=lnk->data; ali@0: if (!strcmp(binding->id,id)) ali@0: return binding->value; ali@0: } ali@0: return NULL; ali@0: } ali@0: ali@0: /** ali@0: * xexpr_bindings_set: ali@0: * @bindings: (transfer none) (element-type XexprBinding): the bindings to ali@0: * update ali@0: * @id: an existing symbol to set ali@0: * @value: (transfer none): the new value ali@0: * ali@0: * Update an existing binding of symbol @id in @bindings with the new value ali@0: * @value. If no existing binding is found, return %FALSE. ali@0: * ali@0: * Returns: %TRUE if @id was found and updated ali@0: */ ali@0: gboolean xexpr_bindings_set(GSList *bindings,const char *id, ali@0: XexprConstant *value) ali@0: { ali@0: GSList *lnk; ali@0: XexprBinding *binding; ali@0: for(lnk=bindings;lnk;lnk=lnk->next) ali@0: { ali@0: binding=lnk->data; ali@0: if (!strcmp(binding->id,id)) ali@0: { ali@0: xexpr_constant_free(binding->value); ali@0: binding->value=xexpr_constant_dup(value); ali@0: return TRUE; ali@0: } ali@0: } ali@0: return FALSE; ali@0: } ali@0: ali@0: /** ali@0: * xexpr_bindings_new: ali@0: * @bindings: (transfer full) (element-type XexprBinding): the bindings to ali@0: * modify ali@0: * @id: a symbol to set or create ali@0: * @value: (transfer none): the new value ali@0: * ali@0: * Update an existing binding of symbol @id or create a new one in @bindings ali@0: * with the new value @value. ali@0: * ali@0: * Returns: (transfer full) (element-type XexprBinding): the new bindings list ali@0: */ ali@0: GSList *xexpr_bindings_new(GSList *bindings,const char *id,XexprConstant *value) ali@0: { ali@0: XexprBinding *binding; ali@0: if (!xexpr_bindings_set(bindings,id,value)) ali@0: { ali@0: binding=g_slice_new(XexprBinding); ali@0: binding->id=g_strdup(id); ali@0: binding->value=xexpr_constant_dup(value); ali@0: bindings=g_slist_prepend(bindings,binding); ali@0: } ali@0: return bindings; ali@0: } ali@0: ali@0: /** ali@0: * xexpr_var_get: ali@0: * @xexpr: an #Xexpr ali@0: * @id: a symbol to look up ali@0: * ali@0: * Look for a definition of symbol @id in @xexpr and return its value. If ali@0: * no definition exists, return %NULL. ali@0: * ali@0: * Returns: (transfer none): the bound value, or %NULL if not found. ali@0: */ ali@0: XexprConstant *xexpr_var_get(Xexpr *xexpr,const char *id) ali@0: { ali@0: XexprConstant *value=NULL; ali@0: XexprEnvironment *environment=xexpr_get_environment(xexpr); ali@0: while(environment && !value) ali@0: { ali@0: value=xexpr_bindings_get(environment->bindings,id); ali@0: environment=environment->outer; ali@0: } ali@0: return value; ali@0: } ali@0: ali@0: /** ali@0: * xexpr_var_new: ali@0: * @xexpr: an #Xexpr ali@0: * @id: a symbol to set or create ali@0: * @value: (transfer none): the new value ali@0: * ali@0: * Update an existing binding of symbol @id in the innermost environment of ali@0: * @xexpr or create a new one with the new value @value. ali@0: */ ali@0: void xexpr_var_new(Xexpr *xexpr,const char *id,XexprConstant *value) ali@0: { ali@0: XexprEnvironment *environment=xexpr_get_environment(xexpr); ali@0: environment->bindings=xexpr_bindings_new(environment->bindings,id,value); ali@0: if (xexpr_is_tracing(xexpr,id)) ali@0: { ali@0: printf("\nCreated new variable %s in frame #0\n",id); ali@0: xexpr_stack_dump(xexpr,stdout); ali@0: } ali@0: } ali@0: ali@0: /** ali@0: * xexpr_var_set: ali@0: * @xexpr: an #Xexpr ali@0: * @id: a symbol to set or create ali@0: * @value: (transfer none): the new value ali@0: * ali@0: * Update the active binding of symbol @id in @xexpr if such exists or create ali@0: * create a new one in the outermost environment with the new value @value. ali@0: */ ali@0: void xexpr_var_set(Xexpr *xexpr,const char *id,XexprConstant *value) ali@0: { ali@0: XexprEnvironment *environment=xexpr_get_environment(xexpr); ali@0: while(environment) ali@0: { ali@0: if (xexpr_bindings_set(environment->bindings,id,value)) ali@0: { ali@0: if (xexpr_is_tracing(xexpr,id)) ali@0: { ali@0: printf("\nSet variable %s\n",id); ali@0: xexpr_stack_dump(xexpr,stdout); ali@0: } ali@0: return; ali@0: } ali@0: if (environment->outer) ali@0: environment=environment->outer; ali@0: else ali@0: break; ali@0: } ali@0: environment->bindings=xexpr_bindings_new(environment->bindings,id,value); ali@0: if (xexpr_is_tracing(xexpr,id)) ali@0: { ali@0: printf("\nCreated new global variable %s\n",id); ali@0: xexpr_stack_dump(xexpr,stdout); ali@0: } ali@0: } ali@0: ali@0: /** ali@0: * xexpr_constant_dup: ali@0: * @constant: an #XexprConstant to duplicate ali@0: * ali@0: * Duplicate @constant. ali@0: * ali@0: * Returns: (transfer full): the new #XexprConstant ali@0: */ ali@0: XexprConstant *xexpr_constant_dup(XexprConstant *constant) ali@0: { ali@0: switch(constant->type) ali@0: { ali@0: case XEXPR_TYPE_INVOCATION: ali@0: return xexpr_new_invocation(constant->u.invocation->ns, ali@0: constant->u.invocation->function,constant->u.invocation->bindings, ali@0: constant->u.invocation->constants); ali@0: break; ali@0: case XEXPR_TYPE_FUNCTION: ali@0: return xexpr_new_function(constant->u.function->args, ali@0: constant->u.function->constants); ali@0: break; ali@0: case XEXPR_TYPE_STRING: ali@0: return xexpr_new_string(constant->u.string,-1); ali@0: break; ali@0: case XEXPR_TYPE_INTEGER: ali@0: return xexpr_new_integer(constant->u.integer); ali@0: break; ali@0: case XEXPR_TYPE_NUMBER: ali@0: return xexpr_new_number(constant->u.number); ali@0: break; ali@0: } ali@0: return NULL; ali@0: } ali@0: ali@0: /** ali@0: * xexpr_bindings_dup: ali@0: * @bindings: (transfer none) (element-type XexprBinding): a list of bindings ali@0: * to duplicate ali@0: * ali@0: * Duplicate @bindings. ali@0: * ali@0: * Returns: (transfer full) (element-type XexprBinging): the new bindings list ali@0: */ ali@0: GSList *xexpr_bindings_dup(GSList *bindings) ali@0: { ali@0: GSList *lnk,*list=NULL; ali@0: XexprBinding *binding,*dup; ali@0: for(lnk=bindings;lnk;lnk=lnk->next) ali@0: { ali@0: binding=lnk->data; ali@0: dup=g_slice_new(XexprBinding); ali@0: dup->id=g_strdup(binding->id); ali@0: dup->value=xexpr_constant_dup(binding->value); ali@0: list=g_slist_prepend(list,dup); ali@0: } ali@0: return g_slist_reverse(list); ali@0: }