1 /*
2 * expr.c : Expression evaluation in Gnumeric
3 *
4 * Copyright (C) 2001-2006 Jody Goldberg (jody@gnome.org)
5 * Copyright (C) 1998-2000 Miguel de Icaza (miguel@gnu.org)
6 * Copyright (C) 2000-2018 Morten Welinder (terra@gnome.org)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) version 3.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 */
23 #include <gnumeric-config.h>
24 #include <glib/gi18n-lib.h>
25 #include <gnumeric.h>
26 #include <expr.h>
27
28 #include <expr-impl.h>
29 #include <expr-name.h>
30 #include <dependent.h>
31 #include <application.h>
32 #include <func.h>
33 #include <cell.h>
34 #include <sheet.h>
35 #include <value.h>
36 #include <parse-util.h>
37 #include <ranges.h>
38 #include <number-match.h>
39 #include <workbook.h>
40 #include <gutils.h>
41 #include <parse-util.h>
42 #include <mathfunc.h>
43
44 #include <goffice/goffice.h>
45 #include <math.h>
46 #include <string.h>
47 #include <stdlib.h>
48
49 /*
50 * Using pools here probably does not save anything, but it's a darn
51 * good debugging tool.
52 */
53 #ifndef USE_EXPR_POOLS
54 #define USE_EXPR_POOLS 1
55 #endif
56
57 #if USE_EXPR_POOLS
58 /* Memory pools for expressions. */
59 static GOMemChunk *expression_pool_small, *expression_pool_big;
60 #define CHUNK_ALLOC(T,p) ((T*)go_mem_chunk_alloc (p))
61 #define CHUNK_FREE(p,v) go_mem_chunk_free ((p), (v))
62 #else
63 #define CHUNK_ALLOC(T,c) g_new (T,1)
64 #define CHUNK_FREE(p,v) g_free ((v))
65 #endif
66
67 /***************************************************************************/
68
69 /**
70 * gnm_expr_new_constant:
71 * @v: (transfer full): #GnmValue
72 *
73 * Returns: (transfer full): constant expression.
74 **/
75 GnmExpr const *
gnm_expr_new_constant(GnmValue * v)76 gnm_expr_new_constant (GnmValue *v)
77 {
78 GnmExprConstant *ans;
79
80 g_return_val_if_fail (v != NULL, NULL);
81
82 ans = CHUNK_ALLOC (GnmExprConstant, expression_pool_small);
83 if (!ans)
84 return NULL;
85 gnm_expr_constant_init (ans, v);
86
87 return (GnmExpr *)ans;
88 }
89
90 /***************************************************************************/
91
92 /**
93 * gnm_expr_new_funcallv: (skip)
94 * @func: #GnmFunc
95 * @argc: argument count
96 * @argv: (in) (transfer full) (array length=argc): transfers everything
97 *
98 * Returns: (transfer full): function call expression.
99 */
100 static GnmExpr const *
gnm_expr_new_funcallv(GnmFunc * func,int argc,GnmExprConstPtr * argv)101 gnm_expr_new_funcallv (GnmFunc *func, int argc, GnmExprConstPtr *argv)
102 {
103 GnmExprFunction *ans;
104 g_return_val_if_fail (func, NULL);
105
106 ans = CHUNK_ALLOC (GnmExprFunction, expression_pool_small);
107
108 ans->oper = GNM_EXPR_OP_FUNCALL;
109 gnm_func_inc_usage (func);
110 ans->func = func;
111 ans->argc = argc;
112 ans->argv = argv;
113
114 return (GnmExpr *)ans;
115 }
116
117 /**
118 * gnm_expr_new_funcall:
119 * @func: #GnmFunc
120 * @args: (transfer full): argument list
121 *
122 * Returns: (transfer full): function call expression.
123 */
124 GnmExpr const *
gnm_expr_new_funcall(GnmFunc * func,GnmExprList * args)125 gnm_expr_new_funcall (GnmFunc *func, GnmExprList *args)
126 {
127 int argc = gnm_expr_list_length (args);
128 GnmExprConstPtr *argv = NULL;
129
130 if (args) {
131 GnmExprList *args0 = args;
132 int i = 0;
133
134 argv = g_new (GnmExprConstPtr, argc);
135 for (; args; args = args->next)
136 argv[i++] = args->data;
137 gnm_expr_list_free (args0);
138 }
139
140 return gnm_expr_new_funcallv (func, argc, argv);
141 }
142
143 /**
144 * gnm_expr_new_funcall1:
145 * @func: #GnmFunc
146 * @arg0: (transfer full): argument
147 *
148 * Returns: (transfer full): function call expression.
149 */
150 GnmExpr const *
gnm_expr_new_funcall1(GnmFunc * func,GnmExpr const * arg0)151 gnm_expr_new_funcall1 (GnmFunc *func,
152 GnmExpr const *arg0)
153 {
154 GnmExprConstPtr *argv = g_new (GnmExprConstPtr, 1);
155 argv[0] = arg0;
156 return gnm_expr_new_funcallv (func, 1, argv);
157 }
158
159 /**
160 * gnm_expr_new_funcall2:
161 * @func: #GnmFunc
162 * @arg0: (transfer full): argument
163 * @arg1: (transfer full): argument
164 *
165 * Returns: (transfer full): function call expression.
166 */
167 GnmExpr const *
gnm_expr_new_funcall2(GnmFunc * func,GnmExpr const * arg0,GnmExpr const * arg1)168 gnm_expr_new_funcall2 (GnmFunc *func,
169 GnmExpr const *arg0,
170 GnmExpr const *arg1)
171 {
172 GnmExprConstPtr *argv = g_new (GnmExprConstPtr, 2);
173 argv[0] = arg0;
174 argv[1] = arg1;
175 return gnm_expr_new_funcallv (func, 2, argv);
176 }
177
178 /**
179 * gnm_expr_new_funcall3:
180 * @func: #GnmFunc
181 * @arg0: (transfer full): argument
182 * @arg1: (transfer full): argument
183 * @arg2: (transfer full): argument
184 *
185 * Returns: (transfer full): function call expression.
186 */
187 GnmExpr const *
gnm_expr_new_funcall3(GnmFunc * func,GnmExpr const * arg0,GnmExpr const * arg1,GnmExpr const * arg2)188 gnm_expr_new_funcall3 (GnmFunc *func,
189 GnmExpr const *arg0,
190 GnmExpr const *arg1,
191 GnmExpr const *arg2)
192 {
193 GnmExprConstPtr *argv = g_new (GnmExprConstPtr, 3);
194 argv[0] = arg0;
195 argv[1] = arg1;
196 argv[2] = arg2;
197 return gnm_expr_new_funcallv (func, 3, argv);
198 }
199
200 /**
201 * gnm_expr_new_funcall4:
202 * @func: #GnmFunc
203 * @arg0: (transfer full): argument
204 * @arg1: (transfer full): argument
205 * @arg2: (transfer full): argument
206 * @arg3: (transfer full): argument
207 *
208 * Returns: (transfer full): function call expression.
209 */
210 GnmExpr const *
gnm_expr_new_funcall4(GnmFunc * func,GnmExpr const * arg0,GnmExpr const * arg1,GnmExpr const * arg2,GnmExpr const * arg3)211 gnm_expr_new_funcall4 (GnmFunc *func,
212 GnmExpr const *arg0,
213 GnmExpr const *arg1,
214 GnmExpr const *arg2,
215 GnmExpr const *arg3)
216 {
217 GnmExprConstPtr *argv = g_new (GnmExprConstPtr, 4);
218 argv[0] = arg0;
219 argv[1] = arg1;
220 argv[2] = arg2;
221 argv[3] = arg3;
222 return gnm_expr_new_funcallv (func, 4, argv);
223 }
224
225 /**
226 * gnm_expr_new_funcall5:
227 * @func: #GnmFunc
228 * @arg0: (transfer full): argument
229 * @arg1: (transfer full): argument
230 * @arg2: (transfer full): argument
231 * @arg3: (transfer full): argument
232 * @arg4: (transfer full): argument
233 *
234 * Returns: (transfer full): function call expression.
235 */
236 GnmExpr const *
gnm_expr_new_funcall5(GnmFunc * func,GnmExpr const * arg0,GnmExpr const * arg1,GnmExpr const * arg2,GnmExpr const * arg3,GnmExpr const * arg4)237 gnm_expr_new_funcall5 (GnmFunc *func,
238 GnmExpr const *arg0,
239 GnmExpr const *arg1,
240 GnmExpr const *arg2,
241 GnmExpr const *arg3,
242 GnmExpr const *arg4)
243 {
244 GnmExprConstPtr *argv = g_new (GnmExprConstPtr, 5);
245 argv[0] = arg0;
246 argv[1] = arg1;
247 argv[2] = arg2;
248 argv[3] = arg3;
249 argv[4] = arg4;
250 return gnm_expr_new_funcallv (func, 5, argv);
251 }
252
253
254 /***************************************************************************/
255
256 /**
257 * gnm_expr_new_unary:
258 * @op: Unary operator
259 * @e: (transfer full): #GnmExpr
260 *
261 * Returns: (transfer full): Unary expression
262 */
263 GnmExpr const *
gnm_expr_new_unary(GnmExprOp op,GnmExpr const * e)264 gnm_expr_new_unary (GnmExprOp op, GnmExpr const *e)
265 {
266 GnmExprUnary *ans;
267
268 ans = CHUNK_ALLOC (GnmExprUnary, expression_pool_small);
269 if (!ans)
270 return NULL;
271
272 ans->oper = op;
273 ans->value = e;
274
275 return (GnmExpr *)ans;
276 }
277
278 /***************************************************************************/
279
280 /**
281 * gnm_expr_new_binary:
282 * @l: (transfer full): left operand.
283 * @op: Unary operator
284 * @r: (transfer full): right operand.
285 *
286 * Returns: (transfer full): Binary expression
287 */
288 GnmExpr const *
gnm_expr_new_binary(GnmExpr const * l,GnmExprOp op,GnmExpr const * r)289 gnm_expr_new_binary (GnmExpr const *l, GnmExprOp op, GnmExpr const *r)
290 {
291 GnmExprBinary *ans;
292
293 ans = CHUNK_ALLOC (GnmExprBinary, expression_pool_small);
294 if (!ans)
295 return NULL;
296
297 ans->oper = op;
298 ans->value_a = l;
299 ans->value_b = r;
300
301 return (GnmExpr *)ans;
302 }
303
304 /***************************************************************************/
305
306 GnmExpr const *
gnm_expr_new_name(GnmNamedExpr * name,Sheet * optional_scope,Workbook * optional_wb_scope)307 gnm_expr_new_name (GnmNamedExpr *name,
308 Sheet *optional_scope, Workbook *optional_wb_scope)
309 {
310 GnmExprName *ans;
311
312 ans = CHUNK_ALLOC (GnmExprName, expression_pool_big);
313 if (!ans)
314 return NULL;
315
316 ans->oper = GNM_EXPR_OP_NAME;
317 ans->name = name;
318 expr_name_ref (name);
319
320 ans->optional_scope = optional_scope;
321 ans->optional_wb_scope = optional_wb_scope;
322
323 return (GnmExpr *)ans;
324 }
325
326 /***************************************************************************/
327
328 /**
329 * gnm_expr_new_cellref:
330 * @cr: (transfer none): cell reference
331 *
332 * Returns: (transfer full): expression referencing @cr.
333 */
334 GnmExpr const *
gnm_expr_new_cellref(GnmCellRef const * cr)335 gnm_expr_new_cellref (GnmCellRef const *cr)
336 {
337 GnmExprCellRef *ans;
338
339 ans = CHUNK_ALLOC (GnmExprCellRef, expression_pool_big);
340 if (!ans)
341 return NULL;
342
343 ans->oper = GNM_EXPR_OP_CELLREF;
344 ans->ref = *cr;
345
346 return (GnmExpr *)ans;
347 }
348
349 /***************************************************************************/
350
351 /**
352 * gnm_expr_is_array:
353 * @expr: #GnmExpr
354 *
355 * Returns: %TRUE if @expr is an array expression, either a corner or a
356 * non-corner element.
357 */
358 static gboolean
gnm_expr_is_array(GnmExpr const * expr)359 gnm_expr_is_array (GnmExpr const *expr)
360 {
361 return expr &&
362 (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_ARRAY_ELEM ||
363 GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_ARRAY_CORNER);
364 }
365
366 /**
367 * gnm_expr_new_array_corner:
368 * @cols: Number of columns
369 * @rows: Number of rows
370 * @expr: (transfer full) (nullable): #GnmExpr
371 *
372 * Returns: (transfer full): An array corner expression
373 **/
374 static GnmExpr const *
gnm_expr_new_array_corner(int cols,int rows,GnmExpr const * expr)375 gnm_expr_new_array_corner(int cols, int rows, GnmExpr const *expr)
376 {
377 GnmExprArrayCorner *ans;
378
379 g_return_val_if_fail (!gnm_expr_is_array (expr), NULL);
380
381 ans = CHUNK_ALLOC (GnmExprArrayCorner, expression_pool_big);
382 ans->oper = GNM_EXPR_OP_ARRAY_CORNER;
383 ans->rows = rows;
384 ans->cols = cols;
385 ans->value = NULL;
386 ans->expr = expr;
387 return (GnmExpr *)ans;
388 }
389
390 /**
391 * gnm_expr_new_array_elem:
392 * @x: Column number relative to corner
393 * @y: Row number relative to corner
394 *
395 * Returns: (transfer full): An array non-corner expression
396 **/
397 static GnmExpr const *
gnm_expr_new_array_elem(int x,int y)398 gnm_expr_new_array_elem (int x, int y)
399 {
400 GnmExprArrayElem *ans;
401
402 ans = CHUNK_ALLOC (GnmExprArrayElem, expression_pool_small);
403 ans->oper = GNM_EXPR_OP_ARRAY_ELEM;
404 ans->x = x;
405 ans->y = y;
406 return (GnmExpr *)ans;
407 }
408
409 /***************************************************************************/
410
411 static GnmExpr const *
gnm_expr_new_setv(int argc,GnmExprConstPtr * argv)412 gnm_expr_new_setv (int argc, GnmExprConstPtr *argv)
413 {
414 GnmExprSet *ans = CHUNK_ALLOC (GnmExprSet, expression_pool_small);
415
416 ans->oper = GNM_EXPR_OP_SET;
417 ans->argc = argc;
418 ans->argv = argv;
419
420 return (GnmExpr *)ans;
421 }
422
423 /**
424 * gnm_expr_new_set:
425 * @args: (transfer full): element list
426 *
427 * Returns: (transfer full): set expression.
428 */
429 GnmExpr const *
gnm_expr_new_set(GnmExprList * set)430 gnm_expr_new_set (GnmExprList *set)
431 {
432 int i, argc;
433 GnmExprConstPtr *argv;
434 GnmExprList *set0 = set;
435
436 argc = gnm_expr_list_length (set);
437 argv = argc ? g_new (GnmExprConstPtr, argc) : NULL;
438 for (i = 0; set; i++, set = set->next)
439 argv[i] = set->data;
440 gnm_expr_list_free (set0);
441
442 return gnm_expr_new_setv (argc, argv);
443 }
444
445 /***************************************************************************/
446
447 /**
448 * gnm_expr_new_range_ctor:
449 * @l: (transfer full): start range
450 * @r: (transfer full): end range
451 *
452 * This function builds a range constructor or something simpler,
453 * but equivalent, if the arguments allow it.
454 *
455 * Returns: (transfer full): And expression referencing @l to @r.
456 **/
457 GnmExpr const *
gnm_expr_new_range_ctor(GnmExpr const * l,GnmExpr const * r)458 gnm_expr_new_range_ctor (GnmExpr const *l, GnmExpr const *r)
459 {
460 GnmValue *v;
461
462 g_return_val_if_fail (l != NULL, NULL);
463 g_return_val_if_fail (r != NULL, NULL);
464
465 if (GNM_EXPR_GET_OPER (l) != GNM_EXPR_OP_CELLREF)
466 goto fallback;
467 if (GNM_EXPR_GET_OPER (r) != GNM_EXPR_OP_CELLREF)
468 goto fallback;
469
470 v = value_new_cellrange_unsafe (&l->cellref.ref, &r->cellref.ref);
471 gnm_expr_free (l);
472 gnm_expr_free (r);
473 return gnm_expr_new_constant (v);
474
475 fallback:
476 return gnm_expr_new_binary (l, GNM_EXPR_OP_RANGE_CTOR, r);
477 }
478
479 /***************************************************************************/
480
481 /**
482 * gnm_expr_copy:
483 * @expr: (transfer none): #GnmExpr
484 *
485 * Returns: (transfer full): A deep copy of @expr.
486 **/
487 GnmExpr const *
gnm_expr_copy(GnmExpr const * expr)488 gnm_expr_copy (GnmExpr const *expr)
489 {
490 g_return_val_if_fail (expr != NULL, NULL);
491
492 switch (GNM_EXPR_GET_OPER (expr)) {
493 case GNM_EXPR_OP_RANGE_CTOR:
494 case GNM_EXPR_OP_INTERSECT:
495 case GNM_EXPR_OP_ANY_BINARY:
496 return gnm_expr_new_binary
497 (gnm_expr_copy (expr->binary.value_a),
498 GNM_EXPR_GET_OPER (expr),
499 gnm_expr_copy (expr->binary.value_b));
500
501 case GNM_EXPR_OP_ANY_UNARY:
502 return gnm_expr_new_unary
503 (GNM_EXPR_GET_OPER (expr),
504 gnm_expr_copy (expr->unary.value));
505
506 case GNM_EXPR_OP_FUNCALL: {
507 GnmExprConstPtr *argv =
508 g_new (GnmExprConstPtr, expr->func.argc);
509 int i;
510
511 for (i = 0; i < expr->func.argc; i++)
512 argv[i] = gnm_expr_copy (expr->func.argv[i]);
513
514 return gnm_expr_new_funcallv
515 (expr->func.func,
516 expr->func.argc,
517 argv);
518 }
519
520 case GNM_EXPR_OP_NAME:
521 return gnm_expr_new_name
522 (expr->name.name,
523 expr->name.optional_scope,
524 expr->name.optional_wb_scope);
525
526 case GNM_EXPR_OP_CONSTANT:
527 return gnm_expr_new_constant
528 (value_dup (expr->constant.value));
529
530 case GNM_EXPR_OP_CELLREF:
531 return gnm_expr_new_cellref (&expr->cellref.ref);
532
533 case GNM_EXPR_OP_ARRAY_CORNER:
534 return gnm_expr_new_array_corner
535 (expr->array_corner.cols, expr->array_corner.rows,
536 gnm_expr_copy (expr->array_corner.expr));
537
538 case GNM_EXPR_OP_ARRAY_ELEM:
539 return gnm_expr_new_array_elem
540 (expr->array_elem.x,
541 expr->array_elem.y);
542
543 case GNM_EXPR_OP_SET: {
544 GnmExprConstPtr *argv =
545 g_new (GnmExprConstPtr, expr->set.argc);
546 int i;
547
548 for (i = 0; i < expr->set.argc; i++)
549 argv[i] = gnm_expr_copy (expr->set.argv[i]);
550
551 return gnm_expr_new_setv
552 (expr->set.argc,
553 argv);
554 }
555
556 #ifndef DEBUG_SWITCH_ENUM
557 default:
558 g_assert_not_reached ();
559 break;
560 #endif
561 }
562 }
563
564 /**
565 * gnm_expr_free:
566 * @expr: (transfer full): #GnmExpr
567 *
568 * Deletes @expr with all its subexpressions.
569 */
570 void
gnm_expr_free(GnmExpr const * expr)571 gnm_expr_free (GnmExpr const *expr)
572 {
573 g_return_if_fail (expr != NULL);
574
575 switch (GNM_EXPR_GET_OPER (expr)) {
576 case GNM_EXPR_OP_RANGE_CTOR:
577 case GNM_EXPR_OP_INTERSECT:
578 case GNM_EXPR_OP_ANY_BINARY:
579 gnm_expr_free (expr->binary.value_a);
580 gnm_expr_free (expr->binary.value_b);
581 CHUNK_FREE (expression_pool_small, (gpointer)expr);
582 break;
583
584 case GNM_EXPR_OP_FUNCALL: {
585 int i;
586
587 for (i = 0; i < expr->func.argc; i++)
588 gnm_expr_free (expr->func.argv[i]);
589 g_free (expr->func.argv);
590 gnm_func_dec_usage (expr->func.func);
591 CHUNK_FREE (expression_pool_small, (gpointer)expr);
592 break;
593 }
594
595 case GNM_EXPR_OP_NAME:
596 expr_name_unref (expr->name.name);
597 CHUNK_FREE (expression_pool_big, (gpointer)expr);
598 break;
599
600 case GNM_EXPR_OP_CONSTANT:
601 value_release ((GnmValue *)expr->constant.value);
602 CHUNK_FREE (expression_pool_small, (gpointer)expr);
603 break;
604
605 case GNM_EXPR_OP_CELLREF:
606 CHUNK_FREE (expression_pool_big, (gpointer)expr);
607 break;
608
609 case GNM_EXPR_OP_ANY_UNARY:
610 gnm_expr_free (expr->unary.value);
611 CHUNK_FREE (expression_pool_small, (gpointer)expr);
612 break;
613
614 case GNM_EXPR_OP_ARRAY_CORNER:
615 value_release (expr->array_corner.value);
616 // A proper corner will not have NULL here, but we explicitly allow it
617 // during construction, so allow it here too.
618 if (expr->array_corner.expr)
619 gnm_expr_free (expr->array_corner.expr);
620 CHUNK_FREE (expression_pool_big, (gpointer)expr);
621 break;
622
623 case GNM_EXPR_OP_ARRAY_ELEM:
624 CHUNK_FREE (expression_pool_small, (gpointer)expr);
625 break;
626
627 case GNM_EXPR_OP_SET: {
628 int i;
629
630 for (i = 0; i < expr->set.argc; i++)
631 gnm_expr_free (expr->set.argv[i]);
632 g_free (expr->set.argv);
633 CHUNK_FREE (expression_pool_small, (gpointer)expr);
634 break;
635 }
636
637 #ifndef DEBUG_SWITCH_ENUM
638 default:
639 g_assert_not_reached ();
640 break;
641 #endif
642 }
643 }
644
645 GType
gnm_expr_get_type(void)646 gnm_expr_get_type (void)
647 {
648 static GType t = 0;
649
650 if (t == 0) {
651 t = g_boxed_type_register_static ("GnmExpr",
652 (GBoxedCopyFunc)gnm_expr_copy,
653 (GBoxedFreeFunc)gnm_expr_free);
654 }
655 return t;
656 }
657
658 GType
gnm_expr_array_corner_get_type(void)659 gnm_expr_array_corner_get_type (void)
660 {
661 static GType t = 0;
662
663 if (t == 0) {
664 t = g_boxed_type_register_static ("GnmExprArrayCorner",
665 (GBoxedCopyFunc)gnm_expr_copy,
666 (GBoxedFreeFunc)gnm_expr_free);
667 }
668 return t;
669 }
670
671 /**
672 * gnm_expr_equal:
673 * @a: first #GnmExpr
674 * @b: first #GnmExpr
675 *
676 * Returns: %TRUE, if the supplied expressions are exactly the
677 * same and %FALSE otherwise. No eval position is used to see if they
678 * are effectively the same. Named expressions must refer the same name,
679 * having equivalent names is insufficient.
680 */
681 gboolean
gnm_expr_equal(GnmExpr const * a,GnmExpr const * b)682 gnm_expr_equal (GnmExpr const *a, GnmExpr const *b)
683 {
684 if (a == b)
685 return TRUE;
686
687 g_return_val_if_fail (a != NULL, FALSE);
688 g_return_val_if_fail (b != NULL, FALSE);
689
690 if (GNM_EXPR_GET_OPER (a) != GNM_EXPR_GET_OPER (b))
691 return FALSE;
692
693 switch (GNM_EXPR_GET_OPER (a)) {
694 case GNM_EXPR_OP_RANGE_CTOR:
695 case GNM_EXPR_OP_INTERSECT:
696 case GNM_EXPR_OP_ANY_BINARY:
697 return gnm_expr_equal (a->binary.value_a, b->binary.value_a) &&
698 gnm_expr_equal (a->binary.value_b, b->binary.value_b);
699
700 case GNM_EXPR_OP_ANY_UNARY:
701 return gnm_expr_equal (a->unary.value, b->unary.value);
702
703 case GNM_EXPR_OP_FUNCALL: {
704 int i;
705
706 if (a->func.func != b->func.func ||
707 a->func.argc != b->func.argc)
708 return FALSE;
709
710 for (i = 0; i < a->func.argc; i++)
711 if (!gnm_expr_equal (a->func.argv[i], b->func.argv[i]))
712 return FALSE;
713 return TRUE;
714 }
715
716 case GNM_EXPR_OP_NAME:
717 return a->name.name == b->name.name &&
718 a->name.optional_scope == b->name.optional_scope &&
719 a->name.optional_wb_scope == b->name.optional_wb_scope;
720
721 case GNM_EXPR_OP_CELLREF:
722 return gnm_cellref_equal (&a->cellref.ref, &b->cellref.ref);
723
724 case GNM_EXPR_OP_CONSTANT:
725 return value_equal (a->constant.value, b->constant.value);
726
727 case GNM_EXPR_OP_ARRAY_CORNER: {
728 GnmExprArrayCorner const *aa = &a->array_corner;
729 GnmExprArrayCorner const *ab = &b->array_corner;
730
731 return aa->cols == ab->cols &&
732 aa->rows == ab->rows &&
733 gnm_expr_equal (aa->expr, ab->expr);
734 }
735 case GNM_EXPR_OP_ARRAY_ELEM: {
736 GnmExprArrayElem const *aa = &a->array_elem;
737 GnmExprArrayElem const *ab = &b->array_elem;
738 return aa->x == ab->x && aa->y == ab->y;
739 }
740
741 case GNM_EXPR_OP_SET: {
742 int i;
743
744 if (a->set.argc != b->set.argc)
745 return FALSE;
746
747 for (i = 0; i < a->set.argc; i++)
748 if (!gnm_expr_equal (a->set.argv[i], b->set.argv[i]))
749 return FALSE;
750 return TRUE;
751 }
752 }
753
754 return FALSE;
755 }
756
757 static GnmCell *
array_elem_get_corner(GnmExprArrayElem const * elem,Sheet const * sheet,GnmCellPos const * pos)758 array_elem_get_corner (GnmExprArrayElem const *elem,
759 Sheet const *sheet, GnmCellPos const *pos)
760 {
761 GnmCell *corner = sheet_cell_get (sheet,
762 pos->col - elem->x, pos->row - elem->y);
763
764 /* Sanity check incase the corner gets removed for some reason */
765 g_return_val_if_fail (corner != NULL, NULL);
766 g_return_val_if_fail (gnm_cell_has_expr (corner), NULL);
767 g_return_val_if_fail (corner->base.texpr != (void *)0xdeadbeef, NULL);
768 g_return_val_if_fail (GNM_IS_EXPR_TOP (corner->base.texpr), NULL);
769
770 return corner;
771 }
772
773 static gboolean
gnm_expr_extract_ref(GnmRangeRef * res,GnmExpr const * expr,GnmEvalPos const * pos,GnmExprEvalFlags flags)774 gnm_expr_extract_ref (GnmRangeRef *res, GnmExpr const *expr,
775 GnmEvalPos const *pos, GnmExprEvalFlags flags)
776 {
777 switch (GNM_EXPR_GET_OPER (expr)) {
778 case GNM_EXPR_OP_FUNCALL : {
779 gboolean failed = TRUE;
780 GnmValue *v;
781 GnmFuncEvalInfo ei;
782
783 ei.pos = pos;
784 ei.func_call = &expr->func;
785 ei.flags = flags;
786 v = function_call_with_exprs (&ei);
787
788 if (v != NULL) {
789 if (VALUE_IS_CELLRANGE (v)) {
790 *res = v->v_range.cell;
791 failed = FALSE;
792 }
793 value_release (v);
794 }
795 return failed;
796 }
797
798 case GNM_EXPR_OP_CELLREF:
799 res->a = expr->cellref.ref;
800 res->b = expr->cellref.ref;
801 return FALSE;
802
803 case GNM_EXPR_OP_CONSTANT: {
804 GnmValue const *v = expr->constant.value;
805 if (VALUE_IS_CELLRANGE (v)) {
806 *res = v->v_range.cell;
807 return FALSE;
808 }
809 return TRUE;
810 }
811
812 case GNM_EXPR_OP_NAME:
813 if (!expr_name_is_active (expr->name.name))
814 return TRUE;
815 return gnm_expr_extract_ref (res, expr->name.name->texpr->expr,
816 pos, flags);
817 default:
818 break;
819 }
820 return TRUE;
821 }
822
823 static inline GnmValue *
handle_empty(GnmValue * res,GnmExprEvalFlags flags)824 handle_empty (GnmValue *res, GnmExprEvalFlags flags)
825 {
826 if (res == NULL)
827 return (flags & GNM_EXPR_EVAL_PERMIT_EMPTY)
828 ? NULL : value_new_int (0);
829
830 if (VALUE_IS_EMPTY (res)) {
831 value_release (res);
832 return (flags & GNM_EXPR_EVAL_PERMIT_EMPTY)
833 ? NULL : value_new_int (0);
834 }
835 return res;
836 }
837
838 /**
839 * value_intersection:
840 * @v: a VALUE_CELLRANGE or VALUE_ARRAY
841 * @pos:
842 *
843 * Handle the implicit union of a single row or column with the eval position.
844 *
845 * NOTE : We do not need to know if this is expression is being evaluated as an
846 * array or not because we can differentiate based on the required type for the
847 * argument.
848 *
849 * Always release the value passed in.
850 *
851 * NOTE: This should match link_unlink_constant.
852 *
853 * Return value:
854 * If the intersection succeeded return a duplicate of the value
855 * at the intersection point. This value needs to be freed.
856 * %NULL if there is no intersection
857 * Returns the upper left corner of an array.
858 **/
859 static GnmValue *
value_intersection(GnmValue * v,GnmEvalPos const * pos)860 value_intersection (GnmValue *v, GnmEvalPos const *pos)
861 {
862 GnmValue *res = NULL;
863 GnmRange r;
864 Sheet *start_sheet, *end_sheet;
865 gboolean found = FALSE;
866
867 if (VALUE_IS_ARRAY (v)) {
868 res = (v->v_array.x == 0 || v->v_array.y == 0)
869 ? value_new_error_VALUE (NULL)
870 : value_dup (v->v_array.vals[0][0]);
871 value_release (v);
872 return res;
873 }
874
875 /* inverted ranges */
876 gnm_rangeref_normalize (&v->v_range.cell, pos, &start_sheet, &end_sheet, &r);
877 value_release (v);
878
879 if (start_sheet == end_sheet || end_sheet == NULL) {
880 int col = pos->eval.col;
881 int row = pos->eval.row;
882
883 if (pos->dep && !dependent_is_cell (pos->dep)) {
884 /* See bug #142412. */
885 col = r.start.col;
886 row = r.start.row;
887 found = TRUE;
888 } else if (range_is_singleton (&r)) {
889 // A single cell
890 col = r.start.col;
891 row = r.start.row;
892 found = TRUE;
893 } else if (r.start.row == r.end.row &&
894 r.start.col <= col && col <= r.end.col) {
895 // A horizontal sliver
896 row = r.start.row;
897 found = TRUE;
898 } else if (r.start.col == r.end.col &&
899 r.start.row <= row && row <= r.end.row) {
900 // A vertical sliver
901 col = r.start.col;
902 found = TRUE;
903 }
904 if (found) {
905 GnmCell *cell = sheet_cell_get (
906 eval_sheet (start_sheet, pos->sheet),
907 col, row);
908 if (cell == NULL)
909 return value_new_empty ();
910 gnm_cell_eval (cell);
911 return value_dup (cell->value);
912 }
913 }
914
915 return value_new_error_VALUE (pos);
916 }
917
918 static GnmValue *
bin_arith(GnmExpr const * expr,GnmEvalPos const * ep,GnmValue const * a,GnmValue const * b)919 bin_arith (GnmExpr const *expr, GnmEvalPos const *ep,
920 GnmValue const *a, GnmValue const *b)
921 {
922 gnm_float const va = value_get_as_float (a);
923 gnm_float const vb = value_get_as_float (b);
924 gnm_float res;
925
926 switch (GNM_EXPR_GET_OPER (expr)) {
927 case GNM_EXPR_OP_ADD:
928 res = va + vb;
929 break;
930
931 case GNM_EXPR_OP_SUB:
932 res = va - vb;
933 break;
934
935 case GNM_EXPR_OP_MULT:
936 res = va * vb;
937 break;
938
939 case GNM_EXPR_OP_DIV:
940 if (vb == 0.0)
941 return value_new_error_DIV0 (ep);
942 res = va / vb;
943 break;
944
945 case GNM_EXPR_OP_EXP:
946 if ((va == 0 && vb <= 0) || (va < 0 && vb != (int)vb))
947 return value_new_error_NUM (ep);
948
949 res = gnm_pow (va, vb);
950 break;
951
952 default:
953 g_assert_not_reached ();
954 }
955
956 if (gnm_finite (res))
957 return value_new_float (res);
958 else
959 return value_new_error_NUM (ep);
960 }
961
962 static GnmValue *
bin_cmp(GnmExprOp op,GnmValDiff comp,GnmEvalPos const * ep)963 bin_cmp (GnmExprOp op, GnmValDiff comp, GnmEvalPos const *ep)
964 {
965 if (comp == TYPE_MISMATCH) {
966 /* TODO TODO TODO : Make error more informative
967 * regarding what is comparing to what
968 */
969 /* For equality comparisons even errors are ok */
970 if (op == GNM_EXPR_OP_EQUAL)
971 return value_new_bool (FALSE);
972 if (op == GNM_EXPR_OP_NOT_EQUAL)
973 return value_new_bool (TRUE);
974
975 return value_new_error_VALUE (ep);
976 }
977
978 switch (op) {
979 case GNM_EXPR_OP_EQUAL: return value_new_bool (comp == IS_EQUAL);
980 case GNM_EXPR_OP_GT: return value_new_bool (comp == IS_GREATER);
981 case GNM_EXPR_OP_LT: return value_new_bool (comp == IS_LESS);
982 case GNM_EXPR_OP_NOT_EQUAL: return value_new_bool (comp != IS_EQUAL);
983 case GNM_EXPR_OP_LTE: return value_new_bool (comp != IS_GREATER);
984 case GNM_EXPR_OP_GTE: return value_new_bool (comp != IS_LESS);
985
986 #ifndef DEBUG_SWITCH_ENUM
987 default:
988 g_assert_not_reached ();
989 #endif
990 }
991 return value_new_error (ep, _("Internal type error"));
992 }
993
994 static GnmValue *
cb_bin_cmp(GnmEvalPos const * ep,GnmValue const * a,GnmValue const * b,GnmExpr const * expr)995 cb_bin_cmp (GnmEvalPos const *ep, GnmValue const *a, GnmValue const *b,
996 GnmExpr const *expr)
997 {
998 if (a != NULL && VALUE_IS_ERROR (a))
999 return value_dup (a);
1000 if (b != NULL && VALUE_IS_ERROR (b))
1001 return value_dup (b);
1002 return bin_cmp (GNM_EXPR_GET_OPER (expr), value_compare (a, b, FALSE), ep);
1003 }
1004
1005 static GnmValue *
cb_bin_arith(GnmEvalPos const * ep,GnmValue const * a,GnmValue const * b,GnmExpr const * expr)1006 cb_bin_arith (GnmEvalPos const *ep, GnmValue const *a, GnmValue const *b,
1007 GnmExpr const *expr)
1008 {
1009 GnmValue *res, *va, *vb;
1010
1011 if (a != NULL && VALUE_IS_ERROR (a))
1012 return value_dup (a);
1013 if (b != NULL && VALUE_IS_ERROR (b))
1014 return value_dup (b);
1015 if (VALUE_IS_EMPTY (a))
1016 a = va = (GnmValue *)value_zero;
1017 else if (VALUE_IS_STRING (a)) {
1018 va = format_match_number (value_peek_string (a), NULL,
1019 sheet_date_conv (ep->sheet));
1020 if (va == NULL)
1021 return value_new_error_VALUE (ep);
1022 } else if (!VALUE_IS_NUMBER (a))
1023 return value_new_error_VALUE (ep);
1024 else
1025 va = (GnmValue *)a;
1026 if (VALUE_IS_EMPTY (b))
1027 b = vb = (GnmValue *)value_zero;
1028 else if (VALUE_IS_STRING (b)) {
1029 vb = format_match_number (value_peek_string (b), NULL,
1030 sheet_date_conv (ep->sheet));
1031 if (vb == NULL) {
1032 if (va != a)
1033 value_release (va);
1034 return value_new_error_VALUE (ep);
1035 }
1036 } else if (!VALUE_IS_NUMBER (b)) {
1037 if (va != a)
1038 value_release (va);
1039 return value_new_error_VALUE (ep);
1040 } else
1041 vb = (GnmValue *)b;
1042
1043 res = bin_arith (expr, ep, va, vb);
1044 if (va != a)
1045 value_release (va);
1046 if (vb != b)
1047 value_release (vb);
1048 return res;
1049 }
1050
1051 static GnmValue *
cb_bin_cat(GnmEvalPos const * ep,GnmValue const * a,GnmValue const * b,GnmExpr const * expr)1052 cb_bin_cat (GnmEvalPos const *ep, GnmValue const *a, GnmValue const *b,
1053 GnmExpr const *expr)
1054 {
1055 if (a != NULL && VALUE_IS_ERROR (a))
1056 return value_dup (a);
1057 if (b != NULL && VALUE_IS_ERROR (b))
1058 return value_dup (b);
1059 if (a == NULL) {
1060 if (b != NULL)
1061 return value_new_string (value_peek_string (b));
1062 else
1063 return value_new_string ("");
1064 } else if (b == NULL)
1065 return value_new_string (value_peek_string (a));
1066 else {
1067 char *tmp = g_strconcat (value_peek_string (a),
1068 value_peek_string (b), NULL);
1069 return value_new_string_nocopy (tmp);
1070 }
1071 }
1072
1073 typedef GnmValue *(*BinOpImplicitIteratorFunc) (GnmEvalPos const *ep,
1074 GnmValue const *a,
1075 GnmValue const *b,
1076 gpointer user_data);
1077 typedef struct {
1078 GnmEvalPos const *ep;
1079 GnmValue *res;
1080 GnmValue const *a, *b;
1081 BinOpImplicitIteratorFunc func;
1082
1083 /* multiply by 0 in unused dimensions.
1084 * this is simpler than lots of conditions
1085 * state->use_x.a ? x : 0
1086 **/
1087 struct {
1088 int a, b;
1089 } x, y;
1090 gpointer user_data;
1091 } BinOpImplicitIteratorState;
1092
1093 static GnmValue *
cb_implicit_iter_a_and_b(GnmValueIter const * v_iter,BinOpImplicitIteratorState const * state)1094 cb_implicit_iter_a_and_b (GnmValueIter const *v_iter,
1095 BinOpImplicitIteratorState const *state)
1096 {
1097 state->res->v_array.vals [v_iter->x][v_iter->y] =
1098 (*state->func) (v_iter->ep,
1099 value_area_get_x_y (state->a,
1100 state->x.a * v_iter->x,
1101 state->y.a * v_iter->y, v_iter->ep),
1102 value_area_get_x_y (state->b,
1103 state->x.b * v_iter->x,
1104 state->y.b * v_iter->y, v_iter->ep),
1105 state->user_data);
1106 return NULL;
1107 }
1108 static GnmValue *
cb_implicit_iter_a_to_scalar_b(GnmValueIter const * v_iter,BinOpImplicitIteratorState const * state)1109 cb_implicit_iter_a_to_scalar_b (GnmValueIter const *v_iter,
1110 BinOpImplicitIteratorState const *state)
1111 {
1112 state->res->v_array.vals [v_iter->x][v_iter->y] =
1113 (*state->func) (v_iter->ep,
1114 v_iter->v, state->b, state->user_data);
1115 return NULL;
1116 }
1117
1118 /* This is only triggered if something returns an array or a range which can
1119 * only happen if we are in array eval mode. */
1120 static GnmValue *
bin_array_iter_a(GnmEvalPos const * ep,GnmValue * a,GnmValue * b,BinOpImplicitIteratorFunc func,GnmExpr const * expr)1121 bin_array_iter_a (GnmEvalPos const *ep,
1122 GnmValue *a, GnmValue *b,
1123 BinOpImplicitIteratorFunc func,
1124 GnmExpr const *expr)
1125 {
1126 BinOpImplicitIteratorState iter_info;
1127
1128 /* a must be a cellrange or array, it cannot be NULL */
1129 iter_info.ep = ep;
1130 iter_info.func = func;
1131 iter_info.user_data = (gpointer) expr;
1132 iter_info.a = a;
1133 iter_info.b = b;
1134
1135 /* matrix to matrix
1136 * Use matching positions unless the dimension is singular, in which
1137 * case use the zero item
1138 * res[x][y] = f(a[singular.a.x ? 0 : x, b[singular.b.x ? 0 : x)
1139 *
1140 * If both items have non-singular sizes for
1141 * the same dimension use the min size (see samples/array.xls) */
1142 if (b != NULL &&
1143 (VALUE_IS_CELLRANGE (b) || VALUE_IS_ARRAY (b))) {
1144 int sa, sb, w = 1, h = 1;
1145
1146 sa = value_area_get_width (a, ep);
1147 sb = value_area_get_width (b, ep);
1148 if ((iter_info.x.a = (sa == 1) ? 0 : 1))
1149 w = sa;
1150 if ((iter_info.x.b = (sb == 1) ? 0 : 1) && (w > sb || w == 1))
1151 w = sb;
1152
1153 sa = value_area_get_height (a, ep);
1154 sb = value_area_get_height (b, ep);
1155 if ((iter_info.y.a = (sa == 1) ? 0 : 1))
1156 h = sa;
1157 if ((iter_info.y.b = (sb == 1) ? 0 : 1) && (h > sb || h == 1))
1158 h = sb;
1159
1160 iter_info.res = value_new_array_empty (w, h);
1161 value_area_foreach (iter_info.res, ep, CELL_ITER_ALL,
1162 (GnmValueIterFunc) cb_implicit_iter_a_and_b, &iter_info);
1163 } else {
1164 iter_info.res = value_new_array_empty (
1165 value_area_get_width (a, ep),
1166 value_area_get_height (a, ep));
1167 value_area_foreach (a, ep, CELL_ITER_ALL,
1168 (GnmValueIterFunc) cb_implicit_iter_a_to_scalar_b, &iter_info);
1169 }
1170
1171 value_release (a);
1172 value_release (b);
1173 return iter_info.res;
1174 }
1175
1176 static GnmValue *
cb_implicit_iter_b_to_scalar_a(GnmValueIter const * v_iter,BinOpImplicitIteratorState const * state)1177 cb_implicit_iter_b_to_scalar_a (GnmValueIter const *v_iter,
1178 BinOpImplicitIteratorState const *state)
1179 {
1180 state->res->v_array.vals [v_iter->x][v_iter->y] =
1181 (*state->func) (v_iter->ep,
1182 state->a, v_iter->v, state->user_data);
1183 return NULL;
1184 }
1185 static GnmValue *
bin_array_iter_b(GnmEvalPos const * ep,GnmValue * a,GnmValue * b,BinOpImplicitIteratorFunc func,GnmExpr const * expr)1186 bin_array_iter_b (GnmEvalPos const *ep,
1187 GnmValue *a, GnmValue *b,
1188 BinOpImplicitIteratorFunc func,
1189 GnmExpr const *expr)
1190 {
1191 BinOpImplicitIteratorState iter_info;
1192
1193 iter_info.func = func;
1194 iter_info.user_data = (gpointer) expr;
1195 iter_info.a = a;
1196 iter_info.b = b;
1197
1198 /* b must be a cellrange or array, it cannot be NULL */
1199 iter_info.res = value_new_array_empty (
1200 value_area_get_width (b, ep),
1201 value_area_get_height (b, ep));
1202 value_area_foreach (b, ep, CELL_ITER_ALL,
1203 (GnmValueIterFunc) cb_implicit_iter_b_to_scalar_a, &iter_info);
1204 value_release (a);
1205 value_release (b);
1206
1207 return iter_info.res;
1208 }
1209
1210 static GnmValue *
negate_value(GnmValue const * v)1211 negate_value (GnmValue const *v)
1212 {
1213 if (VALUE_IS_NUMBER (v)) {
1214 GnmValue *tmp = value_new_float (0 - value_get_as_float (v));
1215 value_set_fmt (tmp, VALUE_FMT (v));
1216 return tmp;
1217 } else
1218 return NULL;
1219 }
1220
1221 static GnmValue *
cb_iter_unary_neg(GnmValueIter const * v_iter,GnmValue * res)1222 cb_iter_unary_neg (GnmValueIter const *v_iter, GnmValue *res)
1223 {
1224 GnmValue const *v = v_iter->v;
1225 GnmValue *tmp = NULL;
1226
1227 if (VALUE_IS_EMPTY (v))
1228 tmp = value_new_int (0);
1229 else if (VALUE_IS_ERROR (v))
1230 tmp = value_dup (v);
1231 else if (VALUE_IS_STRING (v)) {
1232 GnmValue *conv = format_match_number (
1233 value_peek_string (v), NULL,
1234 sheet_date_conv (v_iter->ep->sheet));
1235 if (conv != NULL) {
1236 tmp = negate_value (conv);
1237 value_release (conv);
1238 }
1239 } else {
1240 /* BOOL goes here. */
1241 tmp = negate_value (v);
1242 }
1243
1244 if (NULL == tmp)
1245 tmp = value_new_error_VALUE (v_iter->ep);
1246 res->v_array.vals[v_iter->x][v_iter->y] = tmp;
1247 return NULL;
1248 }
1249
1250 static GnmValue *
cb_iter_percentage(GnmValueIter const * v_iter,GnmValue * res)1251 cb_iter_percentage (GnmValueIter const *v_iter, GnmValue *res)
1252 {
1253 GnmValue const *v = v_iter->v;
1254 GnmValue *tmp;
1255
1256 if (VALUE_IS_EMPTY (v))
1257 tmp = value_new_int (0);
1258 else if (VALUE_IS_ERROR (v))
1259 tmp = value_dup (v);
1260 else {
1261 GnmValue *conv = NULL;
1262 if (VALUE_IS_STRING (v)) {
1263 conv = format_match_number (
1264 value_peek_string (v), NULL,
1265 sheet_date_conv (v_iter->ep->sheet));
1266 if (conv != NULL)
1267 v = conv;
1268 }
1269
1270 if (VALUE_IS_NUMBER (v)){
1271 tmp = value_new_float (value_get_as_float (v) / 100);
1272 value_set_fmt (tmp, go_format_default_percentage ());
1273 } else
1274 tmp = value_new_error_VALUE (v_iter->ep);
1275
1276 value_release (conv);
1277 }
1278
1279 res->v_array.vals[v_iter->x][v_iter->y] = tmp;
1280 return NULL;
1281 }
1282
1283 static GnmValue *
gnm_expr_range_op(GnmExpr const * expr,GnmEvalPos const * ep,GnmExprEvalFlags flags)1284 gnm_expr_range_op (GnmExpr const *expr, GnmEvalPos const *ep,
1285 GnmExprEvalFlags flags)
1286 {
1287 GnmRangeRef a_ref, b_ref;
1288 GnmRange a_range, b_range, res_range;
1289 Sheet *a_start, *a_end, *b_start, *b_end;
1290 GnmValue *res = NULL;
1291
1292 if (gnm_expr_extract_ref (&a_ref, expr->binary.value_a, ep, flags) ||
1293 gnm_expr_extract_ref (&b_ref, expr->binary.value_b, ep, flags))
1294 return value_new_error_REF (ep);
1295
1296 gnm_rangeref_normalize (&a_ref, ep, &a_start, &a_end, &a_range);
1297 gnm_rangeref_normalize (&b_ref, ep, &b_start, &b_end, &b_range);
1298
1299 switch (GNM_EXPR_GET_OPER (expr)) {
1300 case GNM_EXPR_OP_RANGE_CTOR:
1301 res_range = range_union (&a_range, &b_range);
1302 /* b_range might be on a bigger sheet. */
1303 range_ensure_sanity (&res_range, a_start);
1304 break;
1305 case GNM_EXPR_OP_INTERSECT:
1306 /* 3D references not allowed. */
1307 if (a_start != a_end || b_start != b_end)
1308 return value_new_error_VALUE (ep);
1309
1310 /* Must be same sheet. */
1311 if (a_start != b_start)
1312 return value_new_error_VALUE (ep);
1313
1314 if (!range_intersection (&res_range, &a_range, &b_range))
1315 return value_new_error_NULL (ep);
1316 break;
1317 default:
1318 g_assert_not_reached ();
1319 return NULL;
1320 }
1321
1322 res = value_new_cellrange_r (a_start, &res_range);
1323 dependent_add_dynamic_dep (ep->dep, &res->v_range.cell);
1324 if (!(flags & GNM_EXPR_EVAL_PERMIT_NON_SCALAR)) {
1325 res = value_intersection (res, ep);
1326 return (res != NULL)
1327 ? handle_empty (res, flags)
1328 : value_new_error_VALUE (ep);
1329 }
1330 return res;
1331 }
1332
1333 /**
1334 * gnm_expr_eval:
1335 * @expr: #GnmExpr
1336 * @pos: evaluation position
1337 * @flags: #GnmExprEvalFlags
1338 *
1339 * Evaluatates the given expression. If GNM_EXPR_EVAL_PERMIT_EMPTY is not set
1340 * then return zero if the expression instead of the empty value, or the value
1341 * of an unused cell.
1342 *
1343 * Returns: (transfer full): result.
1344 **/
1345 GnmValue *
gnm_expr_eval(GnmExpr const * expr,GnmEvalPos const * pos,GnmExprEvalFlags flags)1346 gnm_expr_eval (GnmExpr const *expr, GnmEvalPos const *pos,
1347 GnmExprEvalFlags flags)
1348 {
1349 GnmValue *res = NULL, *a = NULL, *b = NULL;
1350
1351 g_return_val_if_fail (expr != NULL, handle_empty (NULL, flags));
1352 g_return_val_if_fail (pos != NULL, handle_empty (NULL, flags));
1353
1354 retry:
1355 switch (GNM_EXPR_GET_OPER (expr)){
1356 case GNM_EXPR_OP_EQUAL:
1357 case GNM_EXPR_OP_NOT_EQUAL:
1358 case GNM_EXPR_OP_GT:
1359 case GNM_EXPR_OP_GTE:
1360 case GNM_EXPR_OP_LT:
1361 case GNM_EXPR_OP_LTE:
1362 flags |= GNM_EXPR_EVAL_PERMIT_EMPTY;
1363 flags &= ~GNM_EXPR_EVAL_WANT_REF;
1364
1365 a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1366 if (a != NULL) {
1367 if (VALUE_IS_ERROR (a))
1368 return a;
1369 if (VALUE_IS_CELLRANGE (a) || VALUE_IS_ARRAY (a))
1370 return bin_array_iter_a (pos, a,
1371 gnm_expr_eval (expr->binary.value_b, pos, flags),
1372 (BinOpImplicitIteratorFunc) cb_bin_cmp,
1373 expr);
1374 }
1375
1376 b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1377 if (b != NULL) {
1378 if (VALUE_IS_ERROR (b)) {
1379 value_release (a);
1380 return b;
1381 }
1382 if (VALUE_IS_CELLRANGE (b) || VALUE_IS_ARRAY (b))
1383 return bin_array_iter_b (pos, a, b,
1384 (BinOpImplicitIteratorFunc) cb_bin_cmp,
1385 expr);
1386 }
1387
1388 res = bin_cmp (GNM_EXPR_GET_OPER (expr), value_compare (a, b, FALSE), pos);
1389 value_release (a);
1390 value_release (b);
1391 return res;
1392
1393 case GNM_EXPR_OP_ADD:
1394 case GNM_EXPR_OP_SUB:
1395 case GNM_EXPR_OP_MULT:
1396 case GNM_EXPR_OP_DIV:
1397 case GNM_EXPR_OP_EXP:
1398 /*
1399 * Priority
1400 * 1) Error from A
1401 * 2) #!VALUE error if A is not a number
1402 * 3) Error from B
1403 * 4) #!VALUE error if B is not a number
1404 * 5) result of operation, or error specific to the operation
1405 */
1406
1407 /* Guarantees value != NULL */
1408 flags &= ~GNM_EXPR_EVAL_PERMIT_EMPTY;
1409 flags &= ~GNM_EXPR_EVAL_WANT_REF;
1410
1411 /* 1) Error from A */
1412 a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1413 if (VALUE_IS_ERROR (a))
1414 return value_error_set_pos (&a->v_err, pos);
1415
1416 /* 2) #!VALUE error if A is not a number */
1417 if (VALUE_IS_STRING (a)) {
1418 GnmValue *tmp = format_match_number (value_peek_string (a), NULL,
1419 sheet_date_conv (pos->sheet));
1420
1421 value_release (a);
1422 if (tmp == NULL)
1423 return value_new_error_VALUE (pos);
1424 a = tmp;
1425 } else if (VALUE_IS_CELLRANGE (a) || VALUE_IS_ARRAY (a)) {
1426 b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1427 if (VALUE_IS_STRING (b)) {
1428 res = format_match_number (value_peek_string (b), NULL,
1429 sheet_date_conv (pos->sheet));
1430 value_release (b);
1431 b = (res == NULL) ? value_new_error_VALUE (pos) : res;
1432 }
1433 return bin_array_iter_a (pos, a, b,
1434 (BinOpImplicitIteratorFunc) cb_bin_arith,
1435 expr);
1436 } else if (!VALUE_IS_NUMBER (a)) {
1437 value_release (a);
1438 return value_new_error_VALUE (pos);
1439 }
1440
1441 /* 3) Error from B */
1442 b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1443 if (VALUE_IS_ERROR (b)) {
1444 value_release (a);
1445 return value_error_set_pos (&b->v_err, pos);
1446 }
1447
1448 /* 4) #!VALUE error if B is not a number */
1449 if (VALUE_IS_STRING (b)) {
1450 GnmValue *tmp = format_match_number (value_peek_string (b), NULL,
1451 sheet_date_conv (pos->sheet));
1452
1453 value_release (b);
1454 if (tmp == NULL) {
1455 value_release (a);
1456 return value_new_error_VALUE (pos);
1457 }
1458 b = tmp;
1459 } else if (VALUE_IS_CELLRANGE (b) || VALUE_IS_ARRAY (b))
1460 return bin_array_iter_b (pos, a, b,
1461 (BinOpImplicitIteratorFunc) cb_bin_arith,
1462 expr);
1463 else if (!VALUE_IS_NUMBER (b)) {
1464 value_release (a);
1465 value_release (b);
1466 return value_new_error_VALUE (pos);
1467 }
1468
1469 res = bin_arith (expr, pos, a, b);
1470 value_release (a);
1471 value_release (b);
1472 return res;
1473
1474 case GNM_EXPR_OP_PAREN:
1475 /* Avoid recursive call to save stack. */
1476 expr = expr->unary.value;
1477 goto retry;
1478
1479 case GNM_EXPR_OP_PERCENTAGE:
1480 case GNM_EXPR_OP_UNARY_NEG:
1481 case GNM_EXPR_OP_UNARY_PLUS:
1482 /* Guarantees value != NULL */
1483 flags &= ~GNM_EXPR_EVAL_PERMIT_EMPTY;
1484 flags &= ~GNM_EXPR_EVAL_WANT_REF;
1485
1486 a = gnm_expr_eval (expr->unary.value, pos, flags);
1487 if (VALUE_IS_ERROR (a))
1488 return a;
1489 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_UNARY_PLUS)
1490 return a;
1491
1492 /* 2) #!VALUE error if A is not a number */
1493 if (VALUE_IS_STRING (a)) {
1494 GnmValue *tmp = format_match_number (value_peek_string (a), NULL,
1495 sheet_date_conv (pos->sheet));
1496
1497 value_release (a);
1498 if (tmp == NULL)
1499 return value_new_error_VALUE (pos);
1500 a = tmp;
1501 } else if (VALUE_IS_CELLRANGE (a) || VALUE_IS_ARRAY (a)) {
1502 res = value_new_array_empty (
1503 value_area_get_width (a, pos),
1504 value_area_get_height (a, pos));
1505 value_area_foreach (a, pos, CELL_ITER_ALL,
1506 (GnmValueIterFunc) ((GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_UNARY_NEG)
1507 ? cb_iter_unary_neg : cb_iter_percentage),
1508 res);
1509 value_release (a);
1510 return res;
1511 }
1512 if (!VALUE_IS_NUMBER (a))
1513 res = value_new_error_VALUE (pos);
1514 else if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_UNARY_NEG)
1515 res = negate_value (a);
1516 else {
1517 res = value_new_float (value_get_as_float (a) / 100);
1518 value_set_fmt (res, go_format_default_percentage ());
1519 }
1520 value_release (a);
1521 return res;
1522
1523 case GNM_EXPR_OP_CAT:
1524 flags |= GNM_EXPR_EVAL_PERMIT_EMPTY;
1525 flags &= ~GNM_EXPR_EVAL_WANT_REF;
1526 a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1527 if (a != NULL) {
1528 if (VALUE_IS_ERROR (a))
1529 return a;
1530 if (VALUE_IS_CELLRANGE (a) || VALUE_IS_ARRAY (a))
1531 return bin_array_iter_a (pos, a,
1532 gnm_expr_eval (expr->binary.value_b, pos, flags),
1533 (BinOpImplicitIteratorFunc) cb_bin_cat,
1534 expr);
1535 }
1536 b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1537 if (b != NULL) {
1538 if (VALUE_IS_ERROR (b)) {
1539 value_release (a);
1540 return b;
1541 }
1542 if (VALUE_IS_CELLRANGE (b) || VALUE_IS_ARRAY (b))
1543 return bin_array_iter_b (pos, a, b,
1544 (BinOpImplicitIteratorFunc) cb_bin_cat,
1545 expr);
1546 }
1547
1548 if (a == NULL) {
1549 if (b != NULL) {
1550 res = value_new_string (value_peek_string (b));
1551 value_release (b);
1552 } else
1553 res = value_new_string ("");
1554 } else if (b == NULL) {
1555 res = value_new_string (value_peek_string (a));
1556 value_release (a);
1557 } else {
1558 char *tmp = g_strconcat (value_peek_string (a),
1559 value_peek_string (b), NULL);
1560 res = value_new_string_nocopy (tmp);
1561 value_release (a);
1562 value_release (b);
1563 }
1564 return res;
1565
1566 case GNM_EXPR_OP_FUNCALL: {
1567 GnmFuncEvalInfo ei;
1568 ei.pos = pos;
1569 ei.func_call = &expr->func;
1570 ei.flags = flags;
1571 res = function_call_with_exprs (&ei);
1572 if (res == NULL)
1573 return (flags & GNM_EXPR_EVAL_PERMIT_EMPTY)
1574 ? NULL : value_new_int (0);
1575 if (VALUE_IS_CELLRANGE (res)) {
1576 /*
1577 * pos->dep really shouldn't be NULL here, but it
1578 * will be if someone puts "indirect" into an
1579 * expression used for conditional formats.
1580 */
1581 if (pos->dep)
1582 dependent_add_dynamic_dep (pos->dep,
1583 &res->v_range.cell);
1584 if (!(flags & GNM_EXPR_EVAL_PERMIT_NON_SCALAR)) {
1585 res = value_intersection (res, pos);
1586 return (res != NULL)
1587 ? handle_empty (res, flags)
1588 : value_new_error_VALUE (pos);
1589 }
1590 return res;
1591 }
1592 if (VALUE_IS_ARRAY (res) &&
1593 !(flags & GNM_EXPR_EVAL_PERMIT_NON_SCALAR)) {
1594 a = (res->v_array.x > 0 && res->v_array.y > 0)
1595 ? value_dup (res->v_array.vals[0][0])
1596 : value_new_error_REF (pos);
1597 value_release (res);
1598 return a;
1599 }
1600 return res;
1601 }
1602
1603 case GNM_EXPR_OP_NAME:
1604 if (expr_name_is_active (expr->name.name))
1605 return handle_empty (expr_name_eval (expr->name.name, pos, flags), flags);
1606 return value_new_error_REF (pos);
1607
1608 case GNM_EXPR_OP_CELLREF: {
1609 GnmCell *cell;
1610 GnmCellRef r;
1611
1612 gnm_cellref_make_abs (&r, &expr->cellref.ref, pos);
1613
1614 cell = sheet_cell_get (eval_sheet (r.sheet, pos->sheet),
1615 r.col, r.row);
1616 if (cell)
1617 gnm_cell_eval (cell);
1618
1619 if (flags & GNM_EXPR_EVAL_WANT_REF) {
1620 return value_new_cellrange_unsafe (&r, &r);
1621 } else {
1622 GnmValue *v = cell ? value_dup (cell->value) : NULL;
1623 return handle_empty (v, flags);
1624 }
1625 }
1626
1627 case GNM_EXPR_OP_CONSTANT:
1628 res = value_dup (expr->constant.value);
1629 if (VALUE_IS_CELLRANGE (res) || VALUE_IS_ARRAY (res)) {
1630 if (flags & GNM_EXPR_EVAL_PERMIT_NON_SCALAR)
1631 return res;
1632 res = value_intersection (res, pos);
1633 return (res != NULL)
1634 ? handle_empty (res, flags)
1635 : value_new_error_VALUE (pos);
1636 }
1637 return handle_empty (res, flags);
1638
1639 case GNM_EXPR_OP_ARRAY_CORNER:
1640 case GNM_EXPR_OP_ARRAY_ELEM:
1641 g_warning ("Unexpected array expressions encountered");
1642 return value_new_error_VALUE (pos);
1643
1644 case GNM_EXPR_OP_SET:
1645 if (flags & GNM_EXPR_EVAL_PERMIT_NON_SCALAR) {
1646 int i;
1647 int argc = expr->set.argc;
1648
1649 res = value_new_array_non_init (1, expr->set.argc);
1650 res->v_array.vals[0] = g_new (GnmValue *, expr->set.argc);
1651 for (i = 0; i < argc; i++)
1652 res->v_array.vals[0][i] = gnm_expr_eval (
1653 expr->set.argv[i], pos,
1654 GNM_EXPR_EVAL_SCALAR_NON_EMPTY);
1655 return res;
1656 }
1657 return value_new_error_VALUE (pos);
1658
1659 case GNM_EXPR_OP_RANGE_CTOR:
1660 case GNM_EXPR_OP_INTERSECT:
1661 return gnm_expr_range_op (expr, pos, flags);
1662 }
1663
1664 g_assert_not_reached ();
1665 return value_new_error (pos, _("Unknown evaluation error"));
1666 }
1667
1668 /**
1669 * gnm_expr_simplify_if:
1670 * @expr: Expression
1671 *
1672 * Simplifies @expr if it is a call to "if" with a constant condition.
1673 *
1674 * Returns: (transfer full) (nullable): simpler expression.
1675 */
1676 GnmExpr const *
gnm_expr_simplify_if(GnmExpr const * expr)1677 gnm_expr_simplify_if (GnmExpr const *expr)
1678 {
1679 static GnmFunc *f_if = NULL;
1680 GnmExpr const *cond;
1681 gboolean c;
1682
1683 g_return_val_if_fail (expr != NULL, NULL);
1684
1685 if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_FUNCALL)
1686 return NULL;
1687
1688 if (!f_if)
1689 f_if = gnm_func_lookup ("if", NULL);
1690
1691 if (expr->func.func != f_if || expr->func.argc != 3)
1692 return NULL;
1693
1694 cond = expr->func.argv[0];
1695 if (GNM_EXPR_GET_OPER (cond) == GNM_EXPR_OP_CONSTANT) {
1696 GnmValue const *condval = cond->constant.value;
1697 gboolean err;
1698 c = value_get_as_bool (condval, &err);
1699 if (err)
1700 return NULL;
1701 } else
1702 return NULL;
1703
1704 // We used to test for true() and false() as conditions too, but the code
1705 // never worked and has been unreachable until now.
1706
1707 return gnm_expr_copy (expr->func.argv[c ? 1 : 2]);
1708 }
1709
1710
1711
1712 /*
1713 * Converts a parsed tree into its string representation
1714 * assuming that we are evaluating at col, row
1715 *
1716 * This routine is pretty simple: it walks the GnmExpr and
1717 * appends a string representation to the target.
1718 */
1719 static void
do_expr_as_string(GnmExpr const * expr,int paren_level,GnmConventionsOut * out)1720 do_expr_as_string (GnmExpr const *expr, int paren_level,
1721 GnmConventionsOut *out)
1722 {
1723 static struct {
1724 char const name[4];
1725 guint8 prec; /* Precedences -- should match parser.y */
1726 guint8 assoc_left, assoc_right; /* 0: no, 1: yes. */
1727 guint8 is_prefix; /* for unary operators */
1728 } const operations[] = {
1729 { "", 0, 0, 0, 0 }, /* Parentheses for clarity */
1730 { "=", 1, 1, 0, 0 },
1731 { ">", 1, 1, 0, 0 },
1732 { "<", 1, 1, 0, 0 },
1733 { ">=", 1, 1, 0, 0 },
1734 { "<=", 1, 1, 0, 0 },
1735 { "<>", 1, 1, 0, 0 },
1736 { "+", 3, 1, 0, 0 },
1737 { "-", 3, 1, 0, 0 },
1738 { "*", 4, 1, 0, 0 },
1739 { "/", 4, 1, 0, 0 },
1740 { "^", 5, 0, 0, 0 }, /* Note: neither left nor right */
1741 { "&", 2, 1, 0, 0 },
1742 { "", 0, 0, 0, 0 }, /* Funcall */
1743 { "", 0, 0, 0, 0 }, /* Name */
1744 { "", 0, 0, 0, 0 }, /* Constant */
1745 { "", 0, 0, 0, 0 }, /* Var */
1746 { "-", 7, 0, 0, 1 }, /* Unary - */
1747 { "+", 7, 0, 0, 1 }, /* Unary + */
1748 { "%", 6, 0, 0, 0 }, /* Percentage (NOT MODULO) */
1749 { "", 0, 0, 0, 0 }, /* ArrayCorner */
1750 { "", 0, 0, 0, 0 }, /* ArrayElem */
1751 { "", 8, 0, 0, 0 }, /* Set */
1752 { ":", 10, 1, 0, 0 }, /* Range Ctor */
1753 { " ", 9, 1, 0, 0 } /* Intersection */
1754 };
1755 GnmExprOp const op = GNM_EXPR_GET_OPER (expr);
1756 GString *target = out->accum;
1757
1758 switch (op) {
1759 case GNM_EXPR_OP_RANGE_CTOR:
1760 case GNM_EXPR_OP_INTERSECT:
1761 case GNM_EXPR_OP_ANY_BINARY: {
1762 char const *opname = operations[op].name;
1763 int prec = operations[op].prec;
1764 gboolean need_par = (prec <= paren_level);
1765 size_t prelen = target->len;
1766
1767 if (need_par) g_string_append_c (target, '(');
1768 do_expr_as_string (expr->binary.value_a,
1769 prec - operations[op].assoc_left, out);
1770
1771 /*
1772 * Avoid getting "-2^2". We want to make sure files do not
1773 * contain that construct as we might later change precedence.
1774 *
1775 * Always produce either "-(2^2)" or "(-2)^2".
1776 *
1777 * Note, that the parser introduces an explicit parenthesis in
1778 * this case also, so parsed expressions should not be
1779 * affected by the code here.
1780 */
1781 if (op == GNM_EXPR_OP_EXP &&
1782 (target->str[prelen] == '-' || target->str[prelen] == '+')) {
1783 g_string_insert_c (target, prelen, '(');
1784 g_string_append_c (target, ')');
1785 }
1786
1787 /* Instead of this we ought to move the whole operations
1788 table into the conventions. */
1789 if (op == GNM_EXPR_OP_INTERSECT)
1790 g_string_append_unichar (target, out->convs->intersection_char);
1791 else
1792 g_string_append (target, opname);
1793
1794 do_expr_as_string (expr->binary.value_b,
1795 prec - operations[op].assoc_right, out);
1796 if (need_par) g_string_append_c (target, ')');
1797 return;
1798 }
1799
1800 case GNM_EXPR_OP_ANY_UNARY: {
1801 char const *opname = operations[op].name;
1802 int prec = operations[op].prec;
1803 gboolean is_prefix = operations[op].is_prefix;
1804 gboolean need_par = (prec <= paren_level);
1805
1806 if (need_par) g_string_append_c (target, '(');
1807 if (is_prefix) g_string_append (target, opname);
1808 do_expr_as_string (expr->unary.value, prec, out);
1809 if (!is_prefix) g_string_append (target, opname);
1810 if (need_par) g_string_append_c (target, ')');
1811 return;
1812 }
1813
1814 case GNM_EXPR_OP_FUNCALL:
1815 out->convs->output.func (out, &expr->func);
1816 return;
1817
1818 case GNM_EXPR_OP_NAME:
1819 out->convs->output.name (out, &expr->name);
1820 return;
1821
1822 case GNM_EXPR_OP_CELLREF:
1823 out->convs->output.cell_ref (out, &expr->cellref.ref, FALSE);
1824 return;
1825
1826 case GNM_EXPR_OP_CONSTANT: {
1827 GnmValue const *v = expr->constant.value;
1828 size_t prelen = target->len;
1829
1830 if (VALUE_IS_STRING (v)) {
1831 out->convs->output.string (out, v->v_str.val);
1832 return;
1833 }
1834
1835 if (VALUE_IS_CELLRANGE (v)) {
1836 out->convs->output.range_ref (out, &v->v_range.cell);
1837 return;
1838 }
1839
1840 if (VALUE_IS_BOOLEAN (v) &&
1841 out->convs->output.boolean != NULL) {
1842 out->convs->output.boolean (out, v->v_bool.val);
1843 return;
1844 }
1845
1846
1847 value_get_as_gstring (v, target, out->convs);
1848
1849 /* If the number has a sign, pretend that it is the result of
1850 * OPER_UNARY_{NEG,PLUS}.
1851 */
1852 if ((target->str[prelen] == '-' || target->str[prelen] == '+') &&
1853 operations[GNM_EXPR_OP_UNARY_NEG].prec <= paren_level) {
1854 g_string_insert_c (target, prelen, '(');
1855 g_string_append_c (target, ')');
1856 }
1857 return;
1858 }
1859
1860 case GNM_EXPR_OP_ARRAY_CORNER:
1861 do_expr_as_string (expr->array_corner.expr, 0, out);
1862 return;
1863
1864 case GNM_EXPR_OP_ARRAY_ELEM: {
1865 GnmCell const *corner = array_elem_get_corner (&expr->array_elem,
1866 out->pp->sheet, &out->pp->eval);
1867 if (NULL != corner) {
1868 GnmParsePos const *real_pp = out->pp;
1869 GnmParsePos pp = *real_pp;
1870
1871 pp.eval.col -= expr->array_elem.x;
1872 pp.eval.row -= expr->array_elem.y;
1873 out->pp = &pp;
1874 do_expr_as_string (
1875 corner->base.texpr->expr->array_corner.expr,
1876 0, out);
1877 out->pp = real_pp;
1878 return;
1879 }
1880 break;
1881 }
1882
1883 case GNM_EXPR_OP_SET:
1884 gnm_expr_list_as_string (expr->set.argc, expr->set.argv, out);
1885 return;
1886 }
1887
1888 g_string_append (target, "<ERROR>");
1889 }
1890
1891 /**
1892 * gnm_expr_as_gstring:
1893 * @expr: #GnmExpr
1894 * @out: output conventions
1895 *
1896 * Renders the expression as a string according to @out and places the
1897 * result in @out's accumulator.
1898 */
1899 void
gnm_expr_as_gstring(GnmExpr const * expr,GnmConventionsOut * out)1900 gnm_expr_as_gstring (GnmExpr const *expr, GnmConventionsOut *out)
1901 {
1902 g_return_if_fail (expr != NULL);
1903 g_return_if_fail (out != NULL);
1904
1905 do_expr_as_string (expr, 0, out);
1906 }
1907
1908 /**
1909 * gnm_expr_as_string:
1910 * @expr: #GnmExpr
1911 * @pp: (nullable): Parse position. %NULL should be used for debugging only.
1912 * @convs: (nullable): #GnmConventions. %NULL should be used for debugging
1913 * or when @pp identifies a #Sheet.
1914 *
1915 * Renders the expression as a string according to @convs.
1916 *
1917 * Returns: (transfer full): @expr as a string.
1918 */
1919 char *
gnm_expr_as_string(GnmExpr const * expr,GnmParsePos const * pp,GnmConventions const * convs)1920 gnm_expr_as_string (GnmExpr const *expr, GnmParsePos const *pp,
1921 GnmConventions const *convs)
1922 {
1923 GnmConventionsOut out;
1924 GnmParsePos pp0;
1925
1926 g_return_val_if_fail (expr != NULL, NULL);
1927
1928 /*
1929 * Defaults for debugging only!
1930 */
1931 if (!pp) {
1932 /* UGH: Just get the first sheet in the first workbook! */
1933 Workbook *wb = gnm_app_workbook_get_by_index (0);
1934 Sheet *sheet = workbook_sheet_by_index (wb, 0);
1935 parse_pos_init (&pp0, NULL, sheet, 0, 0);
1936 pp = &pp0;
1937 }
1938 if (!convs)
1939 convs = pp->sheet
1940 ? sheet_get_conventions (pp->sheet)
1941 : gnm_conventions_default;
1942
1943 out.accum = g_string_new (NULL);
1944 out.pp = pp;
1945 out.convs = convs;
1946 do_expr_as_string (expr, 0, &out);
1947 return g_string_free (out.accum, FALSE);
1948 }
1949
1950 /****************************************************************************/
1951
1952 static gboolean
gnm_expr_is_err(GnmExpr const * expr,GnmStdError err)1953 gnm_expr_is_err (GnmExpr const *expr, GnmStdError err)
1954 {
1955 GnmStdError err2;
1956
1957 if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_CONSTANT)
1958 return FALSE;
1959
1960 err2 = value_error_classify (expr->constant.value);
1961 return err == err2;
1962 }
1963
1964 /**
1965 * gnm_expr_get_constant:
1966 * @expr: #GnmExpr
1967 *
1968 * Returns: (transfer none) (nullable): If this expression consists of just
1969 * a constant, return it. Otherwise, %NULL.
1970 */
1971 GnmValue const *
gnm_expr_get_constant(GnmExpr const * expr)1972 gnm_expr_get_constant (GnmExpr const *expr)
1973 {
1974 if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_CONSTANT)
1975 return NULL;
1976
1977 return expr->constant.value;
1978 }
1979
1980 /**
1981 * gnm_expr_get_name:
1982 * @expr: #GnmExpr
1983 *
1984 * Returns: (transfer none) (nullable): If this expression consists of just
1985 * a name, return it. Otherwise, %NULL.
1986 */
1987 GnmNamedExpr const *
gnm_expr_get_name(GnmExpr const * expr)1988 gnm_expr_get_name (GnmExpr const *expr)
1989 {
1990 if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_NAME)
1991 return NULL;
1992
1993 return expr->name.name;
1994 }
1995
1996
1997 /**
1998 * gnm_expr_get_cellref:
1999 * @expr: #GnmExpr
2000 *
2001 * Returns: (transfer none) (nullable): If this expression consists of just
2002 * a cell reference, return it. Otherwise, %NULL.
2003 */
2004 GnmCellRef const *
gnm_expr_get_cellref(GnmExpr const * expr)2005 gnm_expr_get_cellref (GnmExpr const *expr)
2006 {
2007 if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_CELLREF)
2008 return NULL;
2009
2010 return &expr->cellref.ref;
2011 }
2012
2013
2014 typedef struct {
2015 GnmExprRelocateInfo const *details;
2016 gboolean from_inside;
2017 gboolean check_rels;
2018 } RelocInfoInternal;
2019
2020 static GnmExpr const *
invalidate_sheet_cellrange(RelocInfoInternal const * rinfo,GnmValueRange const * v)2021 invalidate_sheet_cellrange (RelocInfoInternal const *rinfo,
2022 GnmValueRange const *v)
2023 {
2024 GnmCellRef ref_a = v->cell.a;
2025 GnmCellRef ref_b = v->cell.b;
2026
2027 Sheet const *sheet_a = ref_a.sheet;
2028 Sheet const *sheet_b = ref_b.sheet;
2029 Workbook *wb;
2030 gboolean hit_a = sheet_a && sheet_a->being_invalidated;
2031 gboolean hit_b = sheet_b && sheet_b->being_invalidated;
2032 int dir;
2033
2034 if (!hit_a && !hit_b)
2035 return NULL;
2036
2037 if (sheet_a == NULL || sheet_b == NULL ||
2038 sheet_a->workbook != sheet_b->workbook)
2039 /* A 3D reference between workbooks? */
2040 return gnm_expr_new_constant (value_new_error_REF (NULL));
2041
2042 /* Narrow the sheet range. */
2043 wb = sheet_a->workbook;
2044 dir = (sheet_a->index_in_wb < sheet_b->index_in_wb) ? +1 : -1;
2045 while (sheet_a != sheet_b && sheet_a->being_invalidated)
2046 sheet_a = workbook_sheet_by_index (wb, sheet_a->index_in_wb + dir);
2047 while (sheet_a != sheet_b && sheet_b->being_invalidated)
2048 sheet_b = workbook_sheet_by_index (wb, sheet_b->index_in_wb - dir);
2049
2050 if (sheet_a->being_invalidated)
2051 return gnm_expr_new_constant (value_new_error_REF (NULL));
2052
2053 ref_a.sheet = (Sheet *)sheet_a;
2054 ref_b.sheet = (Sheet *)sheet_b;
2055 return gnm_expr_new_constant (value_new_cellrange_unsafe (&ref_a, &ref_b));
2056 }
2057
2058 static gboolean
reloc_range(GnmExprRelocateInfo const * rinfo,Sheet const * start_sheet,Sheet const * end_sheet,GnmRange * rng)2059 reloc_range (GnmExprRelocateInfo const *rinfo,
2060 Sheet const *start_sheet, Sheet const *end_sheet,
2061 GnmRange *rng)
2062 {
2063 GnmRange t, b, l, r;
2064 gboolean start, end;
2065
2066 if (start_sheet != end_sheet || /* ignore 3d refs */
2067 start_sheet != rinfo->origin_sheet) /* ref is to a different sheet */
2068 return FALSE;
2069
2070 t.start.col = b.start.col = l.start.col = l.end.col = rng->start.col;
2071 t.end.col = b.end.col = r.start.col = r.end.col = rng->end.col;
2072 t.start.row = t.end.row = l.start.row = r.start.row = rng->start.row;
2073 b.start.row = b.end.row = l.end.row = r.end.row = rng->end.row;
2074
2075 start = range_contained (&t, &rinfo->origin);
2076 end = range_contained (&b, &rinfo->origin);
2077 if (start && end) { /* full enclosure */
2078 rng->start.col += rinfo->col_offset;
2079 rng->end.col += rinfo->col_offset;
2080 rng->start.row += rinfo->row_offset;
2081 rng->end.row += rinfo->row_offset;
2082 return TRUE;
2083 }
2084
2085 if (rinfo->col_offset == 0) {
2086 if (start && rinfo->row_offset < range_height (rng)) {
2087 rng->start.row += rinfo->row_offset;
2088 return TRUE;
2089 }
2090 if (end && rinfo->row_offset > -range_height (rng)) {
2091 /* Special case invalidating the bottom of a range while
2092 * deleting rows. Otherwise we #REF! before we can shorten
2093 * The -1 is safe, origin.start.row == 0 is handled above */
2094 if (rinfo->reloc_type == GNM_EXPR_RELOCATE_ROWS &&
2095 rinfo->row_offset >= gnm_sheet_get_max_rows (end_sheet))
2096 rng->end.row = rinfo->origin.start.row - 1;
2097 else
2098 rng->end.row += rinfo->row_offset;
2099 return TRUE;
2100 }
2101 }
2102
2103 if (rinfo->row_offset == 0) {
2104 if (range_contained (&l, &rinfo->origin) &&
2105 rinfo->col_offset < range_width (rng)) {
2106 rng->start.col += rinfo->col_offset;
2107 return TRUE;
2108 }
2109 if (range_contained (&r, &rinfo->origin) &&
2110 rinfo->col_offset > -range_width (rng)) {
2111 /* Special case invalidating the right side of a range while
2112 * deleting cols. Otherwise we #REF! before we can shorten.
2113 * The -1 is safe, origin.start.col == 0 is handled above */
2114 if (rinfo->reloc_type == GNM_EXPR_RELOCATE_COLS &&
2115 rinfo->col_offset >= gnm_sheet_get_max_cols (end_sheet))
2116 rng->end.col = rinfo->origin.start.col - 1;
2117 else
2118 rng->end.col += rinfo->col_offset;
2119 return TRUE;
2120 }
2121 }
2122
2123 return FALSE;
2124 }
2125
2126 static void
reloc_normalize_cellref(RelocInfoInternal const * rinfo,GnmCellRef const * ref,Sheet ** sheet,GnmCellPos * res)2127 reloc_normalize_cellref (RelocInfoInternal const *rinfo, GnmCellRef const *ref,
2128 Sheet **sheet, GnmCellPos *res)
2129 {
2130 *sheet = eval_sheet (ref->sheet, rinfo->details->pos.sheet);
2131 res->col = ref->col;
2132 if (ref->col_relative) {
2133 if (rinfo->check_rels)
2134 res->col += rinfo->details->pos.eval.col;
2135 else
2136 res->col = 0;
2137 }
2138 res->row = ref->row;
2139 if (ref->row_relative) {
2140 if (rinfo->check_rels)
2141 res->row += rinfo->details->pos.eval.row;
2142 else
2143 res->row = 0;
2144 }
2145 }
2146
2147 /* Return %TRUE if @pos is out of bounds */
2148 static gboolean
reloc_restore_cellref(RelocInfoInternal const * rinfo,GnmSheetSize const * ss,GnmCellPos const * pos,GnmCellRef * res)2149 reloc_restore_cellref (RelocInfoInternal const *rinfo,
2150 GnmSheetSize const *ss, GnmCellPos const *pos,
2151 GnmCellRef *res)
2152 {
2153 if (res->sheet == rinfo->details->origin_sheet) {
2154 res->sheet = rinfo->details->target_sheet;
2155 if (res->sheet)
2156 ss = gnm_sheet_get_size (res->sheet);
2157 }
2158
2159 if (!res->col_relative || rinfo->check_rels) {
2160 if (pos->col < 0 || ss->max_cols <= pos->col)
2161 return TRUE;
2162 res->col = pos->col;
2163 if (res->col_relative) {
2164 res->col -= rinfo->details->pos.eval.col;
2165 if (rinfo->from_inside)
2166 res->col -= rinfo->details->col_offset;
2167 }
2168 }
2169
2170 if (!res->row_relative || rinfo->check_rels) {
2171 if (pos->row < 0 || ss->max_rows <= pos->row)
2172 return TRUE;
2173 res->row = pos->row;
2174 if (res->row_relative) {
2175 res->row -= rinfo->details->pos.eval.row;
2176 if (rinfo->from_inside)
2177 res->row -= rinfo->details->row_offset;
2178 }
2179 }
2180
2181 return FALSE;
2182 }
2183
2184
2185 static GnmExpr const *
reloc_cellrange(RelocInfoInternal const * rinfo,GnmValueRange const * v,gboolean sticky_end)2186 reloc_cellrange (RelocInfoInternal const *rinfo, GnmValueRange const *v,
2187 gboolean sticky_end)
2188 {
2189 GnmRange r;
2190 Sheet *start_sheet, *end_sheet;
2191 GnmSheetSize const *start_ss, *end_ss;
2192 gboolean full_col, full_row;
2193 gboolean full_col_begin, full_row_begin;
2194
2195 /* Normalize the rangeRef, and remember if we had a full col/row
2196 * ref. If relocating the result changes things, or if we're from
2197 * inside the range that is moving map back to a RangeRef from the
2198 * target position. If the result is different that the original
2199 * generate a new expression. */
2200 reloc_normalize_cellref (rinfo, &v->cell.a, &start_sheet, &r.start);
2201 reloc_normalize_cellref (rinfo, &v->cell.b, &end_sheet, &r.end);
2202 /* (Foo,NULL) in Bar will generate (Foo,Bar) in normalize */
2203 if (NULL == v->cell.b.sheet)
2204 end_sheet = start_sheet;
2205 start_ss = gnm_sheet_get_size2 (start_sheet, rinfo->details->pos.wb);
2206 end_ss = gnm_sheet_get_size2 (end_sheet, rinfo->details->pos.wb);
2207
2208 full_col = sticky_end && r.end.row >= start_ss->max_rows - 1;
2209 full_col_begin = full_col && r.start.row == 0;
2210
2211 full_row = sticky_end && r.end.col >= start_ss->max_cols - 1;
2212 full_row_begin = full_row && r.start.col == 0;
2213
2214 if (reloc_range (rinfo->details, start_sheet, end_sheet, &r) ||
2215 rinfo->from_inside) {
2216 GnmRangeRef res = v->cell;
2217
2218 if (full_col)
2219 r.end.row = start_ss->max_rows - 1;
2220 if (full_col_begin)
2221 r.start.row = 0;
2222 if (full_row)
2223 r.end.col = start_ss->max_cols - 1;
2224 if (full_row_begin)
2225 r.start.col = 0;
2226
2227 if (reloc_restore_cellref (rinfo, start_ss, &r.start, &res.a) ||
2228 reloc_restore_cellref (rinfo, end_ss, &r.end, &res.b))
2229 return gnm_expr_new_constant (value_new_error_REF (NULL));
2230 if (gnm_rangeref_equal (&res, &v->cell))
2231 return NULL;
2232 return gnm_expr_new_constant (value_new_cellrange_unsafe (&res.a, &res.b));
2233 }
2234
2235 return NULL;
2236 }
2237
2238 static GnmExpr const *
2239 gnm_expr_relocate (GnmExpr const *expr, RelocInfoInternal const *rinfo);
2240
2241 static GnmExpr const *
cb_relocate(GnmExpr const * expr,GnmExprWalk * data)2242 cb_relocate (GnmExpr const *expr, GnmExprWalk *data)
2243 {
2244 RelocInfoInternal const *rinfo = data->user;
2245
2246 switch (GNM_EXPR_GET_OPER (expr)) {
2247 case GNM_EXPR_OP_NAME: {
2248 GnmNamedExpr *nexpr = expr->name.name;
2249
2250 /* we cannot invalidate references to the name that are
2251 * sitting in the undo queue, or the clipboard. So we just
2252 * flag the name as inactive and remove the reference here.
2253 */
2254 if (!expr_name_is_active (nexpr))
2255 return gnm_expr_new_constant (value_new_error_REF (NULL));
2256
2257 switch (rinfo->details->reloc_type) {
2258 case GNM_EXPR_RELOCATE_INVALIDATE_SHEET:
2259 if (nexpr->pos.sheet && nexpr->pos.sheet->being_invalidated)
2260 return gnm_expr_new_constant (value_new_error_REF (NULL));
2261 else
2262 return NULL;
2263
2264 case GNM_EXPR_RELOCATE_MOVE_RANGE:
2265 /*
2266 * If the name is not officially scoped, check
2267 * that it is available in the new scope
2268 */
2269 if (expr->name.optional_scope == NULL &&
2270 rinfo->details->target_sheet != rinfo->details->origin_sheet) {
2271 GnmNamedExpr *new_nexpr;
2272 GnmParsePos pos;
2273 parse_pos_init_sheet (&pos, rinfo->details->target_sheet);
2274
2275 /* If the name is not available in the new scope explicitly scope it */
2276 new_nexpr = expr_name_lookup (&pos, expr_name_name (nexpr));
2277 if (new_nexpr == NULL) {
2278 if (nexpr->pos.sheet != NULL)
2279 return gnm_expr_new_name (nexpr, nexpr->pos.sheet, NULL);
2280 return gnm_expr_new_name (nexpr, NULL, nexpr->pos.wb);
2281 }
2282
2283 /* replace it with the new name using qualified as
2284 * local to the target sheet
2285 */
2286 return gnm_expr_new_name (new_nexpr, pos.sheet, NULL);
2287 } else {
2288 /*
2289 * Do NOT rewrite the name.
2290 *
2291 * Just invalidate the use of the name if the
2292 * name's expression, if relocated, would
2293 * become invalid.
2294 */
2295 GnmExpr const *tmp =
2296 gnm_expr_relocate (nexpr->texpr->expr,
2297 rinfo);
2298 if (tmp && gnm_expr_is_err (tmp, GNM_ERROR_REF))
2299 return tmp;
2300
2301 if (tmp)
2302 gnm_expr_free (tmp);
2303
2304 return NULL;
2305 }
2306
2307 case GNM_EXPR_RELOCATE_COLS:
2308 case GNM_EXPR_RELOCATE_ROWS:
2309 return NULL;
2310
2311 default:
2312 g_assert_not_reached ();
2313 }
2314 }
2315
2316 case GNM_EXPR_OP_CELLREF: {
2317 GnmCellRef const *ref = &expr->cellref.ref;
2318 switch (rinfo->details->reloc_type) {
2319 case GNM_EXPR_RELOCATE_INVALIDATE_SHEET:
2320 if (ref->sheet &&
2321 ref->sheet->being_invalidated)
2322 return gnm_expr_new_constant (value_new_error_REF (NULL));
2323 return NULL;
2324
2325 case GNM_EXPR_RELOCATE_MOVE_RANGE:
2326 case GNM_EXPR_RELOCATE_COLS:
2327 case GNM_EXPR_RELOCATE_ROWS: {
2328 GnmRange r;
2329 Sheet *sheet;
2330 GnmSheetSize const *ss;
2331
2332 reloc_normalize_cellref (rinfo, ref, &sheet, &r.start);
2333 r.end = r.start;
2334 ss = gnm_sheet_get_size2 (sheet, rinfo->details->pos.wb);
2335
2336 if (reloc_range (rinfo->details, sheet, sheet, &r) ||
2337 rinfo->from_inside) {
2338 GnmCellRef res = *ref;
2339 if (reloc_restore_cellref (rinfo, ss, &r.start, &res))
2340 return gnm_expr_new_constant (value_new_error_REF (NULL));
2341 if (gnm_cellref_equal (&res, ref))
2342 return NULL;
2343 return gnm_expr_new_cellref (&res);
2344 }
2345 return NULL;
2346 }
2347
2348 default:
2349 g_assert_not_reached ();
2350 }
2351
2352 return NULL;
2353 }
2354
2355 case GNM_EXPR_OP_CONSTANT:
2356 if (VALUE_IS_CELLRANGE (expr->constant.value)) {
2357 GnmValueRange const *vr = &expr->constant.value->v_range;
2358 switch (rinfo->details->reloc_type) {
2359 case GNM_EXPR_RELOCATE_INVALIDATE_SHEET:
2360 return invalidate_sheet_cellrange (rinfo, vr);
2361 case GNM_EXPR_RELOCATE_MOVE_RANGE:
2362 return reloc_cellrange (rinfo, vr, TRUE);
2363 case GNM_EXPR_RELOCATE_COLS:
2364 case GNM_EXPR_RELOCATE_ROWS:
2365 return reloc_cellrange (rinfo, vr, rinfo->details->sticky_end);
2366 default:
2367 g_assert_not_reached ();
2368 }
2369 }
2370 return NULL;
2371
2372 default:
2373 return NULL;
2374 }
2375 }
2376
2377 static GnmExpr const *
gnm_expr_relocate(GnmExpr const * expr,RelocInfoInternal const * rinfo)2378 gnm_expr_relocate (GnmExpr const *expr, RelocInfoInternal const *rinfo)
2379 {
2380 g_return_val_if_fail (expr != NULL, NULL);
2381 return gnm_expr_walk (expr, cb_relocate, (gpointer)rinfo);
2382 }
2383
2384 /**
2385 * gnm_expr_get_func_def:
2386 * @expr: Function call expressions
2387 *
2388 * Returns: (transfer none): the called function.
2389 */
2390 GnmFunc *
gnm_expr_get_func_def(GnmExpr const * expr)2391 gnm_expr_get_func_def (GnmExpr const *expr)
2392 {
2393 g_return_val_if_fail (expr != NULL, NULL);
2394 g_return_val_if_fail (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL, NULL);
2395
2396 return expr->func.func;
2397 }
2398
2399 /**
2400 * gnm_expr_get_func_arg:
2401 * @expr: Function call expressions
2402 * @i: argument index
2403 *
2404 * Returns: (transfer none): the @i'th argument of the function call @expr.
2405 */
2406 GnmExpr const *
gnm_expr_get_func_arg(GnmExpr const * expr,int i)2407 gnm_expr_get_func_arg (GnmExpr const *expr, int i)
2408 {
2409 g_return_val_if_fail (expr != NULL, NULL);
2410 g_return_val_if_fail (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL, NULL);
2411 g_return_val_if_fail (i >= 0 && i < expr->func.argc, NULL);
2412
2413 return expr->func.argv[i];
2414 }
2415
2416
2417 static void
cellref_boundingbox(GnmCellRef const * cr,Sheet const * sheet,GnmRange * bound)2418 cellref_boundingbox (GnmCellRef const *cr, Sheet const *sheet, GnmRange *bound)
2419 {
2420 GnmSheetSize const *ss;
2421
2422 if (cr->sheet)
2423 sheet = cr->sheet;
2424 ss = gnm_sheet_get_size (sheet);
2425
2426 if (cr->col_relative) {
2427 if (cr->col >= 0) {
2428 int const c = ss->max_cols - cr->col - 1;
2429 if (bound->end.col > c)
2430 bound->end.col = c;
2431 } else {
2432 int const c = -cr->col;
2433 if (bound->start.col < c)
2434 bound->start.col = c;
2435 }
2436 }
2437 if (cr->row_relative) {
2438 if (cr->row >= 0) {
2439 int const r = ss->max_rows - cr->row - 1;
2440 if (bound->end.row > r)
2441 bound->end.row = r;
2442 } else {
2443 int const r = -cr->row;
2444 if (bound->start.row < r)
2445 bound->start.row = r;
2446 }
2447 }
2448 }
2449
2450 static GnmExpr const *
cb_contains_subtotal(GnmExpr const * expr,GnmExprWalk * data)2451 cb_contains_subtotal (GnmExpr const *expr, GnmExprWalk *data)
2452 {
2453 gboolean *res = data->user;
2454 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL &&
2455 strcmp (expr->func.func->name, "subtotal") == 0) {
2456 *res = TRUE;
2457 data->stop = TRUE;
2458 }
2459 return NULL;
2460 }
2461
2462 /**
2463 * gnm_expr_containts_subtotal:
2464 * @expr: #GnmExpr
2465 *
2466 * Returns: %TRUE if the expression calls the SUBTOTAL function
2467 **/
2468 gboolean
gnm_expr_contains_subtotal(GnmExpr const * expr)2469 gnm_expr_contains_subtotal (GnmExpr const *expr)
2470 {
2471 gboolean res = FALSE;
2472 gnm_expr_walk (expr, cb_contains_subtotal, &res);
2473 return res;
2474 }
2475
2476 /**
2477 * gnm_expr_get_range:
2478 * @expr: #GnmExpr
2479 *
2480 * Returns: (transfer full) (nullable): If this expression contains a
2481 * single range, return it. Otherwise, %NULL. A cell reference is
2482 * returned as a singleton range.
2483 */
2484 GnmValue *
gnm_expr_get_range(GnmExpr const * expr)2485 gnm_expr_get_range (GnmExpr const *expr)
2486 {
2487 g_return_val_if_fail (expr != NULL, NULL);
2488
2489 switch (GNM_EXPR_GET_OPER (expr)) {
2490 case GNM_EXPR_OP_CELLREF:
2491 return value_new_cellrange_unsafe (
2492 &expr->cellref.ref, &expr->cellref.ref);
2493
2494 case GNM_EXPR_OP_CONSTANT:
2495 if (VALUE_IS_CELLRANGE (expr->constant.value))
2496 return value_dup (expr->constant.value);
2497 return NULL;
2498
2499 case GNM_EXPR_OP_NAME:
2500 if (!expr_name_is_active (expr->name.name))
2501 return NULL;
2502 return gnm_expr_top_get_range (expr->name.name->texpr);
2503
2504 case GNM_EXPR_OP_PAREN:
2505 return gnm_expr_get_range (expr->unary.value);
2506
2507 default:
2508 return NULL;
2509 }
2510 }
2511
2512 static gint
gnm_insert_unique_value_cmp(gconstpointer a,gconstpointer b)2513 gnm_insert_unique_value_cmp (gconstpointer a, gconstpointer b)
2514 {
2515 return (value_equal (a,b) ? 0 : 1);
2516 }
2517
2518
2519
2520 static GSList *
gnm_insert_unique_value(GSList * list,GnmValue * data)2521 gnm_insert_unique_value (GSList *list, GnmValue *data)
2522 {
2523 if (g_slist_find_custom (list, data,
2524 gnm_insert_unique_value_cmp)
2525 == NULL)
2526 return g_slist_prepend (list, data);
2527 value_release (data);
2528 return list;
2529 }
2530
2531 /**
2532 * gnm_expr_is_rangeref:
2533 * @expr: #GnmExpr
2534 *
2535 * Returns: %TRUE if the expression can generate a reference.
2536 * NOTE: in the future it would be nice to know if a function
2537 * can return a reference to tighten that up a bit.
2538 **/
2539 gboolean
gnm_expr_is_rangeref(GnmExpr const * expr)2540 gnm_expr_is_rangeref (GnmExpr const *expr)
2541 {
2542 g_return_val_if_fail (expr != NULL, FALSE);
2543
2544 switch (GNM_EXPR_GET_OPER (expr)) {
2545 /* would be better if we could differential which functions can return refs */
2546 case GNM_EXPR_OP_FUNCALL:
2547
2548 /* a set in a set, do we need this ? */
2549 case GNM_EXPR_OP_SET:
2550
2551 case GNM_EXPR_OP_RANGE_CTOR:
2552 case GNM_EXPR_OP_INTERSECT:
2553 case GNM_EXPR_OP_CELLREF:
2554 return TRUE;
2555
2556 case GNM_EXPR_OP_CONSTANT:
2557 if (VALUE_IS_CELLRANGE (expr->constant.value))
2558 return TRUE;
2559 return FALSE;
2560
2561 case GNM_EXPR_OP_NAME:
2562 if (expr_name_is_active (expr->name.name))
2563 return gnm_expr_is_rangeref (expr->name.name->texpr->expr);
2564 return FALSE;
2565
2566 case GNM_EXPR_OP_ARRAY_CORNER: /* I don't think this is possible */
2567 case GNM_EXPR_OP_ARRAY_ELEM:
2568 default:
2569 return FALSE;
2570 }
2571 }
2572
2573 gboolean
gnm_expr_is_data_table(GnmExpr const * expr,GnmCellPos * c_in,GnmCellPos * r_in)2574 gnm_expr_is_data_table (GnmExpr const *expr, GnmCellPos *c_in, GnmCellPos *r_in)
2575 {
2576 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL) {
2577 char const *name = gnm_func_get_name (expr->func.func, FALSE);
2578 if (name && 0 == strcmp (name, "table")) {
2579 if (NULL != r_in) {
2580 GnmExpr const *r = (expr->func.argc <= 0)
2581 ? NULL
2582 : expr->func.argv[0];
2583
2584 if (r != NULL && GNM_EXPR_GET_OPER (r) == GNM_EXPR_OP_CELLREF) {
2585 r_in->col = r->cellref.ref.col;
2586 r_in->row = r->cellref.ref.row;
2587 } else
2588 r_in->col = r_in->row = 0; /* impossible */
2589 }
2590 if (NULL != c_in) {
2591 GnmExpr const *c = (expr->func.argc <= 1)
2592 ? NULL
2593 : expr->func.argv[1];
2594
2595 if (c != NULL && GNM_EXPR_GET_OPER (c) == GNM_EXPR_OP_CELLREF) {
2596 c_in->col = c->cellref.ref.col;
2597 c_in->row = c->cellref.ref.row;
2598 } else
2599 c_in->col = c_in->row = 0; /* impossible */
2600 }
2601 return TRUE;
2602 }
2603 }
2604
2605 /* Do we need anything else here ? */
2606 return FALSE;
2607 }
2608
2609
2610 static GnmExpr const *
do_expr_walk(GnmExpr const * expr,GnmExprWalkerFunc walker,GnmExprWalk * data)2611 do_expr_walk (GnmExpr const *expr, GnmExprWalkerFunc walker, GnmExprWalk *data)
2612 {
2613 GnmExpr const *res;
2614
2615 res = walker (expr, data);
2616 if (data->stop) {
2617 if (res) gnm_expr_free (res);
2618 return NULL;
2619 }
2620 if (res)
2621 return res;
2622
2623 switch (GNM_EXPR_GET_OPER (expr)) {
2624 case GNM_EXPR_OP_RANGE_CTOR:
2625 case GNM_EXPR_OP_INTERSECT:
2626 case GNM_EXPR_OP_ANY_BINARY: {
2627 GnmExpr const *a, *b;
2628
2629 a = do_expr_walk (expr->binary.value_a, walker, data);
2630 if (data->stop)
2631 return NULL;
2632
2633 b = do_expr_walk (expr->binary.value_b, walker, data);
2634 if (data->stop) {
2635 if (a) gnm_expr_free (a);
2636 return NULL;
2637 }
2638
2639 if (!a && !b)
2640 return NULL;
2641
2642 if (!a)
2643 a = gnm_expr_copy (expr->binary.value_a);
2644 else if (!b)
2645 b = gnm_expr_copy (expr->binary.value_b);
2646
2647 return gnm_expr_new_binary (a, GNM_EXPR_GET_OPER (expr), b);
2648 }
2649
2650 case GNM_EXPR_OP_ANY_UNARY: {
2651 GnmExpr const *a = do_expr_walk (expr->unary.value, walker, data);
2652 return a
2653 ? gnm_expr_new_unary (GNM_EXPR_GET_OPER (expr), a)
2654 : NULL;
2655 }
2656
2657 case GNM_EXPR_OP_FUNCALL: {
2658 gboolean any = FALSE;
2659 int i;
2660 int argc = expr->func.argc;
2661 GnmExprConstPtr *argv =
2662 argc ? g_new (GnmExprConstPtr, argc) : NULL;
2663
2664 for (i = 0; i < argc; i++) {
2665 argv[i] = do_expr_walk (expr->func.argv[i], walker, data);
2666 if (data->stop) {
2667 while (--i >= 0)
2668 if (argv[i])
2669 gnm_expr_free (argv[i]);
2670 any = FALSE;
2671 break;
2672 }
2673 if (argv[i])
2674 any = TRUE;
2675 }
2676
2677 if (any) {
2678 int i;
2679 for (i = 0; i < argc; i++)
2680 if (!argv[i])
2681 argv[i] = gnm_expr_copy (expr->func.argv[i]);
2682 return gnm_expr_new_funcallv (expr->func.func,
2683 argc, argv);
2684 } else {
2685 g_free (argv);
2686 return NULL;
2687 }
2688 }
2689 case GNM_EXPR_OP_SET: {
2690 gboolean any = FALSE;
2691 int i;
2692 int argc = expr->set.argc;
2693 GnmExprConstPtr *argv =
2694 argc ? g_new (GnmExprConstPtr, argc) : NULL;
2695
2696 for (i = 0; i < argc; i++) {
2697 argv[i] = do_expr_walk (expr->set.argv[i], walker, data);
2698 if (data->stop) {
2699 while (--i >= 0)
2700 if (argv[i])
2701 gnm_expr_free (argv[i]);
2702 any = FALSE;
2703 break;
2704 }
2705 if (argv[i])
2706 any = TRUE;
2707 }
2708
2709 if (any) {
2710 int i;
2711 for (i = 0; i < argc; i++)
2712 if (!argv[i])
2713 argv[i] = gnm_expr_copy (expr->set.argv[i]);
2714 return gnm_expr_new_setv (argc, argv);
2715 } else {
2716 g_free (argv);
2717 return NULL;
2718 }
2719 }
2720
2721 case GNM_EXPR_OP_ARRAY_CORNER: {
2722 GnmExpr const *e = do_expr_walk (expr->array_corner.expr, walker, data);
2723 return e
2724 ? gnm_expr_new_array_corner (
2725 expr->array_corner.cols,
2726 expr->array_corner.rows, e)
2727 : NULL;
2728 }
2729
2730 default:
2731 return NULL;
2732 }
2733 }
2734
2735 /**
2736 * gnm_expr_walk:
2737 * @expr: expression to walk
2738 * @walker: (scope call): callback for each sub-expression
2739 * @user: user data pointer
2740 *
2741 * Returns: (transfer full) (nullable): transformed expression.
2742 *
2743 * This function walks the expression and calls the walker function for
2744 * each subexpression. If the walker returns a non-%NULL expression,
2745 * a new expression is built.
2746 *
2747 * The walker will be called for an expression before its subexpressions.
2748 * It will receive the expression as its first argument and a GnmExprWalk
2749 * pointer as its second. It may set the stop flag to terminate the walk
2750 * in which case gnm_expr_walk will return %NULL.
2751 **/
2752 GnmExpr const *
gnm_expr_walk(GnmExpr const * expr,GnmExprWalkerFunc walker,gpointer user)2753 gnm_expr_walk (GnmExpr const *expr, GnmExprWalkerFunc walker, gpointer user)
2754 {
2755 GnmExprWalk data;
2756
2757 g_return_val_if_fail (expr != NULL, NULL);
2758
2759 data.user = user;
2760 data.stop = FALSE;
2761 data.flags = 0;
2762 return do_expr_walk (expr, walker, &data);
2763 }
2764
2765 /**
2766 * gnm_expr_is_empty:
2767 * @expr: #GnmExpr
2768 *
2769 * Returns: %TRUE if @expr is a constant expression with the empty value.
2770 */
2771 gboolean
gnm_expr_is_empty(GnmExpr const * expr)2772 gnm_expr_is_empty (GnmExpr const *expr)
2773 {
2774 g_return_val_if_fail (expr != NULL, FALSE);
2775
2776 return (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_CONSTANT &&
2777 VALUE_IS_EMPTY (expr->constant.value));
2778 }
2779
2780 /**
2781 * gnm_expr_list_unref:
2782 * @list: (transfer full): expression list
2783 *
2784 * This frees list and all the expressions in it.
2785 */
2786 void
gnm_expr_list_unref(GnmExprList * list)2787 gnm_expr_list_unref (GnmExprList *list)
2788 {
2789 GnmExprList *l;
2790 for (l = list; l; l = l->next)
2791 gnm_expr_free (l->data);
2792 gnm_expr_list_free (list);
2793 }
2794
2795 /**
2796 * gnm_expr_list_copy:
2797 * @list: (transfer none): list of expressions
2798 *
2799 * Returns: (transfer full): a copy of the list and all the
2800 * expressions in it.
2801 */
2802 GnmExprList *
gnm_expr_list_copy(GnmExprList * list)2803 gnm_expr_list_copy (GnmExprList *list)
2804 {
2805 GnmExprList *res = g_slist_copy (list); /* shallow */
2806 GnmExprList *l;
2807
2808 for (l = res; l; l = l->next)
2809 l->data = (GnmExpr *) gnm_expr_copy (l->data);
2810
2811 return res;
2812 }
2813
2814
2815 void
gnm_expr_list_as_string(int argc,GnmExprConstPtr const * argv,GnmConventionsOut * out)2816 gnm_expr_list_as_string (int argc,
2817 GnmExprConstPtr const *argv,
2818 GnmConventionsOut *out)
2819 {
2820 int i;
2821 gunichar arg_sep;
2822 if (out->convs->arg_sep)
2823 arg_sep = out->convs->arg_sep;
2824 else
2825 arg_sep = go_locale_get_arg_sep ();
2826
2827 g_string_append_c (out->accum, '(');
2828 for (i = 0; i < argc; i++) {
2829 if (i != 0)
2830 g_string_append_unichar (out->accum, arg_sep);
2831 do_expr_as_string (argv[i], 0, out);
2832 }
2833 g_string_append_c (out->accum, ')');
2834 }
2835
2836 static guint
gnm_expr_hash(GnmExpr const * expr)2837 gnm_expr_hash (GnmExpr const *expr)
2838 {
2839 guint h = (guint)(GNM_EXPR_GET_OPER (expr));
2840
2841 switch (GNM_EXPR_GET_OPER (expr)){
2842 case GNM_EXPR_OP_INTERSECT:
2843 case GNM_EXPR_OP_RANGE_CTOR:
2844 case GNM_EXPR_OP_ANY_BINARY:
2845 return ((gnm_expr_hash (expr->binary.value_a) * 7) ^
2846 (gnm_expr_hash (expr->binary.value_b) * 3) ^
2847 h);
2848
2849 case GNM_EXPR_OP_ANY_UNARY:
2850 return ((gnm_expr_hash (expr->unary.value) * 7) ^
2851 h);
2852
2853 case GNM_EXPR_OP_FUNCALL: {
2854 int i;
2855 for (i = 0; i < expr->func.argc; i++)
2856 h = (h * 3) ^ gnm_expr_hash (expr->func.argv[i]);
2857 return h;
2858 }
2859
2860 case GNM_EXPR_OP_SET: {
2861 int i;
2862 for (i = 0; i < expr->set.argc; i++)
2863 h = (h * 3) ^ gnm_expr_hash (expr->set.argv[i]);
2864 return h;
2865 }
2866
2867 case GNM_EXPR_OP_CONSTANT:
2868 return value_hash (expr->constant.value);
2869
2870 case GNM_EXPR_OP_NAME:
2871 /* all we need is a somewhat unique hash, ignore int != ptr */
2872 return GPOINTER_TO_UINT (expr->name.name);
2873
2874 case GNM_EXPR_OP_CELLREF:
2875 return gnm_cellref_hash (&expr->cellref.ref);
2876
2877 case GNM_EXPR_OP_ARRAY_CORNER:
2878 return gnm_expr_hash (expr->array_corner.expr);
2879
2880 case GNM_EXPR_OP_ARRAY_ELEM:
2881 return ((expr->array_elem.x << 16) ^
2882 (expr->array_elem.y));
2883 }
2884
2885 return h;
2886 }
2887
2888
2889 /***************************************************************************/
2890
2891 GnmExprSharer *
gnm_expr_sharer_new(void)2892 gnm_expr_sharer_new (void)
2893 {
2894 GnmExprSharer *es = g_new (GnmExprSharer, 1);
2895 es->nodes_in = 0;
2896 es->nodes_stored = 0;
2897 es->nodes_killed = 0;
2898 es->exprs = g_hash_table_new_full
2899 ((GHashFunc)gnm_expr_top_hash,
2900 (GEqualFunc)gnm_expr_top_equal,
2901 (GDestroyNotify)gnm_expr_top_unref,
2902 NULL);
2903 es->ref_count = 1;
2904 return es;
2905 }
2906
2907 void
gnm_expr_sharer_unref(GnmExprSharer * es)2908 gnm_expr_sharer_unref (GnmExprSharer *es)
2909 {
2910 if (!es || es->ref_count-- > 1)
2911 return;
2912 g_hash_table_destroy (es->exprs);
2913 g_free (es);
2914 }
2915
2916 static GnmExprSharer *
gnm_expr_sharer_ref(GnmExprSharer * es)2917 gnm_expr_sharer_ref (GnmExprSharer *es)
2918 {
2919 es->ref_count++;
2920 return es;
2921 }
2922
2923 GType
gnm_expr_sharer_get_type(void)2924 gnm_expr_sharer_get_type (void)
2925 {
2926 static GType t = 0;
2927
2928 if (t == 0) {
2929 t = g_boxed_type_register_static ("GnmExprSharer",
2930 (GBoxedCopyFunc)gnm_expr_sharer_ref,
2931 (GBoxedFreeFunc)gnm_expr_sharer_unref);
2932 }
2933 return t;
2934 }
2935
2936 GnmExprTop const *
gnm_expr_sharer_share(GnmExprSharer * es,GnmExprTop const * texpr)2937 gnm_expr_sharer_share (GnmExprSharer *es, GnmExprTop const *texpr)
2938 {
2939 GnmExprTop const *shared;
2940
2941 g_return_val_if_fail (es != NULL, texpr);
2942 g_return_val_if_fail (texpr != NULL, NULL);
2943
2944 es->nodes_in++;
2945
2946 /* Corners must not get shared. */
2947 if (GNM_EXPR_GET_OPER (texpr->expr) == GNM_EXPR_OP_ARRAY_CORNER)
2948 return texpr;
2949
2950 shared = g_hash_table_lookup (es->exprs, texpr);
2951 if (shared) {
2952 gnm_expr_top_ref (shared);
2953 if (texpr->refcount == 1)
2954 es->nodes_killed++;
2955 gnm_expr_top_unref (texpr);
2956 return shared;
2957 }
2958
2959 gnm_expr_top_ref (texpr);
2960 g_hash_table_insert (es->exprs, (gpointer)texpr, (gpointer)texpr);
2961 es->nodes_stored++;
2962
2963 return texpr;
2964 }
2965
2966 void
gnm_expr_sharer_report(GnmExprSharer * es)2967 gnm_expr_sharer_report (GnmExprSharer *es)
2968 {
2969 g_printerr ("Expressions in: %d\n", es->nodes_in);
2970 g_printerr ("Expressions stored: %d\n", es->nodes_stored);
2971 g_printerr ("Expressions killed: %d\n", es->nodes_killed);
2972 }
2973
2974 /***************************************************************************/
2975
2976 GnmExprTop const *
gnm_expr_top_new(GnmExpr const * expr)2977 gnm_expr_top_new (GnmExpr const *expr)
2978 {
2979 GnmExprTop *res;
2980
2981 if (expr == NULL)
2982 return NULL;
2983
2984 res = g_new (GnmExprTop, 1);
2985 res->magic = GNM_EXPR_TOP_MAGIC;
2986 res->hash = 0;
2987 res->refcount = 1;
2988 res->expr = expr;
2989 return res;
2990 }
2991
2992 GnmExprTop const *
gnm_expr_top_new_constant(GnmValue * v)2993 gnm_expr_top_new_constant (GnmValue *v)
2994 {
2995 return gnm_expr_top_new (gnm_expr_new_constant (v));
2996 }
2997
2998 GnmExprTop const *
gnm_expr_top_ref(GnmExprTop const * texpr)2999 gnm_expr_top_ref (GnmExprTop const *texpr)
3000 {
3001 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3002 ((GnmExprTop *)texpr)->refcount++;
3003 return texpr;
3004 }
3005
3006 void
gnm_expr_top_unref(GnmExprTop const * texpr)3007 gnm_expr_top_unref (GnmExprTop const *texpr)
3008 {
3009 g_return_if_fail (GNM_IS_EXPR_TOP (texpr));
3010
3011 ((GnmExprTop *)texpr)->refcount--;
3012 if (texpr->refcount == 0) {
3013 gnm_expr_free (texpr->expr);
3014 ((GnmExprTop *)texpr)->magic = 0;
3015 g_free ((GnmExprTop *)texpr);
3016 }
3017 }
3018
3019 GType
gnm_expr_top_get_type(void)3020 gnm_expr_top_get_type (void)
3021 {
3022 static GType t = 0;
3023
3024 if (t == 0) {
3025 t = g_boxed_type_register_static ("GnmExprTop",
3026 (GBoxedCopyFunc)gnm_expr_top_ref,
3027 (GBoxedFreeFunc)gnm_expr_top_unref);
3028 }
3029 return t;
3030 }
3031
3032 gboolean
gnm_expr_top_is_shared(GnmExprTop const * texpr)3033 gnm_expr_top_is_shared (GnmExprTop const *texpr)
3034 {
3035 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3036
3037 return texpr->refcount > 1;
3038 }
3039
3040 GnmExprTop const *
gnm_expr_top_new_array_corner(int cols,int rows,GnmExpr const * expr)3041 gnm_expr_top_new_array_corner (int cols, int rows, GnmExpr const *expr)
3042 {
3043 return gnm_expr_top_new (gnm_expr_new_array_corner (cols, rows, expr));
3044 }
3045
3046 GnmExprTop const *
gnm_expr_top_new_array_elem(int x,int y)3047 gnm_expr_top_new_array_elem (int x, int y)
3048 {
3049 return gnm_expr_top_new (gnm_expr_new_array_elem (x, y));
3050 }
3051
3052 static GnmExpr const *
cb_get_ranges(GnmExpr const * expr,GnmExprWalk * data)3053 cb_get_ranges (GnmExpr const *expr, GnmExprWalk *data)
3054 {
3055 GSList **pranges = data->user;
3056
3057 /* There's no real reason to exclude names here, except that
3058 we used to do so. */
3059 if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_NAME) {
3060 GnmValue *v = gnm_expr_get_range (expr);
3061 if (v)
3062 *pranges = gnm_insert_unique_value (*pranges, v);
3063 }
3064
3065 return NULL;
3066 }
3067
3068 /**
3069 * gnm_expr_top_get_ranges:
3070 * @texpr:
3071 *
3072 * A collect the set of GnmRanges in @expr.
3073 * Returns: (element-type GnmRange) (transfer full): a list of the unique
3074 * references Caller is responsible for releasing the list and the content.
3075 **/
3076 GSList *
gnm_expr_top_get_ranges(GnmExprTop const * texpr)3077 gnm_expr_top_get_ranges (GnmExprTop const *texpr)
3078 {
3079 GSList *res = NULL;
3080
3081 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3082 gnm_expr_walk (texpr->expr, cb_get_ranges, &res);
3083 return res;
3084 }
3085
3086 GnmValue *
gnm_expr_top_get_range(GnmExprTop const * texpr)3087 gnm_expr_top_get_range (GnmExprTop const *texpr)
3088 {
3089 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3090
3091 return gnm_expr_get_range (texpr->expr);
3092 }
3093
3094 char *
gnm_expr_top_as_string(GnmExprTop const * texpr,GnmParsePos const * pp,GnmConventions const * convs)3095 gnm_expr_top_as_string (GnmExprTop const *texpr,
3096 GnmParsePos const *pp,
3097 GnmConventions const *convs)
3098 {
3099 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3100
3101 return gnm_expr_as_string (texpr->expr, pp, convs);
3102 }
3103
3104 // This differs from gnm_expr_as_string in that a top-level set
3105 // representing multiple expressions is rendered as a comma-separated
3106 // list of expressions with no outside parenthesis.
3107 char *
gnm_expr_top_multiple_as_string(GnmExprTop const * texpr,GnmParsePos const * pp,GnmConventions const * convs)3108 gnm_expr_top_multiple_as_string (GnmExprTop const *texpr,
3109 GnmParsePos const *pp,
3110 GnmConventions const *convs)
3111 {
3112 char *res;
3113
3114 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3115
3116 res = gnm_expr_top_as_string (texpr, pp, convs);
3117
3118 if (GNM_EXPR_GET_OPER (texpr->expr) == GNM_EXPR_OP_SET) {
3119 // Get rid of '(' and ')'. This is crude and probably should
3120 // have made it into convs, but it'll do.
3121 size_t l = strlen (res);
3122 if (l >= 2 && res[0] == '(' && res[l - 1] == ')') {
3123 memmove (res, res + 1, l - 2);
3124 res[l - 2] = 0;
3125 }
3126 }
3127
3128 return res;
3129 }
3130
3131 void
gnm_expr_top_as_gstring(GnmExprTop const * texpr,GnmConventionsOut * out)3132 gnm_expr_top_as_gstring (GnmExprTop const *texpr,
3133 GnmConventionsOut *out)
3134 {
3135 g_return_if_fail (GNM_IS_EXPR_TOP (texpr));
3136 g_return_if_fail (out != NULL);
3137
3138 do_expr_as_string (texpr->expr, 0, out);
3139 }
3140
3141 guint
gnm_expr_top_hash(GnmExprTop const * texpr)3142 gnm_expr_top_hash (GnmExprTop const *texpr)
3143 {
3144 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), 0);
3145
3146 if (texpr->hash == 0) {
3147 ((GnmExprTop *)texpr)->hash = gnm_expr_hash (texpr->expr);
3148 /* The following line tests the truncated value. */
3149 if (texpr->hash == 0)
3150 ((GnmExprTop *)texpr)->hash = 1;
3151 }
3152 return texpr->hash;
3153 }
3154
3155 gboolean
gnm_expr_top_equal(GnmExprTop const * te1,GnmExprTop const * te2)3156 gnm_expr_top_equal (GnmExprTop const *te1, GnmExprTop const *te2)
3157 {
3158 if (te1 == te2)
3159 return TRUE;
3160 if (te1 == NULL || te2 == NULL)
3161 return FALSE;
3162
3163 g_return_val_if_fail (GNM_IS_EXPR_TOP (te1), FALSE);
3164 g_return_val_if_fail (GNM_IS_EXPR_TOP (te2), FALSE);
3165
3166 if (te1->hash && te2->hash && te1->hash != te2->hash)
3167 return FALSE;
3168
3169 return gnm_expr_equal (te1->expr, te2->expr);
3170 }
3171
3172 /*
3173 * gnm_expr_top_relocate:
3174 * @texpr: #GnmExprTop to fixup
3175 * @rinfo: #GnmExprRelocateInfo details of relocation
3176 * @ignore_rel: Do not adjust relative refs (for internal use when
3177 * relocating named expressions. Most callers will want FALSE.
3178 *
3179 * GNM_EXPR_RELOCATE_INVALIDATE_SHEET:
3180 * Convert any references to sheets marked being_invalidated into #REF!
3181 * GNM_EXPR_RELOCATE_MOVE_RANGE,
3182 * Find any references to the specified area and adjust them by the
3183 * supplied deltas. Check for out of bounds conditions. Return %NULL if
3184 * no change is required.
3185 * If the expression is within the range to be moved, its relative
3186 * references to cells outside the range are adjusted to reference the
3187 * same cell after the move.
3188 * GNM_EXPR_RELOCATE_COLS
3189 * GNM_EXPR_RELOCATE_ROWS
3190 *
3191 */
3192 GnmExprTop const *
gnm_expr_top_relocate(GnmExprTop const * texpr,GnmExprRelocateInfo const * rinfo,gboolean ignore_rel)3193 gnm_expr_top_relocate (GnmExprTop const *texpr,
3194 GnmExprRelocateInfo const *rinfo,
3195 gboolean ignore_rel)
3196 {
3197 RelocInfoInternal rinfo_tmp;
3198
3199 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3200 g_return_val_if_fail (NULL != rinfo, NULL);
3201
3202 rinfo_tmp.details = rinfo;
3203 rinfo_tmp.check_rels = !ignore_rel;
3204 if (rinfo->reloc_type != GNM_EXPR_RELOCATE_INVALIDATE_SHEET)
3205 rinfo_tmp.from_inside = (rinfo->origin_sheet == rinfo->pos.sheet) &&
3206 range_contains (&rinfo->origin, rinfo->pos.eval.col, rinfo->pos.eval.row);
3207
3208 return gnm_expr_top_new (gnm_expr_relocate (texpr->expr, &rinfo_tmp));
3209 }
3210
3211 /*
3212 * Convenience function to change an expression from one sheet to another.
3213 */
3214 GnmExprTop const *
gnm_expr_top_relocate_sheet(GnmExprTop const * texpr,Sheet const * src,Sheet const * dst)3215 gnm_expr_top_relocate_sheet (GnmExprTop const *texpr,
3216 Sheet const *src,
3217 Sheet const *dst)
3218 {
3219 GnmExprRelocateInfo rinfo;
3220 GnmExprTop const *res;
3221
3222 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3223 g_return_val_if_fail (IS_SHEET (src), NULL);
3224 g_return_val_if_fail (IS_SHEET (dst), NULL);
3225
3226 rinfo.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE;
3227 rinfo.origin_sheet = (Sheet *)src;
3228 rinfo.target_sheet = (Sheet *)dst;
3229 rinfo.col_offset = rinfo.row_offset = 0;
3230 range_init_full_sheet (&rinfo.origin, src);
3231 /* Not sure what sheet to use, but it doesn't seem to matter. */
3232 parse_pos_init_sheet (&rinfo.pos, rinfo.target_sheet);
3233
3234 res = gnm_expr_top_relocate (texpr, &rinfo, FALSE);
3235 if (!res) {
3236 if (gnm_expr_top_is_array_corner (texpr))
3237 res = gnm_expr_top_new (gnm_expr_copy (texpr->expr));
3238 else
3239 gnm_expr_top_ref ((res = texpr));
3240 }
3241
3242 return res;
3243 }
3244
3245 gboolean
gnm_expr_top_contains_subtotal(GnmExprTop const * texpr)3246 gnm_expr_top_contains_subtotal (GnmExprTop const *texpr)
3247 {
3248 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3249
3250 return gnm_expr_contains_subtotal (texpr->expr);
3251 }
3252
3253 static GnmExpr const *
cb_is_volatile(GnmExpr const * expr,GnmExprWalk * data)3254 cb_is_volatile (GnmExpr const *expr, GnmExprWalk *data)
3255 {
3256 gboolean *res = data->user;
3257 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL &&
3258 (gnm_func_get_flags (expr->func.func) & GNM_FUNC_VOLATILE)) {
3259 *res = TRUE;
3260 data->stop = TRUE;
3261 }
3262 return NULL;
3263 }
3264
3265 gboolean
gnm_expr_top_is_volatile(GnmExprTop const * texpr)3266 gnm_expr_top_is_volatile (GnmExprTop const *texpr)
3267 {
3268 gboolean res = FALSE;
3269
3270 /*
3271 * An expression is volatile if it contains a call to a volatile
3272 * function, even in cases like IF(TRUE,12,RAND()) where the
3273 * volatile function won't even be reached.
3274 */
3275
3276 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3277 gnm_expr_walk (texpr->expr, cb_is_volatile, &res);
3278 return res;
3279 }
3280
3281
3282 static GnmValue *
gnm_expr_top_eval_array_corner(GnmExprTop const * texpr,GnmEvalPos const * pos,GnmExprEvalFlags flags)3283 gnm_expr_top_eval_array_corner (GnmExprTop const *texpr,
3284 GnmEvalPos const *pos,
3285 GnmExprEvalFlags flags)
3286 {
3287 GnmExpr const *expr = texpr->expr;
3288 GnmEvalPos pos2;
3289 GnmValue *a;
3290
3291 pos2 = *pos;
3292 pos2.array_texpr = texpr;
3293 a = gnm_expr_eval (expr->array_corner.expr, &pos2,
3294 flags | GNM_EXPR_EVAL_PERMIT_NON_SCALAR);
3295
3296 value_release (expr->array_corner.value);
3297
3298 /* Store real result (cast away const)*/
3299 ((GnmExpr*)expr)->array_corner.value = a;
3300
3301 if (a != NULL &&
3302 (VALUE_IS_CELLRANGE (a) || VALUE_IS_ARRAY (a))) {
3303 if (value_area_get_width (a, pos) <= 0 ||
3304 value_area_get_height (a, pos) <= 0)
3305 return value_new_error_NA (pos);
3306 a = (GnmValue *)value_area_get_x_y (a, 0, 0, pos);
3307 }
3308 return handle_empty ((a != NULL) ? value_dup (a) : NULL, flags);
3309 }
3310
3311 static GnmValue *
gnm_expr_top_eval_array_elem(GnmExprTop const * texpr,GnmEvalPos const * pos,GnmExprEvalFlags flags)3312 gnm_expr_top_eval_array_elem (GnmExprTop const *texpr,
3313 GnmEvalPos const *pos,
3314 GnmExprEvalFlags flags)
3315 {
3316 GnmExpr const *expr = texpr->expr;
3317 /* The upper left corner manages the recalc of the expr */
3318 GnmCell *corner = array_elem_get_corner (&expr->array_elem,
3319 pos->sheet, &pos->eval);
3320 GnmValue *a;
3321
3322 if (!corner ||
3323 !gnm_expr_top_is_array_corner (corner->base.texpr)) {
3324 g_warning ("Funky array setup.");
3325 return handle_empty (NULL, flags);
3326 }
3327
3328 gnm_cell_eval (corner);
3329 a = gnm_expr_top_get_array_value (corner->base.texpr);
3330 if (a == NULL)
3331 return handle_empty (NULL, flags);
3332
3333 if ((VALUE_IS_CELLRANGE (a) || VALUE_IS_ARRAY (a))) {
3334 int const num_x = value_area_get_width (a, pos);
3335 int const num_y = value_area_get_height (a, pos);
3336 int x = expr->array_elem.x;
3337 int y = expr->array_elem.y;
3338
3339 /* Evaluate relative to the upper left corner */
3340 GnmEvalPos tmp_ep = *pos;
3341 tmp_ep.eval.col -= x;
3342 tmp_ep.eval.row -= y;
3343
3344 /* If the src array is 1 element wide or tall we wrap */
3345 if (x >= 1 && num_x == 1)
3346 x = 0;
3347 if (y >= 1 && num_y == 1)
3348 y = 0;
3349 if (x >= num_x || y >= num_y)
3350 return value_new_error_NA (pos);
3351
3352 a = (GnmValue *)value_area_get_x_y (a, x, y, &tmp_ep);
3353 }
3354
3355 return handle_empty ((a != NULL) ? value_dup (a) : NULL, flags);
3356 }
3357
3358 GnmValue *
gnm_expr_top_eval(GnmExprTop const * texpr,GnmEvalPos const * pos,GnmExprEvalFlags flags)3359 gnm_expr_top_eval (GnmExprTop const *texpr,
3360 GnmEvalPos const *pos,
3361 GnmExprEvalFlags flags)
3362 {
3363 GnmValue *res;
3364
3365 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3366
3367 gnm_app_recalc_start ();
3368
3369 if (gnm_expr_top_is_array_corner (texpr))
3370 res = gnm_expr_top_eval_array_corner (texpr, pos, flags);
3371 else if (gnm_expr_top_is_array_elem (texpr, NULL, NULL))
3372 res = gnm_expr_top_eval_array_elem (texpr, pos, flags);
3373 else
3374 res = gnm_expr_eval (texpr->expr, pos, flags);
3375 gnm_app_recalc_finish ();
3376
3377 return res;
3378 }
3379
3380 GnmValue *
gnm_expr_top_eval_fake_array(GnmExprTop const * texpr,GnmEvalPos const * pos,GnmExprEvalFlags flags)3381 gnm_expr_top_eval_fake_array (GnmExprTop const *texpr,
3382 GnmEvalPos const *pos,
3383 GnmExprEvalFlags flags)
3384 {
3385 if (eval_pos_is_array_context (pos))
3386 return gnm_expr_top_eval (texpr, pos, flags);
3387 else {
3388 GnmEvalPos pos2 = *pos;
3389 GnmExprTop const *fake = gnm_expr_top_new_array_corner (1, 1, NULL);
3390 GnmValue *res;
3391 ((GnmExpr *)(fake->expr))->array_corner.expr = texpr->expr; // Patch in our expr
3392 pos2.array_texpr = fake;
3393 res = gnm_expr_eval (texpr->expr, &pos2, flags);
3394 ((GnmExpr *)(fake->expr))->array_corner.expr = NULL;
3395 gnm_expr_top_unref (fake);
3396 return res;
3397 }
3398 }
3399
3400
3401 static GSList *
gnm_insert_unique(GSList * list,gpointer data)3402 gnm_insert_unique (GSList *list, gpointer data)
3403 {
3404 if (g_slist_find (list, data) == NULL)
3405 return g_slist_prepend (list, data);
3406 return list;
3407 }
3408
3409 static GnmExpr const *
cb_referenced_sheets(GnmExpr const * expr,GnmExprWalk * data)3410 cb_referenced_sheets (GnmExpr const *expr, GnmExprWalk *data)
3411 {
3412 GSList **psheets = data->user;
3413
3414 switch (GNM_EXPR_GET_OPER (expr)) {
3415 case GNM_EXPR_OP_CELLREF:
3416 *psheets = gnm_insert_unique (*psheets, expr->cellref.ref.sheet);
3417 break;
3418
3419 case GNM_EXPR_OP_CONSTANT: {
3420 GnmValue const *v = expr->constant.value;
3421 if (!VALUE_IS_CELLRANGE (v))
3422 break;
3423 *psheets = gnm_insert_unique (*psheets, v->v_range.cell.a.sheet);
3424 /* A NULL b sheet means a's sheet. Do not insert that. */
3425 if (v->v_range.cell.b.sheet)
3426 *psheets = gnm_insert_unique (*psheets, v->v_range.cell.b.sheet);
3427 break;
3428 }
3429
3430 default:
3431 break;
3432 }
3433
3434 return NULL;
3435 }
3436
3437 /**
3438 * gnm_expr_top_referenced_sheets:
3439 * @texpr:
3440 *
3441 * Generates a list of the sheets referenced by the supplied expression.
3442 * Caller must free the list. Note, that NULL may occur in the result
3443 * if the expression has a range or cellref without a sheet.
3444 * Returns: (element-type Sheet) (transfer container): the created list.
3445 */
3446 GSList *
gnm_expr_top_referenced_sheets(GnmExprTop const * texpr)3447 gnm_expr_top_referenced_sheets (GnmExprTop const *texpr)
3448 {
3449 GSList *res = NULL;
3450
3451 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3452 gnm_expr_walk (texpr->expr, cb_referenced_sheets, &res);
3453 return res;
3454 }
3455
3456 gboolean
gnm_expr_top_is_err(GnmExprTop const * texpr,GnmStdError err)3457 gnm_expr_top_is_err (GnmExprTop const *texpr, GnmStdError err)
3458 {
3459 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3460 return gnm_expr_is_err (texpr->expr, err);
3461 }
3462
3463 /**
3464 * gnm_expr_top_get_constant:
3465 * @texpr:
3466 *
3467 * If this expression consists of just a constant, return it.
3468 */
3469 GnmValue const *
gnm_expr_top_get_constant(GnmExprTop const * texpr)3470 gnm_expr_top_get_constant (GnmExprTop const *texpr)
3471 {
3472 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3473
3474 return gnm_expr_get_constant (texpr->expr);
3475 }
3476
3477 GnmCellRef const *
gnm_expr_top_get_cellref(GnmExprTop const * texpr)3478 gnm_expr_top_get_cellref (GnmExprTop const *texpr)
3479 {
3480 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3481 return gnm_expr_get_cellref (texpr->expr);
3482 }
3483
3484 static GnmExpr const *
cb_first_funcall(GnmExpr const * expr,GnmExprWalk * data)3485 cb_first_funcall (GnmExpr const *expr, GnmExprWalk *data)
3486 {
3487 GnmExprConstPtr *user = data->user;
3488 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL) {
3489 *user = expr;
3490 data->stop = TRUE;
3491 }
3492 return NULL;
3493 }
3494
3495 /**
3496 * gnm_expr_top_first_funcall:
3497 * @texpr:
3498 *
3499 */
3500 GnmExpr const *
gnm_expr_top_first_funcall(GnmExprTop const * texpr)3501 gnm_expr_top_first_funcall (GnmExprTop const *texpr)
3502 {
3503 GnmExpr const *res = NULL;
3504
3505 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3506 gnm_expr_walk (texpr->expr, cb_first_funcall, &res);
3507 return res;
3508 }
3509
3510 struct cb_get_boundingbox {
3511 Sheet const *sheet;
3512 GnmRange *bound;
3513 };
3514
3515 static GnmExpr const *
cb_get_boundingbox(GnmExpr const * expr,GnmExprWalk * data)3516 cb_get_boundingbox (GnmExpr const *expr, GnmExprWalk *data)
3517 {
3518 struct cb_get_boundingbox *args = data->user;
3519
3520 switch (GNM_EXPR_GET_OPER (expr)) {
3521 case GNM_EXPR_OP_CELLREF:
3522 cellref_boundingbox (&expr->cellref.ref, args->sheet, args->bound);
3523 break;
3524
3525 case GNM_EXPR_OP_CONSTANT: {
3526 GnmValue const *v = expr->constant.value;
3527
3528 if (VALUE_IS_CELLRANGE (v)) {
3529 cellref_boundingbox (&v->v_range.cell.a, args->sheet, args->bound);
3530 cellref_boundingbox (&v->v_range.cell.b, args->sheet, args->bound);
3531 }
3532 break;
3533 }
3534
3535 default:
3536 break;
3537 }
3538
3539 return NULL;
3540 }
3541
3542 /**
3543 * gnm_expr_top_get_boundingbox:
3544 *
3545 * Returns the range of cells in which the expression can be used without going
3546 * out of bounds.
3547 **/
3548 void
gnm_expr_top_get_boundingbox(GnmExprTop const * texpr,Sheet const * sheet,GnmRange * bound)3549 gnm_expr_top_get_boundingbox (GnmExprTop const *texpr, Sheet const *sheet,
3550 GnmRange *bound)
3551 {
3552 struct cb_get_boundingbox args;
3553
3554 g_return_if_fail (GNM_IS_EXPR_TOP (texpr));
3555
3556 range_init_full_sheet (bound, sheet);
3557
3558 args.sheet = sheet;
3559 args.bound = bound;
3560 gnm_expr_walk (texpr->expr, cb_get_boundingbox, &args);
3561 }
3562
3563 gboolean
gnm_expr_top_is_rangeref(GnmExprTop const * texpr)3564 gnm_expr_top_is_rangeref (GnmExprTop const *texpr)
3565 {
3566 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3567
3568 return gnm_expr_is_rangeref (texpr->expr);
3569 }
3570
3571 gboolean
gnm_expr_top_is_array_corner(GnmExprTop const * texpr)3572 gnm_expr_top_is_array_corner (GnmExprTop const *texpr)
3573 {
3574 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3575 return GNM_EXPR_GET_OPER (texpr->expr) == GNM_EXPR_OP_ARRAY_CORNER;
3576 }
3577
3578 void
gnm_expr_top_get_array_size(GnmExprTop const * texpr,int * cols,int * rows)3579 gnm_expr_top_get_array_size (GnmExprTop const *texpr, int *cols, int *rows)
3580 {
3581 g_return_if_fail (GNM_IS_EXPR_TOP (texpr));
3582 g_return_if_fail (GNM_EXPR_GET_OPER (texpr->expr) == GNM_EXPR_OP_ARRAY_CORNER);
3583
3584 if (cols)
3585 *cols = texpr->expr->array_corner.cols;
3586 if (rows)
3587 *rows = texpr->expr->array_corner.rows;
3588 }
3589
3590 GnmValue *
gnm_expr_top_get_array_value(GnmExprTop const * texpr)3591 gnm_expr_top_get_array_value (GnmExprTop const *texpr)
3592 {
3593 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3594 g_return_val_if_fail (GNM_EXPR_GET_OPER (texpr->expr) == GNM_EXPR_OP_ARRAY_CORNER, NULL);
3595 return texpr->expr->array_corner.value;
3596 }
3597
3598 GnmExpr const *
gnm_expr_top_get_array_expr(GnmExprTop const * texpr)3599 gnm_expr_top_get_array_expr (GnmExprTop const *texpr)
3600 {
3601 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3602 g_return_val_if_fail (GNM_EXPR_GET_OPER (texpr->expr) == GNM_EXPR_OP_ARRAY_CORNER, NULL);
3603 return texpr->expr->array_corner.expr;
3604 }
3605
3606 gboolean
gnm_expr_top_is_array_elem(GnmExprTop const * texpr,int * x,int * y)3607 gnm_expr_top_is_array_elem (GnmExprTop const *texpr, int *x, int *y)
3608 {
3609 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3610
3611 if (GNM_EXPR_GET_OPER (texpr->expr) != GNM_EXPR_OP_ARRAY_ELEM)
3612 return FALSE;
3613
3614 if (x) *x = texpr->expr->array_elem.x;
3615 if (y) *y = texpr->expr->array_elem.y;
3616 return TRUE;
3617 }
3618
3619 gboolean
gnm_expr_top_is_array(GnmExprTop const * texpr)3620 gnm_expr_top_is_array (GnmExprTop const *texpr)
3621 {
3622 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3623 return gnm_expr_is_array (texpr->expr);
3624 }
3625
3626 GnmExprTop const *
gnm_expr_top_transpose(GnmExprTop const * texpr)3627 gnm_expr_top_transpose (GnmExprTop const *texpr)
3628 {
3629 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3630 switch (GNM_EXPR_GET_OPER (texpr->expr)) {
3631 case GNM_EXPR_OP_ARRAY_CORNER:
3632 /* Transpose size */
3633 return gnm_expr_top_new_array_corner
3634 (texpr->expr->array_corner.rows,
3635 texpr->expr->array_corner.cols,
3636 gnm_expr_copy (texpr->expr));
3637 case GNM_EXPR_OP_ARRAY_ELEM:
3638 /* Transpose coordinates */
3639 return gnm_expr_top_new_array_elem
3640 (texpr->expr->array_elem.y,
3641 texpr->expr->array_elem.x);
3642 default:
3643 return NULL;
3644 }
3645 }
3646
3647 /****************************************************************************/
3648
3649 #if USE_EXPR_POOLS
3650 typedef union {
3651 guint32 oper_and_refcount;
3652 GnmExprConstant constant;
3653 GnmExprFunction func;
3654 GnmExprUnary unary;
3655 GnmExprBinary binary;
3656 GnmExprArrayElem array_elem;
3657 GnmExprSet set;
3658 } GnmExprSmall;
3659 typedef union {
3660 guint32 oper_and_refcount;
3661 GnmExprName name;
3662 GnmExprCellRef cellref;
3663 GnmExprArrayCorner array_corner;
3664 } GnmExprBig;
3665 #endif
3666
3667 /**
3668 * gnm_expr_init_: (skip)
3669 */
3670 void
gnm_expr_init_(void)3671 gnm_expr_init_ (void)
3672 {
3673 #if 0
3674 GnmExpr e;
3675
3676 #if USE_EXPR_POOLS
3677 /* 12 is an excellent size for a pool. */
3678 g_print ("sizeof(GnmExprSmall) = %d\n", (int)sizeof (GnmExprSmall));
3679 g_print ("sizeof(GnmExprBig) = %d\n", (int)sizeof (GnmExprBig));
3680 #endif
3681 g_print ("sizeof(e.func) = %d\n", (int)sizeof (e.func));
3682 g_print ("sizeof(e.unary) = %d\n", (int)sizeof (e.unary));
3683 g_print ("sizeof(e.binary) = %d\n", (int)sizeof (e.binary));
3684 g_print ("sizeof(e.name) = %d\n", (int)sizeof (e.name));
3685 g_print ("sizeof(e.cellref) = %d\n", (int)sizeof (e.cellref));
3686 g_print ("sizeof(e.array_corner) = %d\n", (int)sizeof (e.array_corner));
3687 g_print ("sizeof(e.array_elem) = %d\n", (int)sizeof (e.array_elem));
3688 g_print ("sizeof(e.set) = %d\n", (int)sizeof (e.set));
3689 #endif
3690 #if USE_EXPR_POOLS
3691 expression_pool_small =
3692 go_mem_chunk_new ("expression pool for small nodes",
3693 sizeof (GnmExprSmall),
3694 16 * 1024 - 128);
3695 expression_pool_big =
3696 go_mem_chunk_new ("expression pool for big nodes",
3697 sizeof (GnmExprBig),
3698 16 * 1024 - 128);
3699 #endif
3700 }
3701
3702 #if USE_EXPR_POOLS
3703 static void
cb_expression_pool_leak(gpointer data,G_GNUC_UNUSED gpointer user)3704 cb_expression_pool_leak (gpointer data, G_GNUC_UNUSED gpointer user)
3705 {
3706 GnmExpr const *expr = data;
3707 GnmParsePos pp;
3708 char *s;
3709
3710 pp.eval.col = 0;
3711 pp.eval.row = 0;
3712 pp.sheet = NULL;
3713 pp.wb = NULL;
3714 s = gnm_expr_as_string (expr, &pp, NULL);
3715 g_printerr ("Leaking expression at %p: %s.\n", (void *)expr, s);
3716 g_free (s);
3717 }
3718 #endif
3719
3720 /**
3721 * gnm_expr_shutdown_: (skip)
3722 */
3723 void
gnm_expr_shutdown_(void)3724 gnm_expr_shutdown_ (void)
3725 {
3726 #if USE_EXPR_POOLS
3727 go_mem_chunk_foreach_leak (expression_pool_small, cb_expression_pool_leak, NULL);
3728 go_mem_chunk_destroy (expression_pool_small, FALSE);
3729 expression_pool_small = NULL;
3730
3731 go_mem_chunk_foreach_leak (expression_pool_big, cb_expression_pool_leak, NULL);
3732 go_mem_chunk_destroy (expression_pool_big, FALSE);
3733 expression_pool_big = NULL;
3734 #endif
3735 }
3736
3737 /****************************************************************************/
3738