Update Spanish translation
[gnumeric.git] / src / expr.c
blob47abb36317e028e679073960178268331c9f4a08
1 /*
2 * expr.c : Expression evaluation in Gnumeric
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)
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.
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.
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
23 #include <gnumeric-config.h>
24 #include <glib/gi18n-lib.h>
25 #include <gnumeric.h>
26 #include <expr.h>
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>
44 #include <goffice/goffice.h>
45 #include <math.h>
46 #include <string.h>
47 #include <stdlib.h>
50 * Using pools here probably does not save anything, but it's a darn
51 * good debugging tool.
53 #ifndef USE_EXPR_POOLS
54 #define USE_EXPR_POOLS 1
55 #endif
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
67 /***************************************************************************/
69 /**
70 * gnm_expr_new_constant:
71 * @v: (transfer full): #GnmValue
73 * Returns: (transfer full): constant expression.
74 **/
75 GnmExpr const *
76 gnm_expr_new_constant (GnmValue *v)
78 GnmExprConstant *ans;
80 g_return_val_if_fail (v != NULL, NULL);
82 ans = CHUNK_ALLOC (GnmExprConstant, expression_pool_small);
83 if (!ans)
84 return NULL;
85 gnm_expr_constant_init (ans, v);
87 return (GnmExpr *)ans;
90 /***************************************************************************/
92 /**
93 * gnm_expr_new_funcallv: (skip)
94 * @func: #GnmFunc
95 * @argc: argument count
96 * @argv: (array length=argc): transfers everything
98 * Returns: (transfer full): function call expression.
100 static GnmExpr const *
101 gnm_expr_new_funcallv (GnmFunc *func, int argc, GnmExprConstPtr *argv)
103 GnmExprFunction *ans;
104 g_return_val_if_fail (func, NULL);
106 ans = CHUNK_ALLOC (GnmExprFunction, expression_pool_small);
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;
114 return (GnmExpr *)ans;
118 * gnm_expr_new_funcall:
119 * @func: #GnmFunc
120 * @args: (transfer full): argument list
122 * Returns: (transfer full): function call expression.
124 GnmExpr const *
125 gnm_expr_new_funcall (GnmFunc *func, GnmExprList *args)
127 int argc = gnm_expr_list_length (args);
128 GnmExprConstPtr *argv = NULL;
130 if (args) {
131 GnmExprList *args0 = args;
132 int i = 0;
134 argv = g_new (GnmExprConstPtr, argc);
135 for (; args; args = args->next)
136 argv[i++] = args->data;
137 gnm_expr_list_free (args0);
140 return gnm_expr_new_funcallv (func, argc, argv);
144 * gnm_expr_new_funcall1:
145 * @func: #GnmFunc
146 * @arg0: (transfer full): argument
148 * Returns: (transfer full): function call expression.
150 GnmExpr const *
151 gnm_expr_new_funcall1 (GnmFunc *func,
152 GnmExpr const *arg0)
154 GnmExprConstPtr *argv = g_new (GnmExprConstPtr, 1);
155 argv[0] = arg0;
156 return gnm_expr_new_funcallv (func, 1, argv);
160 * gnm_expr_new_funcall2:
161 * @func: #GnmFunc
162 * @arg0: (transfer full): argument
163 * @arg1: (transfer full): argument
165 * Returns: (transfer full): function call expression.
167 GnmExpr const *
168 gnm_expr_new_funcall2 (GnmFunc *func,
169 GnmExpr const *arg0,
170 GnmExpr const *arg1)
172 GnmExprConstPtr *argv = g_new (GnmExprConstPtr, 2);
173 argv[0] = arg0;
174 argv[1] = arg1;
175 return gnm_expr_new_funcallv (func, 2, argv);
179 * gnm_expr_new_funcall3:
180 * @func: #GnmFunc
181 * @arg0: (transfer full): argument
182 * @arg1: (transfer full): argument
183 * @arg2: (transfer full): argument
185 * Returns: (transfer full): function call expression.
187 GnmExpr const *
188 gnm_expr_new_funcall3 (GnmFunc *func,
189 GnmExpr const *arg0,
190 GnmExpr const *arg1,
191 GnmExpr const *arg2)
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);
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
208 * Returns: (transfer full): function call expression.
210 GnmExpr const *
211 gnm_expr_new_funcall4 (GnmFunc *func,
212 GnmExpr const *arg0,
213 GnmExpr const *arg1,
214 GnmExpr const *arg2,
215 GnmExpr const *arg3)
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);
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
234 * Returns: (transfer full): function call expression.
236 GnmExpr const *
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)
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);
254 /***************************************************************************/
257 * gnm_expr_new_unary:
258 * @op: Unary operator
259 * @e: (transfer full): #GnmExpr
261 * Returns: (transfer full): Unary expresssion
263 GnmExpr const *
264 gnm_expr_new_unary (GnmExprOp op, GnmExpr const *e)
266 GnmExprUnary *ans;
268 ans = CHUNK_ALLOC (GnmExprUnary, expression_pool_small);
269 if (!ans)
270 return NULL;
272 ans->oper = op;
273 ans->value = e;
275 return (GnmExpr *)ans;
278 /***************************************************************************/
281 * gnm_expr_new_binary:
282 * @l: (transfer full): left operand.
283 * @op: Unary operator
284 * @r: (transfer full): right operand.
286 * Returns: (transfer full): Binary expresssion
288 GnmExpr const *
289 gnm_expr_new_binary (GnmExpr const *l, GnmExprOp op, GnmExpr const *r)
291 GnmExprBinary *ans;
293 ans = CHUNK_ALLOC (GnmExprBinary, expression_pool_small);
294 if (!ans)
295 return NULL;
297 ans->oper = op;
298 ans->value_a = l;
299 ans->value_b = r;
301 return (GnmExpr *)ans;
304 /***************************************************************************/
306 GnmExpr const *
307 gnm_expr_new_name (GnmNamedExpr *name,
308 Sheet *optional_scope, Workbook *optional_wb_scope)
310 GnmExprName *ans;
312 ans = CHUNK_ALLOC (GnmExprName, expression_pool_big);
313 if (!ans)
314 return NULL;
316 ans->oper = GNM_EXPR_OP_NAME;
317 ans->name = name;
318 expr_name_ref (name);
320 ans->optional_scope = optional_scope;
321 ans->optional_wb_scope = optional_wb_scope;
323 return (GnmExpr *)ans;
326 /***************************************************************************/
329 * gnm_expr_new_cellref:
330 * @cr: (transfer none): cell reference
332 * Returns: (transfer full): expression referencing @cr.
334 GnmExpr const *
335 gnm_expr_new_cellref (GnmCellRef const *cr)
337 GnmExprCellRef *ans;
339 ans = CHUNK_ALLOC (GnmExprCellRef, expression_pool_big);
340 if (!ans)
341 return NULL;
343 ans->oper = GNM_EXPR_OP_CELLREF;
344 ans->ref = *cr;
346 return (GnmExpr *)ans;
349 /***************************************************************************/
352 * gnm_expr_is_array:
353 * @expr: #GnmExpr
355 * Returns: %TRUE if @expr is an array expression, either a corner or a
356 * non-corner element.
358 static gboolean
359 gnm_expr_is_array (GnmExpr const *expr)
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);
367 * gnm_expr_new_array_corner:
368 * @cols: Number of columns
369 * @rows: Number of rows
370 * @expr: (transfer full) (nullable): #GnmExpr
372 * Returns: (transfer full): An array corner expression
374 static GnmExpr const *
375 gnm_expr_new_array_corner(int cols, int rows, GnmExpr const *expr)
377 GnmExprArrayCorner *ans;
379 g_return_val_if_fail (!gnm_expr_is_array (expr), NULL);
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;
391 * gnm_expr_new_array_elem:
392 * @x: Column number relative to corner
393 * @y: Row number relative to corner
395 * Returns: (transfer full): An array non-corner expression
397 static GnmExpr const *
398 gnm_expr_new_array_elem (int x, int y)
400 GnmExprArrayElem *ans;
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;
409 /***************************************************************************/
411 static GnmExpr const *
412 gnm_expr_new_setv (int argc, GnmExprConstPtr *argv)
414 GnmExprSet *ans = CHUNK_ALLOC (GnmExprSet, expression_pool_small);
416 ans->oper = GNM_EXPR_OP_SET;
417 ans->argc = argc;
418 ans->argv = argv;
420 return (GnmExpr *)ans;
424 * gnm_expr_new_set:
425 * @args: (transfer full): element list
427 * Returns: (transfer full): set expression.
429 GnmExpr const *
430 gnm_expr_new_set (GnmExprList *set)
432 int i, argc;
433 GnmExprConstPtr *argv;
434 GnmExprList *set0 = set;
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);
442 return gnm_expr_new_setv (argc, argv);
445 /***************************************************************************/
448 * gnm_expr_new_range_ctor:
449 * @l: (transfer full): start range
450 * @r: (transfer full): end range
452 * This function builds a range constructor or something simpler,
453 * but equivalent, if the arguments allow it.
455 * Returns: (transfer full): And expression referencing @l to @r.
457 GnmExpr const *
458 gnm_expr_new_range_ctor (GnmExpr const *l, GnmExpr const *r)
460 GnmValue *v;
462 g_return_val_if_fail (l != NULL, NULL);
463 g_return_val_if_fail (r != NULL, NULL);
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;
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);
475 fallback:
476 return gnm_expr_new_binary (l, GNM_EXPR_OP_RANGE_CTOR, r);
479 /***************************************************************************/
482 * gnm_expr_copy:
483 * @expr: (transfer none): #GnmExpr
485 * Returns: (transfer full): A deep copy of @expr.
487 GnmExpr const *
488 gnm_expr_copy (GnmExpr const *expr)
490 g_return_val_if_fail (expr != NULL, NULL);
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));
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));
506 case GNM_EXPR_OP_FUNCALL: {
507 GnmExprConstPtr *argv =
508 g_new (GnmExprConstPtr, expr->func.argc);
509 int i;
511 for (i = 0; i < expr->func.argc; i++)
512 argv[i] = gnm_expr_copy (expr->func.argv[i]);
514 return gnm_expr_new_funcallv
515 (expr->func.func,
516 expr->func.argc,
517 argv);
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);
526 case GNM_EXPR_OP_CONSTANT:
527 return gnm_expr_new_constant
528 (value_dup (expr->constant.value));
530 case GNM_EXPR_OP_CELLREF:
531 return gnm_expr_new_cellref (&expr->cellref.ref);
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));
538 case GNM_EXPR_OP_ARRAY_ELEM:
539 return gnm_expr_new_array_elem
540 (expr->array_elem.x,
541 expr->array_elem.y);
543 case GNM_EXPR_OP_SET: {
544 GnmExprConstPtr *argv =
545 g_new (GnmExprConstPtr, expr->set.argc);
546 int i;
548 for (i = 0; i < expr->set.argc; i++)
549 argv[i] = gnm_expr_copy (expr->set.argv[i]);
551 return gnm_expr_new_setv
552 (expr->set.argc,
553 argv);
556 #ifndef DEBUG_SWITCH_ENUM
557 default:
558 g_assert_not_reached ();
559 break;
560 #endif
565 * gnm_expr_free:
566 * @expr: (transfer full): #GnmExpr
568 * Deletes @expr with all its subexpressions.
570 void
571 gnm_expr_free (GnmExpr const *expr)
573 g_return_if_fail (expr != NULL);
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;
584 case GNM_EXPR_OP_FUNCALL: {
585 int i;
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;
595 case GNM_EXPR_OP_NAME:
596 expr_name_unref (expr->name.name);
597 CHUNK_FREE (expression_pool_big, (gpointer)expr);
598 break;
600 case GNM_EXPR_OP_CONSTANT:
601 value_release ((GnmValue *)expr->constant.value);
602 CHUNK_FREE (expression_pool_small, (gpointer)expr);
603 break;
605 case GNM_EXPR_OP_CELLREF:
606 CHUNK_FREE (expression_pool_big, (gpointer)expr);
607 break;
609 case GNM_EXPR_OP_ANY_UNARY:
610 gnm_expr_free (expr->unary.value);
611 CHUNK_FREE (expression_pool_small, (gpointer)expr);
612 break;
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;
623 case GNM_EXPR_OP_ARRAY_ELEM:
624 CHUNK_FREE (expression_pool_small, (gpointer)expr);
625 break;
627 case GNM_EXPR_OP_SET: {
628 int i;
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;
637 #ifndef DEBUG_SWITCH_ENUM
638 default:
639 g_assert_not_reached ();
640 break;
641 #endif
645 GType
646 gnm_expr_get_type (void)
648 static GType t = 0;
650 if (t == 0) {
651 t = g_boxed_type_register_static ("GnmExpr",
652 (GBoxedCopyFunc)gnm_expr_copy,
653 (GBoxedFreeFunc)gnm_expr_free);
655 return t;
658 GType
659 gnm_expr_array_corner_get_type (void)
661 static GType t = 0;
663 if (t == 0) {
664 t = g_boxed_type_register_static ("GnmExprArrayCorner",
665 (GBoxedCopyFunc)gnm_expr_copy,
666 (GBoxedFreeFunc)gnm_expr_free);
668 return t;
672 * gnm_expr_equal:
673 * @a: first #GnmExpr
674 * @b: first #GnmExpr
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 insufficeient.
681 gboolean
682 gnm_expr_equal (GnmExpr const *a, GnmExpr const *b)
684 if (a == b)
685 return TRUE;
687 g_return_val_if_fail (a != NULL, FALSE);
688 g_return_val_if_fail (b != NULL, FALSE);
690 if (GNM_EXPR_GET_OPER (a) != GNM_EXPR_GET_OPER (b))
691 return FALSE;
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);
700 case GNM_EXPR_OP_ANY_UNARY:
701 return gnm_expr_equal (a->unary.value, b->unary.value);
703 case GNM_EXPR_OP_FUNCALL: {
704 int i;
706 if (a->func.func != b->func.func ||
707 a->func.argc != b->func.argc)
708 return FALSE;
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;
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;
721 case GNM_EXPR_OP_CELLREF:
722 return gnm_cellref_equal (&a->cellref.ref, &b->cellref.ref);
724 case GNM_EXPR_OP_CONSTANT:
725 return value_equal (a->constant.value, b->constant.value);
727 case GNM_EXPR_OP_ARRAY_CORNER: {
728 GnmExprArrayCorner const *aa = &a->array_corner;
729 GnmExprArrayCorner const *ab = &b->array_corner;
731 return aa->cols == ab->cols &&
732 aa->rows == ab->rows &&
733 gnm_expr_equal (aa->expr, ab->expr);
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;
741 case GNM_EXPR_OP_SET: {
742 int i;
744 if (a->set.argc != b->set.argc)
745 return FALSE;
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;
754 return FALSE;
757 static GnmCell *
758 array_elem_get_corner (GnmExprArrayElem const *elem,
759 Sheet const *sheet, GnmCellPos const *pos)
761 GnmCell *corner = sheet_cell_get (sheet,
762 pos->col - elem->x, pos->row - elem->y);
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);
770 return corner;
773 static gboolean
774 gnm_expr_extract_ref (GnmRangeRef *res, GnmExpr const *expr,
775 GnmEvalPos const *pos, GnmExprEvalFlags flags)
777 switch (GNM_EXPR_GET_OPER (expr)) {
778 case GNM_EXPR_OP_FUNCALL : {
779 gboolean failed = TRUE;
780 GnmValue *v;
781 GnmFuncEvalInfo ei;
783 ei.pos = pos;
784 ei.func_call = &expr->func;
785 ei.flags = flags;
786 v = function_call_with_exprs (&ei);
788 if (v != NULL) {
789 if (VALUE_IS_CELLRANGE (v)) {
790 *res = v->v_range.cell;
791 failed = FALSE;
793 value_release (v);
795 return failed;
798 case GNM_EXPR_OP_CELLREF:
799 res->a = expr->cellref.ref;
800 res->b = expr->cellref.ref;
801 return FALSE;
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;
809 return TRUE;
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;
820 return TRUE;
823 static inline GnmValue *
824 handle_empty (GnmValue *res, GnmExprEvalFlags flags)
826 if (res == NULL)
827 return (flags & GNM_EXPR_EVAL_PERMIT_EMPTY)
828 ? NULL : value_new_int (0);
830 if (VALUE_IS_EMPTY (res)) {
831 value_release (res);
832 return (flags & GNM_EXPR_EVAL_PERMIT_EMPTY)
833 ? NULL : value_new_int (0);
835 return res;
839 * value_intersection:
840 * @v: a VALUE_CELLRANGE or VALUE_ARRAY
841 * @pos:
843 * Handle the implicit union of a single row or column with the eval position.
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.
849 * Always release the value passed in.
851 * Return value:
852 * If the intersection succeeded return a duplicate of the value
853 * at the intersection point. This value needs to be freed.
854 * NULL if there is no intersection
855 * Returns the upper left corner of an array.
857 static GnmValue *
858 value_intersection (GnmValue *v, GnmEvalPos const *pos)
860 GnmValue *res = NULL;
861 GnmRange r;
862 Sheet *start_sheet, *end_sheet;
863 gboolean found = FALSE;
865 if (VALUE_IS_ARRAY (v)) {
866 res = (v->v_array.x == 0 || v->v_array.y == 0)
867 ? value_new_error_VALUE (NULL)
868 : value_dup (v->v_array.vals[0][0]);
869 value_release (v);
870 return res;
873 /* inverted ranges */
874 gnm_rangeref_normalize (&v->v_range.cell, pos, &start_sheet, &end_sheet, &r);
875 value_release (v);
877 if (start_sheet == end_sheet || end_sheet == NULL) {
878 int col = pos->eval.col;
879 int row = pos->eval.row;
881 if (pos->dep && !dependent_is_cell (pos->dep)) {
882 /* See bug #142412. */
883 col = r.start.col;
884 row = r.start.row;
885 found = TRUE;
886 } else if (r.start.row == r.end.row) {
887 if (r.start.col <= col && col <= r.end.col) {
888 row = r.start.row;
889 found = TRUE;
890 } else if (r.start.col == r.end.col) {
891 col = r.start.col;
892 row = r.start.row;
893 found = TRUE;
895 } else if (r.start.col == r.end.col) {
896 if (r.start.row <= row && row <= r.end.row) {
897 col = r.start.col;
898 found = TRUE;
901 if (found) {
902 GnmCell *cell = sheet_cell_get (
903 eval_sheet (start_sheet, pos->sheet),
904 col, row);
905 if (cell == NULL)
906 return value_new_empty ();
907 gnm_cell_eval (cell);
908 return value_dup (cell->value);
912 return value_new_error_VALUE (pos);
915 static GnmValue *
916 bin_arith (GnmExpr const *expr, GnmEvalPos const *ep,
917 GnmValue const *a, GnmValue const *b)
919 gnm_float const va = value_get_as_float (a);
920 gnm_float const vb = value_get_as_float (b);
921 gnm_float res;
923 switch (GNM_EXPR_GET_OPER (expr)) {
924 case GNM_EXPR_OP_ADD:
925 res = va + vb;
926 break;
928 case GNM_EXPR_OP_SUB:
929 res = va - vb;
930 break;
932 case GNM_EXPR_OP_MULT:
933 res = va * vb;
934 break;
936 case GNM_EXPR_OP_DIV:
937 if (vb == 0.0)
938 return value_new_error_DIV0 (ep);
939 res = va / vb;
940 break;
942 case GNM_EXPR_OP_EXP:
943 if ((va == 0 && vb <= 0) || (va < 0 && vb != (int)vb))
944 return value_new_error_NUM (ep);
946 res = gnm_pow (va, vb);
947 break;
949 default:
950 g_assert_not_reached ();
953 if (gnm_finite (res))
954 return value_new_float (res);
955 else
956 return value_new_error_NUM (ep);
959 static GnmValue *
960 bin_cmp (GnmExprOp op, GnmValDiff comp, GnmEvalPos const *ep)
962 if (comp == TYPE_MISMATCH) {
963 /* TODO TODO TODO : Make error more informative
964 * regarding what is comparing to what
966 /* For equality comparisons even errors are ok */
967 if (op == GNM_EXPR_OP_EQUAL)
968 return value_new_bool (FALSE);
969 if (op == GNM_EXPR_OP_NOT_EQUAL)
970 return value_new_bool (TRUE);
972 return value_new_error_VALUE (ep);
975 switch (op) {
976 case GNM_EXPR_OP_EQUAL: return value_new_bool (comp == IS_EQUAL);
977 case GNM_EXPR_OP_GT: return value_new_bool (comp == IS_GREATER);
978 case GNM_EXPR_OP_LT: return value_new_bool (comp == IS_LESS);
979 case GNM_EXPR_OP_NOT_EQUAL: return value_new_bool (comp != IS_EQUAL);
980 case GNM_EXPR_OP_LTE: return value_new_bool (comp != IS_GREATER);
981 case GNM_EXPR_OP_GTE: return value_new_bool (comp != IS_LESS);
983 #ifndef DEBUG_SWITCH_ENUM
984 default:
985 g_assert_not_reached ();
986 #endif
988 return value_new_error (ep, _("Internal type error"));
991 static GnmValue *
992 cb_bin_cmp (GnmEvalPos const *ep, GnmValue const *a, GnmValue const *b,
993 GnmExpr const *expr)
995 if (a != NULL && VALUE_IS_ERROR (a))
996 return value_dup (a);
997 if (b != NULL && VALUE_IS_ERROR (b))
998 return value_dup (b);
999 return bin_cmp (GNM_EXPR_GET_OPER (expr), value_compare (a, b, FALSE), ep);
1002 static GnmValue *
1003 cb_bin_arith (GnmEvalPos const *ep, GnmValue const *a, GnmValue const *b,
1004 GnmExpr const *expr)
1006 GnmValue *res, *va, *vb;
1008 if (a != NULL && VALUE_IS_ERROR (a))
1009 return value_dup (a);
1010 if (b != NULL && VALUE_IS_ERROR (b))
1011 return value_dup (b);
1012 if (VALUE_IS_EMPTY (a))
1013 a = va = (GnmValue *)value_zero;
1014 else if (VALUE_IS_STRING (a)) {
1015 va = format_match_number (value_peek_string (a), NULL,
1016 sheet_date_conv (ep->sheet));
1017 if (va == NULL)
1018 return value_new_error_VALUE (ep);
1019 } else if (!VALUE_IS_NUMBER (a))
1020 return value_new_error_VALUE (ep);
1021 else
1022 va = (GnmValue *)a;
1023 if (VALUE_IS_EMPTY (b))
1024 b = vb = (GnmValue *)value_zero;
1025 else if (VALUE_IS_STRING (b)) {
1026 vb = format_match_number (value_peek_string (b), NULL,
1027 sheet_date_conv (ep->sheet));
1028 if (vb == NULL) {
1029 if (va != a)
1030 value_release (va);
1031 return value_new_error_VALUE (ep);
1033 } else if (!VALUE_IS_NUMBER (b)) {
1034 if (va != a)
1035 value_release (va);
1036 return value_new_error_VALUE (ep);
1037 } else
1038 vb = (GnmValue *)b;
1040 res = bin_arith (expr, ep, va, vb);
1041 if (va != a)
1042 value_release (va);
1043 if (vb != b)
1044 value_release (vb);
1045 return res;
1048 static GnmValue *
1049 cb_bin_cat (GnmEvalPos const *ep, GnmValue const *a, GnmValue const *b,
1050 GnmExpr const *expr)
1052 if (a != NULL && VALUE_IS_ERROR (a))
1053 return value_dup (a);
1054 if (b != NULL && VALUE_IS_ERROR (b))
1055 return value_dup (b);
1056 if (a == NULL) {
1057 if (b != NULL)
1058 return value_new_string (value_peek_string (b));
1059 else
1060 return value_new_string ("");
1061 } else if (b == NULL)
1062 return value_new_string (value_peek_string (a));
1063 else {
1064 char *tmp = g_strconcat (value_peek_string (a),
1065 value_peek_string (b), NULL);
1066 return value_new_string_nocopy (tmp);
1070 typedef GnmValue *(*BinOpImplicitIteratorFunc) (GnmEvalPos const *ep,
1071 GnmValue const *a,
1072 GnmValue const *b,
1073 gpointer user_data);
1074 typedef struct {
1075 GnmEvalPos const *ep;
1076 GnmValue *res;
1077 GnmValue const *a, *b;
1078 BinOpImplicitIteratorFunc func;
1080 /* multiply by 0 in unused dimensions.
1081 * this is simpler than lots of conditions
1082 * state->use_x.a ? x : 0
1084 struct {
1085 int a, b;
1086 } x, y;
1087 gpointer user_data;
1088 } BinOpImplicitIteratorState;
1090 static GnmValue *
1091 cb_implicit_iter_a_and_b (GnmValueIter const *v_iter,
1092 BinOpImplicitIteratorState const *state)
1094 state->res->v_array.vals [v_iter->x][v_iter->y] =
1095 (*state->func) (v_iter->ep,
1096 value_area_get_x_y (state->a,
1097 state->x.a * v_iter->x,
1098 state->y.a * v_iter->y, v_iter->ep),
1099 value_area_get_x_y (state->b,
1100 state->x.b * v_iter->x,
1101 state->y.b * v_iter->y, v_iter->ep),
1102 state->user_data);
1103 return NULL;
1105 static GnmValue *
1106 cb_implicit_iter_a_to_scalar_b (GnmValueIter const *v_iter,
1107 BinOpImplicitIteratorState const *state)
1109 state->res->v_array.vals [v_iter->x][v_iter->y] =
1110 (*state->func) (v_iter->ep,
1111 v_iter->v, state->b, state->user_data);
1112 return NULL;
1115 /* This is only triggered if something returns an array or a range which can
1116 * only happen if we are in array eval mode. */
1117 static GnmValue *
1118 bin_array_iter_a (GnmEvalPos const *ep,
1119 GnmValue *a, GnmValue *b,
1120 BinOpImplicitIteratorFunc func,
1121 GnmExpr const *expr)
1123 BinOpImplicitIteratorState iter_info;
1125 /* a must be a cellrange or array, it can not be NULL */
1126 iter_info.ep = ep;
1127 iter_info.func = func;
1128 iter_info.user_data = (gpointer) expr;
1129 iter_info.a = a;
1130 iter_info.b = b;
1132 /* matrix to matrix
1133 * Use matching positions unless the dimension is singular, in which
1134 * case use the zero item
1135 * res[x][y] = f(a[singular.a.x ? 0 : x, b[singular.b.x ? 0 : x)
1137 * If both items have non-singular sizes for
1138 * the same dimension use the min size (see samples/array.xls) */
1139 if (b != NULL &&
1140 (VALUE_IS_CELLRANGE (b) || VALUE_IS_ARRAY (b))) {
1141 int sa, sb, w = 1, h = 1;
1143 sa = value_area_get_width (a, ep);
1144 sb = value_area_get_width (b, ep);
1145 if ((iter_info.x.a = (sa == 1) ? 0 : 1))
1146 w = sa;
1147 if ((iter_info.x.b = (sb == 1) ? 0 : 1) && (w > sb || w == 1))
1148 w = sb;
1150 sa = value_area_get_height (a, ep);
1151 sb = value_area_get_height (b, ep);
1152 if ((iter_info.y.a = (sa == 1) ? 0 : 1))
1153 h = sa;
1154 if ((iter_info.y.b = (sb == 1) ? 0 : 1) && (h > sb || h == 1))
1155 h = sb;
1157 iter_info.res = value_new_array_empty (w, h);
1158 value_area_foreach (iter_info.res, ep, CELL_ITER_ALL,
1159 (GnmValueIterFunc) cb_implicit_iter_a_and_b, &iter_info);
1160 } else {
1161 iter_info.res = value_new_array_empty (
1162 value_area_get_width (a, ep),
1163 value_area_get_height (a, ep));
1164 value_area_foreach (a, ep, CELL_ITER_ALL,
1165 (GnmValueIterFunc) cb_implicit_iter_a_to_scalar_b, &iter_info);
1168 value_release (a);
1169 value_release (b);
1170 return iter_info.res;
1173 static GnmValue *
1174 cb_implicit_iter_b_to_scalar_a (GnmValueIter const *v_iter,
1175 BinOpImplicitIteratorState const *state)
1177 state->res->v_array.vals [v_iter->x][v_iter->y] =
1178 (*state->func) (v_iter->ep,
1179 state->a, v_iter->v, state->user_data);
1180 return NULL;
1182 static GnmValue *
1183 bin_array_iter_b (GnmEvalPos const *ep,
1184 GnmValue *a, GnmValue *b,
1185 BinOpImplicitIteratorFunc func,
1186 GnmExpr const *expr)
1188 BinOpImplicitIteratorState iter_info;
1190 iter_info.func = func;
1191 iter_info.user_data = (gpointer) expr;
1192 iter_info.a = a;
1193 iter_info.b = b;
1195 /* b must be a cellrange or array, it cannot be NULL */
1196 iter_info.res = value_new_array_empty (
1197 value_area_get_width (b, ep),
1198 value_area_get_height (b, ep));
1199 value_area_foreach (b, ep, CELL_ITER_ALL,
1200 (GnmValueIterFunc) cb_implicit_iter_b_to_scalar_a, &iter_info);
1201 value_release (a);
1202 value_release (b);
1204 return iter_info.res;
1207 static GnmValue *
1208 negate_value (GnmValue const *v)
1210 if (VALUE_IS_NUMBER (v)) {
1211 GnmValue *tmp = value_new_float (0 - value_get_as_float (v));
1212 value_set_fmt (tmp, VALUE_FMT (v));
1213 return tmp;
1214 } else
1215 return NULL;
1218 static GnmValue *
1219 cb_iter_unary_neg (GnmValueIter const *v_iter, GnmValue *res)
1221 GnmValue const *v = v_iter->v;
1222 GnmValue *tmp = NULL;
1224 if (VALUE_IS_EMPTY (v))
1225 tmp = value_new_int (0);
1226 else if (VALUE_IS_ERROR (v))
1227 tmp = value_dup (v);
1228 else if (VALUE_IS_STRING (v)) {
1229 GnmValue *conv = format_match_number (
1230 value_peek_string (v), NULL,
1231 sheet_date_conv (v_iter->ep->sheet));
1232 if (conv != NULL) {
1233 tmp = negate_value (conv);
1234 value_release (conv);
1236 } else {
1237 /* BOOL goes here. */
1238 tmp = negate_value (v);
1241 if (NULL == tmp)
1242 tmp = value_new_error_VALUE (v_iter->ep);
1243 res->v_array.vals[v_iter->x][v_iter->y] = tmp;
1244 return NULL;
1247 static GnmValue *
1248 cb_iter_percentage (GnmValueIter const *v_iter, GnmValue *res)
1250 GnmValue const *v = v_iter->v;
1251 GnmValue *tmp;
1253 if (VALUE_IS_EMPTY (v))
1254 tmp = value_new_int (0);
1255 else if (VALUE_IS_ERROR (v))
1256 tmp = value_dup (v);
1257 else {
1258 GnmValue *conv = NULL;
1259 if (VALUE_IS_STRING (v)) {
1260 conv = format_match_number (
1261 value_peek_string (v), NULL,
1262 sheet_date_conv (v_iter->ep->sheet));
1263 if (conv != NULL)
1264 v = conv;
1267 if (VALUE_IS_NUMBER (v)){
1268 tmp = value_new_float (value_get_as_float (v) / 100);
1269 value_set_fmt (tmp, go_format_default_percentage ());
1270 } else
1271 tmp = value_new_error_VALUE (v_iter->ep);
1273 value_release (conv);
1276 res->v_array.vals[v_iter->x][v_iter->y] = tmp;
1277 return NULL;
1280 static GnmValue *
1281 gnm_expr_range_op (GnmExpr const *expr, GnmEvalPos const *ep,
1282 GnmExprEvalFlags flags)
1284 GnmRangeRef a_ref, b_ref;
1285 GnmRange a_range, b_range, res_range;
1286 Sheet *a_start, *a_end, *b_start, *b_end;
1287 GnmValue *res = NULL;
1289 if (gnm_expr_extract_ref (&a_ref, expr->binary.value_a, ep, flags) ||
1290 gnm_expr_extract_ref (&b_ref, expr->binary.value_b, ep, flags))
1291 return value_new_error_REF (ep);
1293 gnm_rangeref_normalize (&a_ref, ep, &a_start, &a_end, &a_range);
1294 gnm_rangeref_normalize (&b_ref, ep, &b_start, &b_end, &b_range);
1296 switch (GNM_EXPR_GET_OPER (expr)) {
1297 case GNM_EXPR_OP_RANGE_CTOR:
1298 res_range = range_union (&a_range, &b_range);
1299 /* b_range might be on a bigger sheet. */
1300 range_ensure_sanity (&res_range, a_start);
1301 break;
1302 case GNM_EXPR_OP_INTERSECT:
1303 /* 3D references not allowed. */
1304 if (a_start != a_end || b_start != b_end)
1305 return value_new_error_VALUE (ep);
1307 /* Must be same sheet. */
1308 if (a_start != b_start)
1309 return value_new_error_VALUE (ep);
1311 if (!range_intersection (&res_range, &a_range, &b_range))
1312 return value_new_error_NULL (ep);
1313 break;
1314 default:
1315 g_assert_not_reached ();
1316 return NULL;
1319 res = value_new_cellrange_r (a_start, &res_range);
1320 dependent_add_dynamic_dep (ep->dep, &res->v_range.cell);
1321 if (!(flags & GNM_EXPR_EVAL_PERMIT_NON_SCALAR)) {
1322 res = value_intersection (res, ep);
1323 return (res != NULL)
1324 ? handle_empty (res, flags)
1325 : value_new_error_VALUE (ep);
1327 return res;
1331 * gnm_expr_eval:
1332 * @expr: #GnmExpr
1333 * @pos: evaluation position
1334 * @flags: #GnmExprEvalFlags
1336 * Evaluatates the given expression. Iif GNM_EXPR_EVAL_PERMIT_EMPTY is not set
1337 * then return zero if the expression instead of the empty value, or the value
1338 * of an unused cell.
1340 * Returns: (transfer full): result.
1342 GnmValue *
1343 gnm_expr_eval (GnmExpr const *expr, GnmEvalPos const *pos,
1344 GnmExprEvalFlags flags)
1346 GnmValue *res = NULL, *a = NULL, *b = NULL;
1348 g_return_val_if_fail (expr != NULL, handle_empty (NULL, flags));
1349 g_return_val_if_fail (pos != NULL, handle_empty (NULL, flags));
1351 retry:
1352 switch (GNM_EXPR_GET_OPER (expr)){
1353 case GNM_EXPR_OP_EQUAL:
1354 case GNM_EXPR_OP_NOT_EQUAL:
1355 case GNM_EXPR_OP_GT:
1356 case GNM_EXPR_OP_GTE:
1357 case GNM_EXPR_OP_LT:
1358 case GNM_EXPR_OP_LTE:
1359 flags |= GNM_EXPR_EVAL_PERMIT_EMPTY;
1360 flags &= ~GNM_EXPR_EVAL_WANT_REF;
1362 a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1363 if (a != NULL) {
1364 if (VALUE_IS_ERROR (a))
1365 return a;
1366 if (VALUE_IS_CELLRANGE (a) || VALUE_IS_ARRAY (a))
1367 return bin_array_iter_a (pos, a,
1368 gnm_expr_eval (expr->binary.value_b, pos, flags),
1369 (BinOpImplicitIteratorFunc) cb_bin_cmp,
1370 expr);
1373 b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1374 if (b != NULL) {
1375 if (VALUE_IS_ERROR (b)) {
1376 value_release (a);
1377 return b;
1379 if (VALUE_IS_CELLRANGE (b) || VALUE_IS_ARRAY (b))
1380 return bin_array_iter_b (pos, a, b,
1381 (BinOpImplicitIteratorFunc) cb_bin_cmp,
1382 expr);
1385 res = bin_cmp (GNM_EXPR_GET_OPER (expr), value_compare (a, b, FALSE), pos);
1386 value_release (a);
1387 value_release (b);
1388 return res;
1390 case GNM_EXPR_OP_ADD:
1391 case GNM_EXPR_OP_SUB:
1392 case GNM_EXPR_OP_MULT:
1393 case GNM_EXPR_OP_DIV:
1394 case GNM_EXPR_OP_EXP:
1396 * Priority
1397 * 1) Error from A
1398 * 2) #!VALUE error if A is not a number
1399 * 3) Error from B
1400 * 4) #!VALUE error if B is not a number
1401 * 5) result of operation, or error specific to the operation
1404 /* Guarantees value != NULL */
1405 flags &= ~GNM_EXPR_EVAL_PERMIT_EMPTY;
1406 flags &= ~GNM_EXPR_EVAL_WANT_REF;
1408 /* 1) Error from A */
1409 a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1410 if (VALUE_IS_ERROR (a))
1411 return value_error_set_pos (&a->v_err, pos);
1413 /* 2) #!VALUE error if A is not a number */
1414 if (VALUE_IS_STRING (a)) {
1415 GnmValue *tmp = format_match_number (value_peek_string (a), NULL,
1416 sheet_date_conv (pos->sheet));
1418 value_release (a);
1419 if (tmp == NULL)
1420 return value_new_error_VALUE (pos);
1421 a = tmp;
1422 } else if (VALUE_IS_CELLRANGE (a) || VALUE_IS_ARRAY (a)) {
1423 b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1424 if (VALUE_IS_STRING (b)) {
1425 res = format_match_number (value_peek_string (b), NULL,
1426 sheet_date_conv (pos->sheet));
1427 value_release (b);
1428 b = (res == NULL) ? value_new_error_VALUE (pos) : res;
1430 return bin_array_iter_a (pos, a, b,
1431 (BinOpImplicitIteratorFunc) cb_bin_arith,
1432 expr);
1433 } else if (!VALUE_IS_NUMBER (a)) {
1434 value_release (a);
1435 return value_new_error_VALUE (pos);
1438 /* 3) Error from B */
1439 b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1440 if (VALUE_IS_ERROR (b)) {
1441 value_release (a);
1442 return value_error_set_pos (&b->v_err, pos);
1445 /* 4) #!VALUE error if B is not a number */
1446 if (VALUE_IS_STRING (b)) {
1447 GnmValue *tmp = format_match_number (value_peek_string (b), NULL,
1448 sheet_date_conv (pos->sheet));
1450 value_release (b);
1451 if (tmp == NULL) {
1452 value_release (a);
1453 return value_new_error_VALUE (pos);
1455 b = tmp;
1456 } else if (VALUE_IS_CELLRANGE (b) || VALUE_IS_ARRAY (b))
1457 return bin_array_iter_b (pos, a, b,
1458 (BinOpImplicitIteratorFunc) cb_bin_arith,
1459 expr);
1460 else if (!VALUE_IS_NUMBER (b)) {
1461 value_release (a);
1462 value_release (b);
1463 return value_new_error_VALUE (pos);
1466 res = bin_arith (expr, pos, a, b);
1467 value_release (a);
1468 value_release (b);
1469 return res;
1471 case GNM_EXPR_OP_PAREN:
1472 /* Avoid recursive call to save stack. */
1473 expr = expr->unary.value;
1474 goto retry;
1476 case GNM_EXPR_OP_PERCENTAGE:
1477 case GNM_EXPR_OP_UNARY_NEG:
1478 case GNM_EXPR_OP_UNARY_PLUS:
1479 /* Guarantees value != NULL */
1480 flags &= ~GNM_EXPR_EVAL_PERMIT_EMPTY;
1481 flags &= ~GNM_EXPR_EVAL_WANT_REF;
1483 a = gnm_expr_eval (expr->unary.value, pos, flags);
1484 if (VALUE_IS_ERROR (a))
1485 return a;
1486 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_UNARY_PLUS)
1487 return a;
1489 /* 2) #!VALUE error if A is not a number */
1490 if (VALUE_IS_STRING (a)) {
1491 GnmValue *tmp = format_match_number (value_peek_string (a), NULL,
1492 sheet_date_conv (pos->sheet));
1494 value_release (a);
1495 if (tmp == NULL)
1496 return value_new_error_VALUE (pos);
1497 a = tmp;
1498 } else if (VALUE_IS_CELLRANGE (a) || VALUE_IS_ARRAY (a)) {
1499 res = value_new_array_empty (
1500 value_area_get_width (a, pos),
1501 value_area_get_height (a, pos));
1502 value_area_foreach (a, pos, CELL_ITER_ALL,
1503 (GnmValueIterFunc) ((GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_UNARY_NEG)
1504 ? cb_iter_unary_neg : cb_iter_percentage),
1505 res);
1506 value_release (a);
1507 return res;
1509 if (!VALUE_IS_NUMBER (a))
1510 res = value_new_error_VALUE (pos);
1511 else if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_UNARY_NEG)
1512 res = negate_value (a);
1513 else {
1514 res = value_new_float (value_get_as_float (a) / 100);
1515 value_set_fmt (res, go_format_default_percentage ());
1517 value_release (a);
1518 return res;
1520 case GNM_EXPR_OP_CAT:
1521 flags |= GNM_EXPR_EVAL_PERMIT_EMPTY;
1522 flags &= ~GNM_EXPR_EVAL_WANT_REF;
1523 a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1524 if (a != NULL) {
1525 if (VALUE_IS_ERROR (a))
1526 return a;
1527 if (VALUE_IS_CELLRANGE (a) || VALUE_IS_ARRAY (a))
1528 return bin_array_iter_a (pos, a,
1529 gnm_expr_eval (expr->binary.value_b, pos, flags),
1530 (BinOpImplicitIteratorFunc) cb_bin_cat,
1531 expr);
1533 b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1534 if (b != NULL) {
1535 if (VALUE_IS_ERROR (b)) {
1536 value_release (a);
1537 return b;
1539 if (VALUE_IS_CELLRANGE (b) || VALUE_IS_ARRAY (b))
1540 return bin_array_iter_b (pos, a, b,
1541 (BinOpImplicitIteratorFunc) cb_bin_cat,
1542 expr);
1545 if (a == NULL) {
1546 if (b != NULL) {
1547 res = value_new_string (value_peek_string (b));
1548 value_release (b);
1549 } else
1550 res = value_new_string ("");
1551 } else if (b == NULL) {
1552 res = value_new_string (value_peek_string (a));
1553 value_release (a);
1554 } else {
1555 char *tmp = g_strconcat (value_peek_string (a),
1556 value_peek_string (b), NULL);
1557 res = value_new_string_nocopy (tmp);
1558 value_release (a);
1559 value_release (b);
1561 return res;
1563 case GNM_EXPR_OP_FUNCALL: {
1564 GnmFuncEvalInfo ei;
1565 ei.pos = pos;
1566 ei.func_call = &expr->func;
1567 ei.flags = flags;
1568 res = function_call_with_exprs (&ei);
1569 if (res == NULL)
1570 return (flags & GNM_EXPR_EVAL_PERMIT_EMPTY)
1571 ? NULL : value_new_int (0);
1572 if (VALUE_IS_CELLRANGE (res)) {
1574 * pos->dep really shouldn't be NULL here, but it
1575 * will be if someone puts "indirect" into an
1576 * expression used for conditional formats.
1578 if (pos->dep)
1579 dependent_add_dynamic_dep (pos->dep,
1580 &res->v_range.cell);
1581 if (!(flags & GNM_EXPR_EVAL_PERMIT_NON_SCALAR)) {
1582 res = value_intersection (res, pos);
1583 return (res != NULL)
1584 ? handle_empty (res, flags)
1585 : value_new_error_VALUE (pos);
1587 return res;
1589 if (VALUE_IS_ARRAY (res) &&
1590 !(flags & GNM_EXPR_EVAL_PERMIT_NON_SCALAR)) {
1591 a = (res->v_array.x > 0 && res->v_array.y > 0)
1592 ? value_dup (res->v_array.vals[0][0])
1593 : value_new_error_REF (pos);
1594 value_release (res);
1595 return a;
1597 return res;
1600 case GNM_EXPR_OP_NAME:
1601 if (expr_name_is_active (expr->name.name))
1602 return handle_empty (expr_name_eval (expr->name.name, pos, flags), flags);
1603 return value_new_error_REF (pos);
1605 case GNM_EXPR_OP_CELLREF: {
1606 GnmCell *cell;
1607 GnmCellRef r;
1609 gnm_cellref_make_abs (&r, &expr->cellref.ref, pos);
1611 cell = sheet_cell_get (eval_sheet (r.sheet, pos->sheet),
1612 r.col, r.row);
1613 if (cell)
1614 gnm_cell_eval (cell);
1616 if (flags & GNM_EXPR_EVAL_WANT_REF) {
1617 return value_new_cellrange_unsafe (&r, &r);
1618 } else {
1619 GnmValue *v = cell ? value_dup (cell->value) : NULL;
1620 return handle_empty (v, flags);
1624 case GNM_EXPR_OP_CONSTANT:
1625 res = value_dup (expr->constant.value);
1626 if (VALUE_IS_CELLRANGE (res) || VALUE_IS_ARRAY (res)) {
1627 if (flags & GNM_EXPR_EVAL_PERMIT_NON_SCALAR)
1628 return res;
1629 res = value_intersection (res, pos);
1630 return (res != NULL)
1631 ? handle_empty (res, flags)
1632 : value_new_error_VALUE (pos);
1634 return handle_empty (res, flags);
1636 case GNM_EXPR_OP_ARRAY_CORNER:
1637 case GNM_EXPR_OP_ARRAY_ELEM:
1638 g_warning ("Unexpected array expressions encountered");
1639 return value_new_error_VALUE (pos);
1641 case GNM_EXPR_OP_SET:
1642 if (flags & GNM_EXPR_EVAL_PERMIT_NON_SCALAR) {
1643 int i;
1644 int argc = expr->set.argc;
1646 res = value_new_array_non_init (1, expr->set.argc);
1647 res->v_array.vals[0] = g_new (GnmValue *, expr->set.argc);
1648 for (i = 0; i < argc; i++)
1649 res->v_array.vals[0][i] = gnm_expr_eval (
1650 expr->set.argv[i], pos,
1651 GNM_EXPR_EVAL_SCALAR_NON_EMPTY);
1652 return res;
1654 return value_new_error_VALUE (pos);
1656 case GNM_EXPR_OP_RANGE_CTOR:
1657 case GNM_EXPR_OP_INTERSECT:
1658 return gnm_expr_range_op (expr, pos, flags);
1661 g_assert_not_reached ();
1662 return value_new_error (pos, _("Unknown evaluation error"));
1666 * gnm_expr_simplify_if:
1667 * @expr: Expression
1669 * Simplifies @expr if it is a call to "if" with a constant condition.
1671 * Returns: (transfer full) (nullable): simpler expression.
1673 GnmExpr const *
1674 gnm_expr_simplify_if (GnmExpr const *expr)
1676 static GnmFunc *f_if = NULL;
1677 GnmExpr const *cond;
1678 gboolean c;
1680 g_return_val_if_fail (expr != NULL, NULL);
1682 if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_FUNCALL)
1683 return NULL;
1685 if (!f_if)
1686 f_if = gnm_func_lookup ("if", NULL);
1688 if (expr->func.func != f_if || expr->func.argc != 3)
1689 return NULL;
1691 cond = expr->func.argv[0];
1692 if (GNM_EXPR_GET_OPER (cond) == GNM_EXPR_OP_CONSTANT) {
1693 GnmValue const *condval = cond->constant.value;
1694 gboolean err;
1695 c = value_get_as_bool (condval, &err);
1696 if (err)
1697 return NULL;
1698 } else
1699 return NULL;
1701 // We used to test for true() and false() as conditions too, but the code
1702 // never worked and has been unreachable until now.
1704 return gnm_expr_copy (expr->func.argv[c ? 1 : 2]);
1710 * Converts a parsed tree into its string representation
1711 * assuming that we are evaluating at col, row
1713 * This routine is pretty simple: it walks the GnmExpr and
1714 * appends a string representation to the target.
1716 static void
1717 do_expr_as_string (GnmExpr const *expr, int paren_level,
1718 GnmConventionsOut *out)
1720 static struct {
1721 char const name[4];
1722 guint8 prec; /* Precedences -- should match parser.y */
1723 guint8 assoc_left, assoc_right; /* 0: no, 1: yes. */
1724 guint8 is_prefix; /* for unary operators */
1725 } const operations[] = {
1726 { "", 0, 0, 0, 0 }, /* Parentheses for clarity */
1727 { "=", 1, 1, 0, 0 },
1728 { ">", 1, 1, 0, 0 },
1729 { "<", 1, 1, 0, 0 },
1730 { ">=", 1, 1, 0, 0 },
1731 { "<=", 1, 1, 0, 0 },
1732 { "<>", 1, 1, 0, 0 },
1733 { "+", 3, 1, 0, 0 },
1734 { "-", 3, 1, 0, 0 },
1735 { "*", 4, 1, 0, 0 },
1736 { "/", 4, 1, 0, 0 },
1737 { "^", 5, 0, 0, 0 }, /* Note: neither left nor right */
1738 { "&", 2, 1, 0, 0 },
1739 { "", 0, 0, 0, 0 }, /* Funcall */
1740 { "", 0, 0, 0, 0 }, /* Name */
1741 { "", 0, 0, 0, 0 }, /* Constant */
1742 { "", 0, 0, 0, 0 }, /* Var */
1743 { "-", 7, 0, 0, 1 }, /* Unary - */
1744 { "+", 7, 0, 0, 1 }, /* Unary + */
1745 { "%", 6, 0, 0, 0 }, /* Percentage (NOT MODULO) */
1746 { "", 0, 0, 0, 0 }, /* ArrayCorner */
1747 { "", 0, 0, 0, 0 }, /* ArrayElem */
1748 { "", 8, 0, 0, 0 }, /* Set */
1749 { ":", 10, 1, 0, 0 }, /* Range Ctor */
1750 { " ", 9, 1, 0, 0 } /* Intersection */
1752 GnmExprOp const op = GNM_EXPR_GET_OPER (expr);
1753 GString *target = out->accum;
1755 switch (op) {
1756 case GNM_EXPR_OP_RANGE_CTOR:
1757 case GNM_EXPR_OP_INTERSECT:
1758 case GNM_EXPR_OP_ANY_BINARY: {
1759 char const *opname = operations[op].name;
1760 int prec = operations[op].prec;
1761 gboolean need_par = (prec <= paren_level);
1762 size_t prelen = target->len;
1764 if (need_par) g_string_append_c (target, '(');
1765 do_expr_as_string (expr->binary.value_a,
1766 prec - operations[op].assoc_left, out);
1769 * Avoid getting "-2^2". We want to make sure files do not
1770 * contain that construct as we might later change precedence.
1772 * Always produce either "-(2^2)" or "(-2)^2".
1774 * Note, that the parser introduces an explicit parenthesis in
1775 * this case also, so parsed expressions should not be
1776 * affected by the code here.
1778 if (op == GNM_EXPR_OP_EXP &&
1779 (target->str[prelen] == '-' || target->str[prelen] == '+')) {
1780 g_string_insert_c (target, prelen, '(');
1781 g_string_append_c (target, ')');
1784 /* Instead of this we ought to move the whole operations
1785 table into the conventions. */
1786 if (op == GNM_EXPR_OP_INTERSECT)
1787 g_string_append_unichar (target, out->convs->intersection_char);
1788 else
1789 g_string_append (target, opname);
1791 do_expr_as_string (expr->binary.value_b,
1792 prec - operations[op].assoc_right, out);
1793 if (need_par) g_string_append_c (target, ')');
1794 return;
1797 case GNM_EXPR_OP_ANY_UNARY: {
1798 char const *opname = operations[op].name;
1799 int prec = operations[op].prec;
1800 gboolean is_prefix = operations[op].is_prefix;
1801 gboolean need_par = (prec <= paren_level);
1803 if (need_par) g_string_append_c (target, '(');
1804 if (is_prefix) g_string_append (target, opname);
1805 do_expr_as_string (expr->unary.value, prec, out);
1806 if (!is_prefix) g_string_append (target, opname);
1807 if (need_par) g_string_append_c (target, ')');
1808 return;
1811 case GNM_EXPR_OP_FUNCALL:
1812 out->convs->output.func (out, &expr->func);
1813 return;
1815 case GNM_EXPR_OP_NAME:
1816 out->convs->output.name (out, &expr->name);
1817 return;
1819 case GNM_EXPR_OP_CELLREF:
1820 out->convs->output.cell_ref (out, &expr->cellref.ref, FALSE);
1821 return;
1823 case GNM_EXPR_OP_CONSTANT: {
1824 GnmValue const *v = expr->constant.value;
1825 size_t prelen = target->len;
1827 if (VALUE_IS_STRING (v)) {
1828 out->convs->output.string (out, v->v_str.val);
1829 return;
1832 if (VALUE_IS_CELLRANGE (v)) {
1833 out->convs->output.range_ref (out, &v->v_range.cell);
1834 return;
1837 if (VALUE_IS_BOOLEAN (v) &&
1838 out->convs->output.boolean != NULL) {
1839 out->convs->output.boolean (out, v->v_bool.val);
1840 return;
1844 value_get_as_gstring (v, target, out->convs);
1846 /* If the number has a sign, pretend that it is the result of
1847 * OPER_UNARY_{NEG,PLUS}.
1849 if ((target->str[prelen] == '-' || target->str[prelen] == '+') &&
1850 operations[GNM_EXPR_OP_UNARY_NEG].prec <= paren_level) {
1851 g_string_insert_c (target, prelen, '(');
1852 g_string_append_c (target, ')');
1854 return;
1857 case GNM_EXPR_OP_ARRAY_CORNER:
1858 do_expr_as_string (expr->array_corner.expr, 0, out);
1859 return;
1861 case GNM_EXPR_OP_ARRAY_ELEM: {
1862 GnmCell const *corner = array_elem_get_corner (&expr->array_elem,
1863 out->pp->sheet, &out->pp->eval);
1864 if (NULL != corner) {
1865 GnmParsePos const *real_pp = out->pp;
1866 GnmParsePos pp = *real_pp;
1868 pp.eval.col -= expr->array_elem.x;
1869 pp.eval.row -= expr->array_elem.y;
1870 out->pp = &pp;
1871 do_expr_as_string (
1872 corner->base.texpr->expr->array_corner.expr,
1873 0, out);
1874 out->pp = real_pp;
1875 return;
1877 break;
1880 case GNM_EXPR_OP_SET:
1881 gnm_expr_list_as_string (expr->set.argc, expr->set.argv, out);
1882 return;
1885 g_string_append (target, "<ERROR>");
1889 * gnm_expr_as_gstring:
1890 * @expr: #GnmExpr
1891 * @out: output convensions
1893 * Renders the expression as a string according to @out and places the
1894 * result in @out's accumulator.
1896 void
1897 gnm_expr_as_gstring (GnmExpr const *expr, GnmConventionsOut *out)
1899 g_return_if_fail (expr != NULL);
1900 g_return_if_fail (out != NULL);
1902 do_expr_as_string (expr, 0, out);
1906 * gnm_expr_as_string:
1907 * @expr: #GnmExpr
1908 * @pp: (nullable): Parse position. %NULL should be used for debugging only.
1909 * @convs: (nullable): #GnmConventions. %NULL should be used for debugging
1910 * or when @pp identifies a #Sheet.
1912 * Renders the expression as a string according to @convs.
1914 * Returns: (transfer full): @expr as a string.
1916 char *
1917 gnm_expr_as_string (GnmExpr const *expr, GnmParsePos const *pp,
1918 GnmConventions const *convs)
1920 GnmConventionsOut out;
1921 GnmParsePos pp0;
1923 g_return_val_if_fail (expr != NULL, NULL);
1926 * Defaults for debugging only!
1928 if (!pp) {
1929 /* UGH: Just get the first sheet in the first workbook! */
1930 Workbook *wb = gnm_app_workbook_get_by_index (0);
1931 Sheet *sheet = workbook_sheet_by_index (wb, 0);
1932 parse_pos_init (&pp0, NULL, sheet, 0, 0);
1933 pp = &pp0;
1935 if (!convs)
1936 convs = pp->sheet
1937 ? sheet_get_conventions (pp->sheet)
1938 : gnm_conventions_default;
1940 out.accum = g_string_new (NULL);
1941 out.pp = pp;
1942 out.convs = convs;
1943 do_expr_as_string (expr, 0, &out);
1944 return g_string_free (out.accum, FALSE);
1947 /****************************************************************************/
1949 static gboolean
1950 gnm_expr_is_err (GnmExpr const *expr, GnmStdError err)
1952 GnmStdError err2;
1954 if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_CONSTANT)
1955 return FALSE;
1957 err2 = value_error_classify (expr->constant.value);
1958 return err == err2;
1962 * gnm_expr_get_constant:
1963 * @expr: #GnmExpr
1965 * Returns: (transfer none) (nullable): If this expression consists of just
1966 * a constant, return it. Otherwise, %NULL.
1968 GnmValue const *
1969 gnm_expr_get_constant (GnmExpr const *expr)
1971 if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_CONSTANT)
1972 return NULL;
1974 return expr->constant.value;
1978 * gnm_expr_get_name:
1979 * @expr: #GnmExpr
1981 * Returns: (transfer none) (nullable): If this expression consists of just
1982 * a name, return it. Otherwise, %NULL.
1984 GnmNamedExpr const *
1985 gnm_expr_get_name (GnmExpr const *expr)
1987 if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_NAME)
1988 return NULL;
1990 return expr->name.name;
1995 * gnm_expr_get_cellref:
1996 * @expr: #GnmExpr
1998 * Returns: (transfer none) (nullable): If this expression consists of just
1999 * a cell reference, return it. Otherwise, %NULL.
2001 GnmCellRef const *
2002 gnm_expr_get_cellref (GnmExpr const *expr)
2004 if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_CELLREF)
2005 return NULL;
2007 return &expr->cellref.ref;
2011 typedef struct {
2012 GnmExprRelocateInfo const *details;
2013 gboolean from_inside;
2014 gboolean check_rels;
2015 } RelocInfoInternal;
2017 static GnmExpr const *
2018 invalidate_sheet_cellrange (RelocInfoInternal const *rinfo,
2019 GnmValueRange const *v)
2021 GnmCellRef ref_a = v->cell.a;
2022 GnmCellRef ref_b = v->cell.b;
2024 Sheet const *sheet_a = ref_a.sheet;
2025 Sheet const *sheet_b = ref_b.sheet;
2026 Workbook *wb;
2027 gboolean hit_a = sheet_a && sheet_a->being_invalidated;
2028 gboolean hit_b = sheet_b && sheet_b->being_invalidated;
2029 int dir;
2031 if (!hit_a && !hit_b)
2032 return NULL;
2034 if (sheet_a == NULL || sheet_b == NULL ||
2035 sheet_a->workbook != sheet_b->workbook)
2036 /* A 3D reference between workbooks? */
2037 return gnm_expr_new_constant (value_new_error_REF (NULL));
2039 /* Narrow the sheet range. */
2040 wb = sheet_a->workbook;
2041 dir = (sheet_a->index_in_wb < sheet_b->index_in_wb) ? +1 : -1;
2042 while (sheet_a != sheet_b && sheet_a->being_invalidated)
2043 sheet_a = workbook_sheet_by_index (wb, sheet_a->index_in_wb + dir);
2044 while (sheet_a != sheet_b && sheet_b->being_invalidated)
2045 sheet_b = workbook_sheet_by_index (wb, sheet_b->index_in_wb - dir);
2047 if (sheet_a->being_invalidated)
2048 return gnm_expr_new_constant (value_new_error_REF (NULL));
2050 ref_a.sheet = (Sheet *)sheet_a;
2051 ref_b.sheet = (Sheet *)sheet_b;
2052 return gnm_expr_new_constant (value_new_cellrange_unsafe (&ref_a, &ref_b));
2055 static gboolean
2056 reloc_range (GnmExprRelocateInfo const *rinfo,
2057 Sheet const *start_sheet, Sheet const *end_sheet,
2058 GnmRange *rng)
2060 GnmRange t, b, l, r;
2061 gboolean start, end;
2063 if (start_sheet != end_sheet || /* ignore 3d refs */
2064 start_sheet != rinfo->origin_sheet) /* ref is to a different sheet */
2065 return FALSE;
2067 t.start.col = b.start.col = l.start.col = l.end.col = rng->start.col;
2068 t.end.col = b.end.col = r.start.col = r.end.col = rng->end.col;
2069 t.start.row = t.end.row = l.start.row = r.start.row = rng->start.row;
2070 b.start.row = b.end.row = l.end.row = r.end.row = rng->end.row;
2072 start = range_contained (&t, &rinfo->origin);
2073 end = range_contained (&b, &rinfo->origin);
2074 if (start && end) { /* full enclosure */
2075 rng->start.col += rinfo->col_offset;
2076 rng->end.col += rinfo->col_offset;
2077 rng->start.row += rinfo->row_offset;
2078 rng->end.row += rinfo->row_offset;
2079 return TRUE;
2082 if (rinfo->col_offset == 0) {
2083 if (start && rinfo->row_offset < range_height (rng)) {
2084 rng->start.row += rinfo->row_offset;
2085 return TRUE;
2087 if (end && rinfo->row_offset > -range_height (rng)) {
2088 /* Special case invalidating the bottom of a range while
2089 * deleting rows. Otherwise we #REF! before we can shorten
2090 * The -1 is safe, origin.start.row == 0 is handled above */
2091 if (rinfo->reloc_type == GNM_EXPR_RELOCATE_ROWS &&
2092 rinfo->row_offset >= gnm_sheet_get_max_rows (end_sheet))
2093 rng->end.row = rinfo->origin.start.row - 1;
2094 else
2095 rng->end.row += rinfo->row_offset;
2096 return TRUE;
2100 if (rinfo->row_offset == 0) {
2101 if (range_contained (&l, &rinfo->origin) &&
2102 rinfo->col_offset < range_width (rng)) {
2103 rng->start.col += rinfo->col_offset;
2104 return TRUE;
2106 if (range_contained (&r, &rinfo->origin) &&
2107 rinfo->col_offset > -range_width (rng)) {
2108 /* Special case invalidating the right side of a range while
2109 * deleting cols. Otherwise we #REF! before we can shorten.
2110 * The -1 is safe, origin.start.col == 0 is handled above */
2111 if (rinfo->reloc_type == GNM_EXPR_RELOCATE_COLS &&
2112 rinfo->col_offset >= gnm_sheet_get_max_cols (end_sheet))
2113 rng->end.col = rinfo->origin.start.col - 1;
2114 else
2115 rng->end.col += rinfo->col_offset;
2116 return TRUE;
2120 return FALSE;
2123 static void
2124 reloc_normalize_cellref (RelocInfoInternal const *rinfo, GnmCellRef const *ref,
2125 Sheet **sheet, GnmCellPos *res)
2127 *sheet = eval_sheet (ref->sheet, rinfo->details->pos.sheet);
2128 res->col = ref->col;
2129 if (ref->col_relative) {
2130 if (rinfo->check_rels)
2131 res->col += rinfo->details->pos.eval.col;
2132 else
2133 res->col = 0;
2135 res->row = ref->row;
2136 if (ref->row_relative) {
2137 if (rinfo->check_rels)
2138 res->row += rinfo->details->pos.eval.row;
2139 else
2140 res->row = 0;
2144 /* Return %TRUE if @pos is out of bounds */
2145 static gboolean
2146 reloc_restore_cellref (RelocInfoInternal const *rinfo,
2147 GnmSheetSize const *ss, GnmCellPos const *pos,
2148 GnmCellRef *res)
2150 if (res->sheet == rinfo->details->origin_sheet) {
2151 res->sheet = rinfo->details->target_sheet;
2152 if (res->sheet)
2153 ss = gnm_sheet_get_size (res->sheet);
2156 if (!res->col_relative || rinfo->check_rels) {
2157 if (pos->col < 0 || ss->max_cols <= pos->col)
2158 return TRUE;
2159 res->col = pos->col;
2160 if (res->col_relative) {
2161 res->col -= rinfo->details->pos.eval.col;
2162 if (rinfo->from_inside)
2163 res->col -= rinfo->details->col_offset;
2167 if (!res->row_relative || rinfo->check_rels) {
2168 if (pos->row < 0 || ss->max_rows <= pos->row)
2169 return TRUE;
2170 res->row = pos->row;
2171 if (res->row_relative) {
2172 res->row -= rinfo->details->pos.eval.row;
2173 if (rinfo->from_inside)
2174 res->row -= rinfo->details->row_offset;
2178 return FALSE;
2182 static GnmExpr const *
2183 reloc_cellrange (RelocInfoInternal const *rinfo, GnmValueRange const *v,
2184 gboolean sticky_end)
2186 GnmRange r;
2187 Sheet *start_sheet, *end_sheet;
2188 GnmSheetSize const *start_ss, *end_ss;
2189 gboolean full_col, full_row;
2190 gboolean full_col_begin, full_row_begin;
2192 /* Normalize the rangeRef, and remember if we had a full col/row
2193 * ref. If relocating the result changes things, or if we're from
2194 * inside the range that is moving map back to a RangeRef from the
2195 * target position. If the result is different that the original
2196 * generate a new expression. */
2197 reloc_normalize_cellref (rinfo, &v->cell.a, &start_sheet, &r.start);
2198 reloc_normalize_cellref (rinfo, &v->cell.b, &end_sheet, &r.end);
2199 /* (Foo,NULL) in Bar will generate (Foo,Bar) in normalize */
2200 if (NULL == v->cell.b.sheet)
2201 end_sheet = start_sheet;
2202 start_ss = gnm_sheet_get_size2 (start_sheet, rinfo->details->pos.wb);
2203 end_ss = gnm_sheet_get_size2 (end_sheet, rinfo->details->pos.wb);
2205 full_col = sticky_end && r.end.row >= start_ss->max_rows - 1;
2206 full_col_begin = full_col && r.start.row == 0;
2208 full_row = sticky_end && r.end.col >= start_ss->max_cols - 1;
2209 full_row_begin = full_row && r.start.col == 0;
2211 if (reloc_range (rinfo->details, start_sheet, end_sheet, &r) ||
2212 rinfo->from_inside) {
2213 GnmRangeRef res = v->cell;
2215 if (full_col)
2216 r.end.row = start_ss->max_rows - 1;
2217 if (full_col_begin)
2218 r.start.row = 0;
2219 if (full_row)
2220 r.end.col = start_ss->max_cols - 1;
2221 if (full_row_begin)
2222 r.start.col = 0;
2224 if (reloc_restore_cellref (rinfo, start_ss, &r.start, &res.a) ||
2225 reloc_restore_cellref (rinfo, end_ss, &r.end, &res.b))
2226 return gnm_expr_new_constant (value_new_error_REF (NULL));
2227 if (gnm_rangeref_equal (&res, &v->cell))
2228 return NULL;
2229 return gnm_expr_new_constant (value_new_cellrange_unsafe (&res.a, &res.b));
2232 return NULL;
2235 static GnmExpr const *
2236 gnm_expr_relocate (GnmExpr const *expr, RelocInfoInternal const *rinfo);
2238 static GnmExpr const *
2239 cb_relocate (GnmExpr const *expr, GnmExprWalk *data)
2241 RelocInfoInternal const *rinfo = data->user;
2243 switch (GNM_EXPR_GET_OPER (expr)) {
2244 case GNM_EXPR_OP_NAME: {
2245 GnmNamedExpr *nexpr = expr->name.name;
2247 /* we cannot invalidate references to the name that are
2248 * sitting in the undo queue, or the clipboard. So we just
2249 * flag the name as inactive and remove the reference here.
2251 if (!expr_name_is_active (nexpr))
2252 return gnm_expr_new_constant (value_new_error_REF (NULL));
2254 switch (rinfo->details->reloc_type) {
2255 case GNM_EXPR_RELOCATE_INVALIDATE_SHEET:
2256 if (nexpr->pos.sheet && nexpr->pos.sheet->being_invalidated)
2257 return gnm_expr_new_constant (value_new_error_REF (NULL));
2258 else
2259 return NULL;
2261 case GNM_EXPR_RELOCATE_MOVE_RANGE:
2263 * If the name is not officially scoped, check
2264 * that it is available in the new scope
2266 if (expr->name.optional_scope == NULL &&
2267 rinfo->details->target_sheet != rinfo->details->origin_sheet) {
2268 GnmNamedExpr *new_nexpr;
2269 GnmParsePos pos;
2270 parse_pos_init_sheet (&pos, rinfo->details->target_sheet);
2272 /* If the name is not available in the new scope explicitly scope it */
2273 new_nexpr = expr_name_lookup (&pos, expr_name_name (nexpr));
2274 if (new_nexpr == NULL) {
2275 if (nexpr->pos.sheet != NULL)
2276 return gnm_expr_new_name (nexpr, nexpr->pos.sheet, NULL);
2277 return gnm_expr_new_name (nexpr, NULL, nexpr->pos.wb);
2280 /* replace it with the new name using qualified as
2281 * local to the target sheet
2283 return gnm_expr_new_name (new_nexpr, pos.sheet, NULL);
2284 } else {
2286 * Do NOT rewrite the name.
2288 * Just invalidate the use of the name if the
2289 * name's expression, if relocated, would
2290 * become invalid.
2292 GnmExpr const *tmp =
2293 gnm_expr_relocate (nexpr->texpr->expr,
2294 rinfo);
2295 if (tmp && gnm_expr_is_err (tmp, GNM_ERROR_REF))
2296 return tmp;
2298 if (tmp)
2299 gnm_expr_free (tmp);
2301 return NULL;
2304 case GNM_EXPR_RELOCATE_COLS:
2305 case GNM_EXPR_RELOCATE_ROWS:
2306 return NULL;
2308 default:
2309 g_assert_not_reached ();
2313 case GNM_EXPR_OP_CELLREF: {
2314 GnmCellRef const *ref = &expr->cellref.ref;
2315 switch (rinfo->details->reloc_type) {
2316 case GNM_EXPR_RELOCATE_INVALIDATE_SHEET:
2317 if (ref->sheet &&
2318 ref->sheet->being_invalidated)
2319 return gnm_expr_new_constant (value_new_error_REF (NULL));
2320 return NULL;
2322 case GNM_EXPR_RELOCATE_MOVE_RANGE:
2323 case GNM_EXPR_RELOCATE_COLS:
2324 case GNM_EXPR_RELOCATE_ROWS: {
2325 GnmRange r;
2326 Sheet *sheet;
2327 GnmSheetSize const *ss;
2329 reloc_normalize_cellref (rinfo, ref, &sheet, &r.start);
2330 r.end = r.start;
2331 ss = gnm_sheet_get_size2 (sheet, rinfo->details->pos.wb);
2333 if (reloc_range (rinfo->details, sheet, sheet, &r) ||
2334 rinfo->from_inside) {
2335 GnmCellRef res = *ref;
2336 if (reloc_restore_cellref (rinfo, ss, &r.start, &res))
2337 return gnm_expr_new_constant (value_new_error_REF (NULL));
2338 if (gnm_cellref_equal (&res, ref))
2339 return NULL;
2340 return gnm_expr_new_cellref (&res);
2342 return NULL;
2345 default:
2346 g_assert_not_reached ();
2349 return NULL;
2352 case GNM_EXPR_OP_CONSTANT:
2353 if (VALUE_IS_CELLRANGE (expr->constant.value)) {
2354 GnmValueRange const *vr = &expr->constant.value->v_range;
2355 switch (rinfo->details->reloc_type) {
2356 case GNM_EXPR_RELOCATE_INVALIDATE_SHEET:
2357 return invalidate_sheet_cellrange (rinfo, vr);
2358 case GNM_EXPR_RELOCATE_MOVE_RANGE:
2359 return reloc_cellrange (rinfo, vr, TRUE);
2360 case GNM_EXPR_RELOCATE_COLS:
2361 case GNM_EXPR_RELOCATE_ROWS:
2362 return reloc_cellrange (rinfo, vr, rinfo->details->sticky_end);
2363 default:
2364 g_assert_not_reached ();
2367 return NULL;
2369 default:
2370 return NULL;
2374 static GnmExpr const *
2375 gnm_expr_relocate (GnmExpr const *expr, RelocInfoInternal const *rinfo)
2377 g_return_val_if_fail (expr != NULL, NULL);
2378 return gnm_expr_walk (expr, cb_relocate, (gpointer)rinfo);
2382 * gnm_expr_get_func_def:
2383 * @expr: Function call expressions
2385 * Returns: (transfer none): the called function.
2387 GnmFunc *
2388 gnm_expr_get_func_def (GnmExpr const *expr)
2390 g_return_val_if_fail (expr != NULL, NULL);
2391 g_return_val_if_fail (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL, NULL);
2393 return expr->func.func;
2397 * gnm_expr_get_func_arg:
2398 * @expr: Function call expressions
2399 * @i: argument index
2401 * Returns: (transfer none): the @i'th argument of the function call @expr.
2403 GnmExpr const *
2404 gnm_expr_get_func_arg (GnmExpr const *expr, int i)
2406 g_return_val_if_fail (expr != NULL, NULL);
2407 g_return_val_if_fail (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL, NULL);
2408 g_return_val_if_fail (i >= 0 && i < expr->func.argc, NULL);
2410 return expr->func.argv[i];
2414 static void
2415 cellref_boundingbox (GnmCellRef const *cr, Sheet const *sheet, GnmRange *bound)
2417 GnmSheetSize const *ss;
2419 if (cr->sheet)
2420 sheet = cr->sheet;
2421 ss = gnm_sheet_get_size (sheet);
2423 if (cr->col_relative) {
2424 if (cr->col >= 0) {
2425 int const c = ss->max_cols - cr->col - 1;
2426 if (bound->end.col > c)
2427 bound->end.col = c;
2428 } else {
2429 int const c = -cr->col;
2430 if (bound->start.col < c)
2431 bound->start.col = c;
2434 if (cr->row_relative) {
2435 if (cr->row >= 0) {
2436 int const r = ss->max_rows - cr->row - 1;
2437 if (bound->end.row > r)
2438 bound->end.row = r;
2439 } else {
2440 int const r = -cr->row;
2441 if (bound->start.row < r)
2442 bound->start.row = r;
2447 static GnmExpr const *
2448 cb_contains_subtotal (GnmExpr const *expr, GnmExprWalk *data)
2450 gboolean *res = data->user;
2451 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL &&
2452 strcmp (expr->func.func->name, "subtotal") == 0) {
2453 *res = TRUE;
2454 data->stop = TRUE;
2456 return NULL;
2460 * gnm_expr_containts_subtotal:
2461 * @expr: #GnmExpr
2463 * Returns: %TRUE if the expression calls the SUBTOTAL function
2465 gboolean
2466 gnm_expr_contains_subtotal (GnmExpr const *expr)
2468 gboolean res = FALSE;
2469 gnm_expr_walk (expr, cb_contains_subtotal, &res);
2470 return res;
2474 * gnm_expr_get_range:
2475 * @expr: #GnmExpr
2477 * Returns: (transfer full) (nullable): If this expression contains a
2478 * single range, return it. Otherwise, %NULL. A cell reference is
2479 * returned as a singleton range.
2481 GnmValue *
2482 gnm_expr_get_range (GnmExpr const *expr)
2484 g_return_val_if_fail (expr != NULL, NULL);
2486 switch (GNM_EXPR_GET_OPER (expr)) {
2487 case GNM_EXPR_OP_CELLREF:
2488 return value_new_cellrange_unsafe (
2489 &expr->cellref.ref, &expr->cellref.ref);
2491 case GNM_EXPR_OP_CONSTANT:
2492 if (VALUE_IS_CELLRANGE (expr->constant.value))
2493 return value_dup (expr->constant.value);
2494 return NULL;
2496 case GNM_EXPR_OP_NAME:
2497 if (!expr_name_is_active (expr->name.name))
2498 return NULL;
2499 return gnm_expr_top_get_range (expr->name.name->texpr);
2501 case GNM_EXPR_OP_PAREN:
2502 return gnm_expr_get_range (expr->unary.value);
2504 default:
2505 return NULL;
2509 static gint
2510 gnm_insert_unique_value_cmp (gconstpointer a, gconstpointer b)
2512 return (value_equal (a,b) ? 0 : 1);
2517 static GSList *
2518 gnm_insert_unique_value (GSList *list, GnmValue *data)
2520 if (g_slist_find_custom (list, data,
2521 gnm_insert_unique_value_cmp)
2522 == NULL)
2523 return g_slist_prepend (list, data);
2524 value_release (data);
2525 return list;
2529 * gnm_expr_is_rangeref:
2530 * @expr: #GnmExpr
2532 * Returns: %TRUE if the expression can generate a reference.
2533 * NOTE: in the future it would be nice to know if a function
2534 * can return a reference to tighten that up a bit.
2536 gboolean
2537 gnm_expr_is_rangeref (GnmExpr const *expr)
2539 g_return_val_if_fail (expr != NULL, FALSE);
2541 switch (GNM_EXPR_GET_OPER (expr)) {
2542 /* would be better if we could differential which functions can return refs */
2543 case GNM_EXPR_OP_FUNCALL:
2545 /* a set in a set, do we need this ? */
2546 case GNM_EXPR_OP_SET:
2548 case GNM_EXPR_OP_RANGE_CTOR:
2549 case GNM_EXPR_OP_INTERSECT:
2550 case GNM_EXPR_OP_CELLREF:
2551 return TRUE;
2553 case GNM_EXPR_OP_CONSTANT:
2554 if (VALUE_IS_CELLRANGE (expr->constant.value))
2555 return TRUE;
2556 return FALSE;
2558 case GNM_EXPR_OP_NAME:
2559 if (expr_name_is_active (expr->name.name))
2560 return gnm_expr_is_rangeref (expr->name.name->texpr->expr);
2561 return FALSE;
2563 case GNM_EXPR_OP_ARRAY_CORNER: /* I don't think this is possible */
2564 case GNM_EXPR_OP_ARRAY_ELEM:
2565 default:
2566 return FALSE;
2570 gboolean
2571 gnm_expr_is_data_table (GnmExpr const *expr, GnmCellPos *c_in, GnmCellPos *r_in)
2573 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL) {
2574 char const *name = gnm_func_get_name (expr->func.func, FALSE);
2575 if (name && 0 == strcmp (name, "table")) {
2576 if (NULL != r_in) {
2577 GnmExpr const *r = (expr->func.argc <= 0)
2578 ? NULL
2579 : expr->func.argv[0];
2581 if (r != NULL && GNM_EXPR_GET_OPER (r) == GNM_EXPR_OP_CELLREF) {
2582 r_in->col = r->cellref.ref.col;
2583 r_in->row = r->cellref.ref.row;
2584 } else
2585 r_in->col = r_in->row = 0; /* impossible */
2587 if (NULL != c_in) {
2588 GnmExpr const *c = (expr->func.argc <= 1)
2589 ? NULL
2590 : expr->func.argv[1];
2592 if (c != NULL && GNM_EXPR_GET_OPER (c) == GNM_EXPR_OP_CELLREF) {
2593 c_in->col = c->cellref.ref.col;
2594 c_in->row = c->cellref.ref.row;
2595 } else
2596 c_in->col = c_in->row = 0; /* impossible */
2598 return TRUE;
2602 /* Do we need anything else here ? */
2603 return FALSE;
2607 static GnmExpr const *
2608 do_expr_walk (GnmExpr const *expr, GnmExprWalkerFunc walker, GnmExprWalk *data)
2610 GnmExpr const *res;
2612 res = walker (expr, data);
2613 if (data->stop) {
2614 if (res) gnm_expr_free (res);
2615 return NULL;
2617 if (res)
2618 return res;
2620 switch (GNM_EXPR_GET_OPER (expr)) {
2621 case GNM_EXPR_OP_RANGE_CTOR:
2622 case GNM_EXPR_OP_INTERSECT:
2623 case GNM_EXPR_OP_ANY_BINARY: {
2624 GnmExpr const *a, *b;
2626 a = do_expr_walk (expr->binary.value_a, walker, data);
2627 if (data->stop)
2628 return NULL;
2630 b = do_expr_walk (expr->binary.value_b, walker, data);
2631 if (data->stop) {
2632 if (a) gnm_expr_free (a);
2633 return NULL;
2636 if (!a && !b)
2637 return NULL;
2639 if (!a)
2640 a = gnm_expr_copy (expr->binary.value_a);
2641 else if (!b)
2642 b = gnm_expr_copy (expr->binary.value_b);
2644 return gnm_expr_new_binary (a, GNM_EXPR_GET_OPER (expr), b);
2647 case GNM_EXPR_OP_ANY_UNARY: {
2648 GnmExpr const *a = do_expr_walk (expr->unary.value, walker, data);
2649 return a
2650 ? gnm_expr_new_unary (GNM_EXPR_GET_OPER (expr), a)
2651 : NULL;
2654 case GNM_EXPR_OP_FUNCALL: {
2655 gboolean any = FALSE;
2656 int i;
2657 int argc = expr->func.argc;
2658 GnmExprConstPtr *argv =
2659 argc ? g_new (GnmExprConstPtr, argc) : NULL;
2661 for (i = 0; i < argc; i++) {
2662 argv[i] = do_expr_walk (expr->func.argv[i], walker, data);
2663 if (data->stop) {
2664 while (--i >= 0)
2665 if (argv[i])
2666 gnm_expr_free (argv[i]);
2667 any = FALSE;
2668 break;
2670 if (argv[i])
2671 any = TRUE;
2674 if (any) {
2675 int i;
2676 for (i = 0; i < argc; i++)
2677 if (!argv[i])
2678 argv[i] = gnm_expr_copy (expr->func.argv[i]);
2679 return gnm_expr_new_funcallv (expr->func.func,
2680 argc, argv);
2681 } else {
2682 g_free (argv);
2683 return NULL;
2686 case GNM_EXPR_OP_SET: {
2687 gboolean any = FALSE;
2688 int i;
2689 int argc = expr->set.argc;
2690 GnmExprConstPtr *argv =
2691 argc ? g_new (GnmExprConstPtr, argc) : NULL;
2693 for (i = 0; i < argc; i++) {
2694 argv[i] = do_expr_walk (expr->set.argv[i], walker, data);
2695 if (data->stop) {
2696 while (--i >= 0)
2697 if (argv[i])
2698 gnm_expr_free (argv[i]);
2699 any = FALSE;
2700 break;
2702 if (argv[i])
2703 any = TRUE;
2706 if (any) {
2707 int i;
2708 for (i = 0; i < argc; i++)
2709 if (!argv[i])
2710 argv[i] = gnm_expr_copy (expr->set.argv[i]);
2711 return gnm_expr_new_setv (argc, argv);
2712 } else {
2713 g_free (argv);
2714 return NULL;
2718 case GNM_EXPR_OP_ARRAY_CORNER: {
2719 GnmExpr const *e = do_expr_walk (expr->array_corner.expr, walker, data);
2720 return e
2721 ? gnm_expr_new_array_corner (
2722 expr->array_corner.cols,
2723 expr->array_corner.rows, e)
2724 : NULL;
2727 default:
2728 return NULL;
2733 * gnm_expr_walk:
2734 * @expr: expression to walk
2735 * @walker: (scope call): callback for each sub-expression
2736 * @user: user data pointer
2738 * Returns: (transfer full) (allow-none): transformed expression.
2740 * This function walks the expression and calls the walker function for
2741 * each subexpression. If the walker returns a non-%NULL expression,
2742 * a new expression is built.
2744 * The walker will be called for an expression before its subexpressions.
2745 * It will receive the expression as its first argument and a GnmExprWalk
2746 * pointer as its second. It may set the stop flag to terminate the walk
2747 * in which case gnm_expr_walk will return %NULL.
2749 GnmExpr const *
2750 gnm_expr_walk (GnmExpr const *expr, GnmExprWalkerFunc walker, gpointer user)
2752 GnmExprWalk data;
2754 g_return_val_if_fail (expr != NULL, NULL);
2756 data.user = user;
2757 data.stop = FALSE;
2758 data.flags = 0;
2759 return do_expr_walk (expr, walker, &data);
2763 * gnm_expr_is_empty:
2764 * @expr: #GnmExpr
2766 * Returns: %TRUE if @expr is a constant expression with the empty value.
2768 gboolean
2769 gnm_expr_is_empty (GnmExpr const *expr)
2771 g_return_val_if_fail (expr != NULL, FALSE);
2773 return (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_CONSTANT &&
2774 VALUE_IS_EMPTY (expr->constant.value));
2778 * gnm_expr_list_unref:
2779 * @list: (transfer full): expression list
2781 * This frees list and all the expressions in it.
2783 void
2784 gnm_expr_list_unref (GnmExprList *list)
2786 GnmExprList *l;
2787 for (l = list; l; l = l->next)
2788 gnm_expr_free (l->data);
2789 gnm_expr_list_free (list);
2793 * gnm_expr_list_copy:
2794 * @list: (transfer none): list of expressions
2796 * Returns: (transfer full): a copy of the list and all the
2797 * expressions in it.
2799 GnmExprList *
2800 gnm_expr_list_copy (GnmExprList *list)
2802 GnmExprList *res = g_slist_copy (list); /* shallow */
2803 GnmExprList *l;
2805 for (l = res; l; l = l->next)
2806 l->data = (GnmExpr *) gnm_expr_copy (l->data);
2808 return res;
2812 void
2813 gnm_expr_list_as_string (int argc,
2814 GnmExprConstPtr const *argv,
2815 GnmConventionsOut *out)
2817 int i;
2818 gunichar arg_sep;
2819 if (out->convs->arg_sep)
2820 arg_sep = out->convs->arg_sep;
2821 else
2822 arg_sep = go_locale_get_arg_sep ();
2824 g_string_append_c (out->accum, '(');
2825 for (i = 0; i < argc; i++) {
2826 if (i != 0)
2827 g_string_append_unichar (out->accum, arg_sep);
2828 do_expr_as_string (argv[i], 0, out);
2830 g_string_append_c (out->accum, ')');
2833 static guint
2834 gnm_expr_hash (GnmExpr const *expr)
2836 guint h = (guint)(GNM_EXPR_GET_OPER (expr));
2838 switch (GNM_EXPR_GET_OPER (expr)){
2839 case GNM_EXPR_OP_INTERSECT:
2840 case GNM_EXPR_OP_RANGE_CTOR:
2841 case GNM_EXPR_OP_ANY_BINARY:
2842 return ((gnm_expr_hash (expr->binary.value_a) * 7) ^
2843 (gnm_expr_hash (expr->binary.value_b) * 3) ^
2846 case GNM_EXPR_OP_ANY_UNARY:
2847 return ((gnm_expr_hash (expr->unary.value) * 7) ^
2850 case GNM_EXPR_OP_FUNCALL: {
2851 int i;
2852 for (i = 0; i < expr->func.argc; i++)
2853 h = (h * 3) ^ gnm_expr_hash (expr->func.argv[i]);
2854 return h;
2857 case GNM_EXPR_OP_SET: {
2858 int i;
2859 for (i = 0; i < expr->set.argc; i++)
2860 h = (h * 3) ^ gnm_expr_hash (expr->set.argv[i]);
2861 return h;
2864 case GNM_EXPR_OP_CONSTANT:
2865 return value_hash (expr->constant.value);
2867 case GNM_EXPR_OP_NAME:
2868 /* all we need is a somewhat unique hash, ignore int != ptr */
2869 return GPOINTER_TO_UINT (expr->name.name);
2871 case GNM_EXPR_OP_CELLREF:
2872 return gnm_cellref_hash (&expr->cellref.ref);
2874 case GNM_EXPR_OP_ARRAY_CORNER:
2875 return gnm_expr_hash (expr->array_corner.expr);
2877 case GNM_EXPR_OP_ARRAY_ELEM:
2878 return ((expr->array_elem.x << 16) ^
2879 (expr->array_elem.y));
2882 return h;
2886 /***************************************************************************/
2888 GnmExprSharer *
2889 gnm_expr_sharer_new (void)
2891 GnmExprSharer *es = g_new (GnmExprSharer, 1);
2892 es->nodes_in = 0;
2893 es->nodes_stored = 0;
2894 es->nodes_killed = 0;
2895 es->exprs = g_hash_table_new_full
2896 ((GHashFunc)gnm_expr_top_hash,
2897 (GEqualFunc)gnm_expr_top_equal,
2898 (GDestroyNotify)gnm_expr_top_unref,
2899 NULL);
2900 es->ref_count = 1;
2901 return es;
2904 void
2905 gnm_expr_sharer_destroy (GnmExprSharer *es)
2907 if (!es || es->ref_count-- > 1)
2908 return;
2909 g_hash_table_destroy (es->exprs);
2910 g_free (es);
2913 static GnmExprSharer *
2914 gnm_expr_sharer_ref (GnmExprSharer *es)
2916 es->ref_count++;
2917 return es;
2920 GType
2921 gnm_expr_sharer_get_type (void)
2923 static GType t = 0;
2925 if (t == 0) {
2926 t = g_boxed_type_register_static ("GnmExprSharer",
2927 (GBoxedCopyFunc)gnm_expr_sharer_ref,
2928 (GBoxedFreeFunc)gnm_expr_sharer_destroy);
2930 return t;
2933 GnmExprTop const *
2934 gnm_expr_sharer_share (GnmExprSharer *es, GnmExprTop const *texpr)
2936 GnmExprTop const *shared;
2938 g_return_val_if_fail (es != NULL, texpr);
2939 g_return_val_if_fail (texpr != NULL, NULL);
2941 es->nodes_in++;
2943 /* Corners must not get shared. */
2944 if (GNM_EXPR_GET_OPER (texpr->expr) == GNM_EXPR_OP_ARRAY_CORNER)
2945 return texpr;
2947 shared = g_hash_table_lookup (es->exprs, texpr);
2948 if (shared) {
2949 gnm_expr_top_ref (shared);
2950 if (texpr->refcount == 1)
2951 es->nodes_killed++;
2952 gnm_expr_top_unref (texpr);
2953 return shared;
2956 gnm_expr_top_ref (texpr);
2957 g_hash_table_insert (es->exprs, (gpointer)texpr, (gpointer)texpr);
2958 es->nodes_stored++;
2960 return texpr;
2963 void
2964 gnm_expr_sharer_report (GnmExprSharer *es)
2966 g_printerr ("Expressions in: %d\n", es->nodes_in);
2967 g_printerr ("Expressions stored: %d\n", es->nodes_stored);
2968 g_printerr ("Expressions killed: %d\n", es->nodes_killed);
2971 /***************************************************************************/
2973 GnmExprTop const *
2974 gnm_expr_top_new (GnmExpr const *expr)
2976 GnmExprTop *res;
2978 if (expr == NULL)
2979 return NULL;
2981 res = g_new (GnmExprTop, 1);
2982 res->magic = GNM_EXPR_TOP_MAGIC;
2983 res->hash = 0;
2984 res->refcount = 1;
2985 res->expr = expr;
2986 return res;
2989 GnmExprTop const *
2990 gnm_expr_top_new_constant (GnmValue *v)
2992 return gnm_expr_top_new (gnm_expr_new_constant (v));
2995 GnmExprTop const *
2996 gnm_expr_top_ref (GnmExprTop const *texpr)
2998 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
2999 ((GnmExprTop *)texpr)->refcount++;
3000 return texpr;
3003 void
3004 gnm_expr_top_unref (GnmExprTop const *texpr)
3006 g_return_if_fail (GNM_IS_EXPR_TOP (texpr));
3008 ((GnmExprTop *)texpr)->refcount--;
3009 if (texpr->refcount == 0) {
3010 gnm_expr_free (texpr->expr);
3011 ((GnmExprTop *)texpr)->magic = 0;
3012 g_free ((GnmExprTop *)texpr);
3016 GType
3017 gnm_expr_top_get_type (void)
3019 static GType t = 0;
3021 if (t == 0) {
3022 t = g_boxed_type_register_static ("GnmExprTop",
3023 (GBoxedCopyFunc)gnm_expr_top_ref,
3024 (GBoxedFreeFunc)gnm_expr_top_unref);
3026 return t;
3029 gboolean
3030 gnm_expr_top_is_shared (GnmExprTop const *texpr)
3032 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3034 return texpr->refcount > 1;
3037 GnmExprTop const *
3038 gnm_expr_top_new_array_corner (int cols, int rows, GnmExpr const *expr)
3040 return gnm_expr_top_new (gnm_expr_new_array_corner (cols, rows, expr));
3043 GnmExprTop const *
3044 gnm_expr_top_new_array_elem (int x, int y)
3046 return gnm_expr_top_new (gnm_expr_new_array_elem (x, y));
3049 static GnmExpr const *
3050 cb_get_ranges (GnmExpr const *expr, GnmExprWalk *data)
3052 GSList **pranges = data->user;
3054 /* There's no real reason to exclude names here, except that
3055 we used to do so. */
3056 if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_NAME) {
3057 GnmValue *v = gnm_expr_get_range (expr);
3058 if (v)
3059 *pranges = gnm_insert_unique_value (*pranges, v);
3062 return NULL;
3066 * gnm_expr_top_get_ranges:
3067 * @texpr:
3069 * A collect the set of GnmRanges in @expr.
3070 * Returns: (element-type GnmRange) (transfer full): a list of the unique
3071 * references Caller is responsible for releasing the list and the content.
3073 GSList *
3074 gnm_expr_top_get_ranges (GnmExprTop const *texpr)
3076 GSList *res = NULL;
3078 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3079 gnm_expr_walk (texpr->expr, cb_get_ranges, &res);
3080 return res;
3083 GnmValue *
3084 gnm_expr_top_get_range (GnmExprTop const *texpr)
3086 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3088 return gnm_expr_get_range (texpr->expr);
3091 char *
3092 gnm_expr_top_as_string (GnmExprTop const *texpr,
3093 GnmParsePos const *pp,
3094 GnmConventions const *convs)
3096 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3098 return gnm_expr_as_string (texpr->expr, pp, convs);
3101 void
3102 gnm_expr_top_as_gstring (GnmExprTop const *texpr,
3103 GnmConventionsOut *out)
3105 g_return_if_fail (GNM_IS_EXPR_TOP (texpr));
3106 g_return_if_fail (out != NULL);
3108 do_expr_as_string (texpr->expr, 0, out);
3111 guint
3112 gnm_expr_top_hash (GnmExprTop const *texpr)
3114 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), 0);
3116 if (texpr->hash == 0) {
3117 ((GnmExprTop *)texpr)->hash = gnm_expr_hash (texpr->expr);
3118 /* The following line tests the truncated value. */
3119 if (texpr->hash == 0)
3120 ((GnmExprTop *)texpr)->hash = 1;
3122 return texpr->hash;
3125 gboolean
3126 gnm_expr_top_equal (GnmExprTop const *te1, GnmExprTop const *te2)
3128 if (te1 == te2)
3129 return TRUE;
3130 if (te1 == NULL || te2 == NULL)
3131 return FALSE;
3133 g_return_val_if_fail (GNM_IS_EXPR_TOP (te1), FALSE);
3134 g_return_val_if_fail (GNM_IS_EXPR_TOP (te2), FALSE);
3136 if (te1->hash && te2->hash && te1->hash != te2->hash)
3137 return FALSE;
3139 return gnm_expr_equal (te1->expr, te2->expr);
3143 * gnm_expr_top_relocate:
3144 * @texpr: #GnmExprTop to fixup
3145 * @rinfo: #GnmExprRelocateInfo details of relocation
3146 * @ignore_rel: Do not adjust relative refs (for internal use when
3147 * relocating named expressions. Most callers will want FALSE.
3149 * GNM_EXPR_RELOCATE_INVALIDATE_SHEET:
3150 * Convert any references to sheets marked being_invalidated into #REF!
3151 * GNM_EXPR_RELOCATE_MOVE_RANGE,
3152 * Find any references to the specified area and adjust them by the
3153 * supplied deltas. Check for out of bounds conditions. Return NULL if
3154 * no change is required.
3155 * If the expression is within the range to be moved, its relative
3156 * references to cells outside the range are adjusted to reference the
3157 * same cell after the move.
3158 * GNM_EXPR_RELOCATE_COLS
3159 * GNM_EXPR_RELOCATE_ROWS
3162 GnmExprTop const *
3163 gnm_expr_top_relocate (GnmExprTop const *texpr,
3164 GnmExprRelocateInfo const *rinfo,
3165 gboolean ignore_rel)
3167 RelocInfoInternal rinfo_tmp;
3169 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3170 g_return_val_if_fail (NULL != rinfo, NULL);
3172 rinfo_tmp.details = rinfo;
3173 rinfo_tmp.check_rels = !ignore_rel;
3174 if (rinfo->reloc_type != GNM_EXPR_RELOCATE_INVALIDATE_SHEET)
3175 rinfo_tmp.from_inside = (rinfo->origin_sheet == rinfo->pos.sheet) &&
3176 range_contains (&rinfo->origin, rinfo->pos.eval.col, rinfo->pos.eval.row);
3178 return gnm_expr_top_new (gnm_expr_relocate (texpr->expr, &rinfo_tmp));
3182 * Convenience function to change an expression from one sheet to another.
3184 GnmExprTop const *
3185 gnm_expr_top_relocate_sheet (GnmExprTop const *texpr,
3186 Sheet const *src,
3187 Sheet const *dst)
3189 GnmExprRelocateInfo rinfo;
3190 GnmExprTop const *res;
3192 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3193 g_return_val_if_fail (IS_SHEET (src), NULL);
3194 g_return_val_if_fail (IS_SHEET (dst), NULL);
3196 rinfo.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE;
3197 rinfo.origin_sheet = (Sheet *)src;
3198 rinfo.target_sheet = (Sheet *)dst;
3199 rinfo.col_offset = rinfo.row_offset = 0;
3200 range_init_full_sheet (&rinfo.origin, src);
3201 /* Not sure what sheet to use, but it doesn't seem to matter. */
3202 parse_pos_init_sheet (&rinfo.pos, rinfo.target_sheet);
3204 res = gnm_expr_top_relocate (texpr, &rinfo, FALSE);
3205 if (!res) {
3206 if (gnm_expr_top_is_array_corner (texpr))
3207 res = gnm_expr_top_new (gnm_expr_copy (texpr->expr));
3208 else
3209 gnm_expr_top_ref ((res = texpr));
3212 return res;
3215 gboolean
3216 gnm_expr_top_contains_subtotal (GnmExprTop const *texpr)
3218 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3220 return gnm_expr_contains_subtotal (texpr->expr);
3223 static GnmExpr const *
3224 cb_is_volatile (GnmExpr const *expr, GnmExprWalk *data)
3226 gboolean *res = data->user;
3227 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL &&
3228 (gnm_func_get_flags (expr->func.func) & GNM_FUNC_VOLATILE)) {
3229 *res = TRUE;
3230 data->stop = TRUE;
3232 return NULL;
3235 gboolean
3236 gnm_expr_top_is_volatile (GnmExprTop const *texpr)
3238 gboolean res = FALSE;
3241 * An expression is volatile if it contains a call to a volatile
3242 * function, even in cases like IF(TRUE,12,RAND()) where the
3243 * volatile function won't even be reached.
3246 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3247 gnm_expr_walk (texpr->expr, cb_is_volatile, &res);
3248 return res;
3252 static GnmValue *
3253 gnm_expr_top_eval_array_corner (GnmExprTop const *texpr,
3254 GnmEvalPos const *pos,
3255 GnmExprEvalFlags flags)
3257 GnmExpr const *expr = texpr->expr;
3258 GnmEvalPos pos2;
3259 GnmValue *a;
3261 pos2 = *pos;
3262 pos2.array_texpr = texpr;
3263 a = gnm_expr_eval (expr->array_corner.expr, &pos2,
3264 flags | GNM_EXPR_EVAL_PERMIT_NON_SCALAR);
3266 value_release (expr->array_corner.value);
3268 /* Store real result (cast away const)*/
3269 ((GnmExpr*)expr)->array_corner.value = a;
3271 if (a != NULL &&
3272 (VALUE_IS_CELLRANGE (a) || VALUE_IS_ARRAY (a))) {
3273 if (value_area_get_width (a, pos) <= 0 ||
3274 value_area_get_height (a, pos) <= 0)
3275 return value_new_error_NA (pos);
3276 a = (GnmValue *)value_area_get_x_y (a, 0, 0, pos);
3278 return handle_empty ((a != NULL) ? value_dup (a) : NULL, flags);
3281 static GnmValue *
3282 gnm_expr_top_eval_array_elem (GnmExprTop const *texpr,
3283 GnmEvalPos const *pos,
3284 GnmExprEvalFlags flags)
3286 GnmExpr const *expr = texpr->expr;
3287 /* The upper left corner manages the recalc of the expr */
3288 GnmCell *corner = array_elem_get_corner (&expr->array_elem,
3289 pos->sheet, &pos->eval);
3290 GnmValue *a;
3292 if (!corner ||
3293 !gnm_expr_top_is_array_corner (corner->base.texpr)) {
3294 g_warning ("Funky array setup.");
3295 return handle_empty (NULL, flags);
3298 gnm_cell_eval (corner);
3299 a = gnm_expr_top_get_array_value (corner->base.texpr);
3300 if (a == NULL)
3301 return handle_empty (NULL, flags);
3303 if ((VALUE_IS_CELLRANGE (a) || VALUE_IS_ARRAY (a))) {
3304 int const num_x = value_area_get_width (a, pos);
3305 int const num_y = value_area_get_height (a, pos);
3306 int x = expr->array_elem.x;
3307 int y = expr->array_elem.y;
3309 /* Evaluate relative to the upper left corner */
3310 GnmEvalPos tmp_ep = *pos;
3311 tmp_ep.eval.col -= x;
3312 tmp_ep.eval.row -= y;
3314 /* If the src array is 1 element wide or tall we wrap */
3315 if (x >= 1 && num_x == 1)
3316 x = 0;
3317 if (y >= 1 && num_y == 1)
3318 y = 0;
3319 if (x >= num_x || y >= num_y)
3320 return value_new_error_NA (pos);
3322 a = (GnmValue *)value_area_get_x_y (a, x, y, &tmp_ep);
3325 return handle_empty ((a != NULL) ? value_dup (a) : NULL, flags);
3328 GnmValue *
3329 gnm_expr_top_eval (GnmExprTop const *texpr,
3330 GnmEvalPos const *pos,
3331 GnmExprEvalFlags flags)
3333 GnmValue *res;
3335 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3337 gnm_app_recalc_start ();
3339 if (gnm_expr_top_is_array_corner (texpr))
3340 res = gnm_expr_top_eval_array_corner (texpr, pos, flags);
3341 else if (gnm_expr_top_is_array_elem (texpr, NULL, NULL))
3342 res = gnm_expr_top_eval_array_elem (texpr, pos, flags);
3343 else if ((flags & GNM_EXPR_EVAL_ARRAY_CONTEXT) && !eval_pos_is_array_context (pos)) {
3344 // Array context out of the blue. Fake it.
3345 GnmEvalPos pos2;
3346 GnmExprTop const *fake = gnm_expr_top_new_array_corner (1, 1, NULL);
3347 ((GnmExpr *)(fake->expr))->array_corner.expr = texpr->expr; // Patch in our expr
3348 pos2 = *pos;
3349 pos2.array_texpr = fake;
3350 res = gnm_expr_eval (texpr->expr, &pos2, flags);
3351 ((GnmExpr *)(fake->expr))->array_corner.expr = NULL;
3352 gnm_expr_top_unref (fake);
3353 } else
3354 res = gnm_expr_eval (texpr->expr, pos, flags);
3355 gnm_app_recalc_finish ();
3357 return res;
3360 static GSList *
3361 gnm_insert_unique (GSList *list, gpointer data)
3363 if (g_slist_find (list, data) == NULL)
3364 return g_slist_prepend (list, data);
3365 return list;
3368 static GnmExpr const *
3369 cb_referenced_sheets (GnmExpr const *expr, GnmExprWalk *data)
3371 GSList **psheets = data->user;
3373 switch (GNM_EXPR_GET_OPER (expr)) {
3374 case GNM_EXPR_OP_CELLREF:
3375 *psheets = gnm_insert_unique (*psheets, expr->cellref.ref.sheet);
3376 break;
3378 case GNM_EXPR_OP_CONSTANT: {
3379 GnmValue const *v = expr->constant.value;
3380 if (!VALUE_IS_CELLRANGE (v))
3381 break;
3382 *psheets = gnm_insert_unique (*psheets, v->v_range.cell.a.sheet);
3383 /* A NULL b sheet means a's sheet. Do not insert that. */
3384 if (v->v_range.cell.b.sheet)
3385 *psheets = gnm_insert_unique (*psheets, v->v_range.cell.b.sheet);
3386 break;
3389 default:
3390 break;
3393 return NULL;
3397 * gnm_expr_top_referenced_sheets:
3398 * @texpr:
3400 * Generates a list of the sheets referenced by the supplied expression.
3401 * Caller must free the list. Note, that NULL may occur in the result
3402 * if the expression has a range or cellref without a sheet.
3403 * Returns: (element-type Sheet) (transfer container): the created list.
3405 GSList *
3406 gnm_expr_top_referenced_sheets (GnmExprTop const *texpr)
3408 GSList *res = NULL;
3410 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3411 gnm_expr_walk (texpr->expr, cb_referenced_sheets, &res);
3412 return res;
3415 gboolean
3416 gnm_expr_top_is_err (GnmExprTop const *texpr, GnmStdError err)
3418 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3419 return gnm_expr_is_err (texpr->expr, err);
3423 * gnm_expr_top_get_constant:
3424 * @texpr:
3426 * If this expression consists of just a constant, return it.
3428 GnmValue const *
3429 gnm_expr_top_get_constant (GnmExprTop const *texpr)
3431 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3433 return gnm_expr_get_constant (texpr->expr);
3436 GnmCellRef const *
3437 gnm_expr_top_get_cellref (GnmExprTop const *texpr)
3439 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3440 return gnm_expr_get_cellref (texpr->expr);
3443 static GnmExpr const *
3444 cb_first_funcall (GnmExpr const *expr, GnmExprWalk *data)
3446 GnmExprConstPtr *user = data->user;
3447 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_FUNCALL) {
3448 *user = expr;
3449 data->stop = TRUE;
3451 return NULL;
3455 * gnm_expr_top_first_funcall:
3456 * @texpr:
3459 GnmExpr const *
3460 gnm_expr_top_first_funcall (GnmExprTop const *texpr)
3462 GnmExpr const *res = NULL;
3464 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3465 gnm_expr_walk (texpr->expr, cb_first_funcall, &res);
3466 return res;
3469 struct cb_get_boundingbox {
3470 Sheet const *sheet;
3471 GnmRange *bound;
3474 static GnmExpr const *
3475 cb_get_boundingbox (GnmExpr const *expr, GnmExprWalk *data)
3477 struct cb_get_boundingbox *args = data->user;
3479 switch (GNM_EXPR_GET_OPER (expr)) {
3480 case GNM_EXPR_OP_CELLREF:
3481 cellref_boundingbox (&expr->cellref.ref, args->sheet, args->bound);
3482 break;
3484 case GNM_EXPR_OP_CONSTANT: {
3485 GnmValue const *v = expr->constant.value;
3487 if (VALUE_IS_CELLRANGE (v)) {
3488 cellref_boundingbox (&v->v_range.cell.a, args->sheet, args->bound);
3489 cellref_boundingbox (&v->v_range.cell.b, args->sheet, args->bound);
3491 break;
3494 default:
3495 break;
3498 return NULL;
3502 * gnm_expr_top_get_boundingbox:
3504 * Returns the range of cells in which the expression can be used without going
3505 * out of bounds.
3507 void
3508 gnm_expr_top_get_boundingbox (GnmExprTop const *texpr, Sheet const *sheet,
3509 GnmRange *bound)
3511 struct cb_get_boundingbox args;
3513 g_return_if_fail (GNM_IS_EXPR_TOP (texpr));
3515 range_init_full_sheet (bound, sheet);
3517 args.sheet = sheet;
3518 args.bound = bound;
3519 gnm_expr_walk (texpr->expr, cb_get_boundingbox, &args);
3522 gboolean
3523 gnm_expr_top_is_rangeref (GnmExprTop const *texpr)
3525 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3527 return gnm_expr_is_rangeref (texpr->expr);
3530 gboolean
3531 gnm_expr_top_is_array_corner (GnmExprTop const *texpr)
3533 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3534 return GNM_EXPR_GET_OPER (texpr->expr) == GNM_EXPR_OP_ARRAY_CORNER;
3537 void
3538 gnm_expr_top_get_array_size (GnmExprTop const *texpr, int *cols, int *rows)
3540 g_return_if_fail (GNM_IS_EXPR_TOP (texpr));
3541 g_return_if_fail (GNM_EXPR_GET_OPER (texpr->expr) == GNM_EXPR_OP_ARRAY_CORNER);
3543 if (cols)
3544 *cols = texpr->expr->array_corner.cols;
3545 if (rows)
3546 *rows = texpr->expr->array_corner.rows;
3549 GnmValue *
3550 gnm_expr_top_get_array_value (GnmExprTop const *texpr)
3552 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3553 g_return_val_if_fail (GNM_EXPR_GET_OPER (texpr->expr) == GNM_EXPR_OP_ARRAY_CORNER, NULL);
3554 return texpr->expr->array_corner.value;
3557 GnmExpr const *
3558 gnm_expr_top_get_array_expr (GnmExprTop const *texpr)
3560 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3561 g_return_val_if_fail (GNM_EXPR_GET_OPER (texpr->expr) == GNM_EXPR_OP_ARRAY_CORNER, NULL);
3562 return texpr->expr->array_corner.expr;
3565 gboolean
3566 gnm_expr_top_is_array_elem (GnmExprTop const *texpr, int *x, int *y)
3568 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3570 if (GNM_EXPR_GET_OPER (texpr->expr) != GNM_EXPR_OP_ARRAY_ELEM)
3571 return FALSE;
3573 if (x) *x = texpr->expr->array_elem.x;
3574 if (y) *y = texpr->expr->array_elem.y;
3575 return TRUE;
3578 gboolean
3579 gnm_expr_top_is_array (GnmExprTop const *texpr)
3581 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), FALSE);
3582 return gnm_expr_is_array (texpr->expr);
3585 GnmExprTop const *
3586 gnm_expr_top_transpose (GnmExprTop const *texpr)
3588 g_return_val_if_fail (GNM_IS_EXPR_TOP (texpr), NULL);
3589 switch (GNM_EXPR_GET_OPER (texpr->expr)) {
3590 case GNM_EXPR_OP_ARRAY_CORNER:
3591 /* Transpose size */
3592 return gnm_expr_top_new_array_corner
3593 (texpr->expr->array_corner.rows,
3594 texpr->expr->array_corner.cols,
3595 gnm_expr_copy (texpr->expr));
3596 case GNM_EXPR_OP_ARRAY_ELEM:
3597 /* Transpose coordinates */
3598 return gnm_expr_top_new_array_elem
3599 (texpr->expr->array_elem.y,
3600 texpr->expr->array_elem.x);
3601 default:
3602 return NULL;
3606 /****************************************************************************/
3608 #if USE_EXPR_POOLS
3609 typedef union {
3610 guint32 oper_and_refcount;
3611 GnmExprConstant constant;
3612 GnmExprFunction func;
3613 GnmExprUnary unary;
3614 GnmExprBinary binary;
3615 GnmExprArrayElem array_elem;
3616 GnmExprSet set;
3617 } GnmExprSmall;
3618 typedef union {
3619 guint32 oper_and_refcount;
3620 GnmExprName name;
3621 GnmExprCellRef cellref;
3622 GnmExprArrayCorner array_corner;
3623 } GnmExprBig;
3624 #endif
3627 * gnm_expr_init_: (skip)
3629 void
3630 gnm_expr_init_ (void)
3632 #if 0
3633 GnmExpr e;
3635 #if USE_EXPR_POOLS
3636 /* 12 is an excellent size for a pool. */
3637 g_print ("sizeof(GnmExprSmall) = %d\n", (int)sizeof (GnmExprSmall));
3638 g_print ("sizeof(GnmExprBig) = %d\n", (int)sizeof (GnmExprBig));
3639 #endif
3640 g_print ("sizeof(e.func) = %d\n", (int)sizeof (e.func));
3641 g_print ("sizeof(e.unary) = %d\n", (int)sizeof (e.unary));
3642 g_print ("sizeof(e.binary) = %d\n", (int)sizeof (e.binary));
3643 g_print ("sizeof(e.name) = %d\n", (int)sizeof (e.name));
3644 g_print ("sizeof(e.cellref) = %d\n", (int)sizeof (e.cellref));
3645 g_print ("sizeof(e.array_corner) = %d\n", (int)sizeof (e.array_corner));
3646 g_print ("sizeof(e.array_elem) = %d\n", (int)sizeof (e.array_elem));
3647 g_print ("sizeof(e.set) = %d\n", (int)sizeof (e.set));
3648 #endif
3649 #if USE_EXPR_POOLS
3650 expression_pool_small =
3651 go_mem_chunk_new ("expression pool for small nodes",
3652 sizeof (GnmExprSmall),
3653 16 * 1024 - 128);
3654 expression_pool_big =
3655 go_mem_chunk_new ("expression pool for big nodes",
3656 sizeof (GnmExprBig),
3657 16 * 1024 - 128);
3658 #endif
3661 #if USE_EXPR_POOLS
3662 static void
3663 cb_expression_pool_leak (gpointer data, G_GNUC_UNUSED gpointer user)
3665 GnmExpr const *expr = data;
3666 GnmParsePos pp;
3667 char *s;
3669 pp.eval.col = 0;
3670 pp.eval.row = 0;
3671 pp.sheet = NULL;
3672 pp.wb = NULL;
3673 s = gnm_expr_as_string (expr, &pp, NULL);
3674 g_printerr ("Leaking expression at %p: %s.\n", (void *)expr, s);
3675 g_free (s);
3677 #endif
3680 * gnm_expr_shutdown_: (skip)
3682 void
3683 gnm_expr_shutdown_ (void)
3685 #if USE_EXPR_POOLS
3686 go_mem_chunk_foreach_leak (expression_pool_small, cb_expression_pool_leak, NULL);
3687 go_mem_chunk_destroy (expression_pool_small, FALSE);
3688 expression_pool_small = NULL;
3690 go_mem_chunk_foreach_leak (expression_pool_big, cb_expression_pool_leak, NULL);
3691 go_mem_chunk_destroy (expression_pool_big, FALSE);
3692 expression_pool_big = NULL;
3693 #endif
3696 /****************************************************************************/