|
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 = <nil/>)
|
|
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 = <integer>1</integer>)
|
|
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 |
}
|