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