expr.c 75.6 KB
Newer Older
1
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
Miguel de Icaza's avatar
Miguel de Icaza committed
2
/*
3
 * expr.c : Expression evaluation in Gnumeric
Miguel de Icaza's avatar
Miguel de Icaza committed
4
 *
5
 * Copyright (C) 2001-2002 Jody Goldberg (jody@gnome.org)
6
 * Copyright (C) 1998-2000 Miguel de Icaza (miguel@gnu.org)
7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
J.H.M. Dassen (Ray)'s avatar
J.H.M. Dassen (Ray) committed
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
20
 * USA
Miguel de Icaza's avatar
Miguel de Icaza committed
21
 */
22
#include <gnumeric-config.h>
23
#include <glib/gi18n.h>
24
#include "gnumeric.h"
Arturo Espinosa's avatar
Arturo Espinosa committed
25
#include "expr.h"
26

27
#include "expr-impl.h"
28
#include "expr-name.h"
29
#include "dependent.h"
30
#include "gnm-format.h"
31
#include "func.h"
Jody Goldberg's avatar
Jody Goldberg committed
32
#include "cell.h"
Jody Goldberg's avatar
Jody Goldberg committed
33 34
#include "sheet.h"
#include "str.h"
35
#include "value.h"
36
#include "parse-util.h"
37
#include "ranges.h"
38
#include "number-match.h"
Jody Goldberg's avatar
Jody Goldberg committed
39
#include "workbook-priv.h"
Jeffrey Stedfast's avatar
Jeffrey Stedfast committed
40
#include "gutils.h"
41
#include "parse-util.h"
42
#include "mathfunc.h"
43

44 45
#include <math.h>
#include <string.h>
Jody Goldberg's avatar
Jody Goldberg committed
46
#include <stdlib.h>
Morten Welinder's avatar
Morten Welinder committed
47
#include <goffice/utils/go-glib-extras.h>
48

49 50 51 52 53 54 55 56 57
/*
 * Using pools here probably does not save anything, but it's a darn
 * good debugging tool.
 */
#ifndef USE_EXPR_POOLS
#define USE_EXPR_POOLS 1
#endif

#if USE_EXPR_POOLS
58 59
/* Memory pools for expressions.  */
static GOMemChunk *expression_pool_small, *expression_pool_big;
60 61
#define CHUNK_ALLOC(T,p) ((T*)go_mem_chunk_alloc (p))
#define CHUNK_FREE(p,v) go_mem_chunk_free ((p), (v))
62 63 64 65 66
#else
#define CHUNK_ALLOC(T,c) g_new (T,1)
#define CHUNK_FREE(p,v) g_free ((v))
#endif

67 68
/***************************************************************************/

Jody Goldberg's avatar
Jody Goldberg committed
69 70 71 72 73 74 75 76 77 78 79 80
#if 0
static guint
gnm_expr_constant_hash (GnmExprConstant const *expr)
{
	return value_hash (expr->value);
}
static gboolean
gnm_expr_constant_eq (GnmExprConstant const *a,
		      GnmExprConstant const *b)
{
}
#endif
Jody Goldberg's avatar
Jody Goldberg committed
81 82 83 84 85 86
/**
 * gnm_expr_new_constant :
 * @v :
 *
 * Absorbs the value.
 **/
87
GnmExpr const *
Jody Goldberg's avatar
Jody Goldberg committed
88
gnm_expr_new_constant (GnmValue *v)
89
{
90
	GnmExprConstant *ans;
91

92
	ans = CHUNK_ALLOC (GnmExprConstant, expression_pool_small);
93 94
	if (!ans)
		return NULL;
95
	gnm_expr_constant_init (ans, v);
96

97
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
98 99
}

Jody Goldberg's avatar
Jody Goldberg committed
100 101 102 103 104 105
/***************************************************************************/

#if 0
static guint
gnm_expr_function_hash (GnmExprFunction const *expr)
{
106
	guint h = GNM_EXPR_GET_OPER (expr);
Jody Goldberg's avatar
Jody Goldberg committed
107 108 109 110 111 112 113 114 115 116 117 118
	GnmExprList *l;
	for (l = expr->arg_list; l; l = l->next)
		h = (h * 3) ^ (GPOINTER_TO_INT (l->data));
	return h;
}
static gboolean
gnm_expr_function_eq (GnmExprFunction const *a,
		      GnmExprFunction const *b)
{
}
#endif

119
GnmExpr const *
120
gnm_expr_new_funcall (GnmFunc *func, GnmExprList *arg_list)
121
{
122
	GnmExprFunction *ans;
Jody Goldberg's avatar
Jody Goldberg committed
123
	g_return_val_if_fail (func, NULL);
124

125
	ans = CHUNK_ALLOC (GnmExprFunction, expression_pool_small);
126

127
	GNM_EXPR_SET_OPER_REF1 (ans, GNM_EXPR_OP_FUNCALL);
Jody Goldberg's avatar
Jody Goldberg committed
128
	gnm_func_ref (func);
129
	ans->func = func;
130 131
	ans->argc = gnm_expr_list_length (arg_list);
	if (arg_list) {
132
		GnmExprList *arg_list0 = arg_list;
133
		int i;
134
		ans->argv = g_new (GnmExprConstPtr, ans->argc);
135 136
		for (i = 0; arg_list; i++, arg_list = arg_list->next)
			ans->argv[i] = arg_list->data;
137
		gnm_expr_list_free (arg_list0);
138 139
	} else
		ans->argv = NULL;
140

141
	return (GnmExpr *)ans;
142
}
143

Morten Welinder's avatar
Morten Welinder committed
144 145 146 147 148 149 150 151 152 153 154 155
GnmExpr const *
gnm_expr_new_funcall1 (GnmFunc *func,
		       GnmExpr const *arg0)
{
	GnmExprFunction *ans;
	g_return_val_if_fail (func, NULL);

	ans = CHUNK_ALLOC (GnmExprFunction, expression_pool_small);
	GNM_EXPR_SET_OPER_REF1 (ans, GNM_EXPR_OP_FUNCALL);
	gnm_func_ref (func);
	ans->func = func;
	ans->argc = 1;
156
	ans->argv = g_new (GnmExprConstPtr, 1);
Morten Welinder's avatar
Morten Welinder committed
157
	ans->argv[0] = arg0;
158
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
}

GnmExpr const *
gnm_expr_new_funcall2 (GnmFunc *func,
		       GnmExpr const *arg0,
		       GnmExpr const *arg1)
{
	GnmExprFunction *ans;
	g_return_val_if_fail (func, NULL);

	ans = CHUNK_ALLOC (GnmExprFunction, expression_pool_small);
	GNM_EXPR_SET_OPER_REF1 (ans, GNM_EXPR_OP_FUNCALL);
	gnm_func_ref (func);
	ans->func = func;
	ans->argc = 2;
174
	ans->argv = g_new (GnmExprConstPtr, 2);
Morten Welinder's avatar
Morten Welinder committed
175 176
	ans->argv[0] = arg0;
	ans->argv[1] = arg1;
177
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
}

GnmExpr const *
gnm_expr_new_funcall3 (GnmFunc *func,
		       GnmExpr const *arg0,
		       GnmExpr const *arg1,
		       GnmExpr const *arg2)
{
	GnmExprFunction *ans;
	g_return_val_if_fail (func, NULL);

	ans = CHUNK_ALLOC (GnmExprFunction, expression_pool_small);
	GNM_EXPR_SET_OPER_REF1 (ans, GNM_EXPR_OP_FUNCALL);
	gnm_func_ref (func);
	ans->func = func;
	ans->argc = 3;
194
	ans->argv = g_new (GnmExprConstPtr, 3);
Morten Welinder's avatar
Morten Welinder committed
195 196 197
	ans->argv[0] = arg0;
	ans->argv[1] = arg1;
	ans->argv[2] = arg2;
198
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
199 200 201
}


Jody Goldberg's avatar
Jody Goldberg committed
202 203 204 205 206 207 208
/***************************************************************************/

#if 0
static guint
gnm_expr_unary_hash (GnmExprUnary const *expr)
{
	return  (GPOINTER_TO_INT (expr->value) * 7) ^
209
		(guint)GNM_EXPR_GET_OPER (expr);
Jody Goldberg's avatar
Jody Goldberg committed
210 211 212 213 214
}
static gboolean
gnm_expr_unary_eq (GnmExprUnary const *a,
		   GnmExprUnary const *b)
{
215 216
	return GNM_EXPR_GET_OPER (a) == GNM_EXPR_GET_OPER (b) &&
		a->value == b->value;
Jody Goldberg's avatar
Jody Goldberg committed
217 218 219
}
#endif

220 221
GnmExpr const *
gnm_expr_new_unary  (GnmExprOp op, GnmExpr const *e)
Morten Welinder's avatar
Morten Welinder committed
222
{
223
	GnmExprUnary *ans;
Morten Welinder's avatar
Morten Welinder committed
224

225
	ans = CHUNK_ALLOC (GnmExprUnary, expression_pool_small);
226 227 228
	if (!ans)
		return NULL;

229
	GNM_EXPR_SET_OPER_REF1 (ans, op);
230
	ans->value = e;
231

232
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
233 234
}

Jody Goldberg's avatar
Jody Goldberg committed
235 236 237 238 239 240 241 242
/***************************************************************************/

#if 0
static guint
gnm_expr_binary_hash (GnmExprBinary const *expr)
{
	return  (GPOINTER_TO_INT (expr->value_a) * 7) ^
		(GPOINTER_TO_INT (expr->value_b) * 3) ^
243
		(guint)(GNM_EXPR_GET_OPER (expr));
Jody Goldberg's avatar
Jody Goldberg committed
244 245
}
#endif
Morten Welinder's avatar
Morten Welinder committed
246

247 248
GnmExpr const *
gnm_expr_new_binary (GnmExpr const *l, GnmExprOp op, GnmExpr const *r)
Morten Welinder's avatar
Morten Welinder committed
249
{
250
	GnmExprBinary *ans;
Morten Welinder's avatar
Morten Welinder committed
251

252
	ans = CHUNK_ALLOC (GnmExprBinary, expression_pool_small);
253 254
	if (!ans)
		return NULL;
255

256
	GNM_EXPR_SET_OPER_REF1 (ans, op);
257 258
	ans->value_a = l;
	ans->value_b = r;
259

260
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
261 262
}

Jody Goldberg's avatar
Jody Goldberg committed
263 264 265 266 267 268 269 270 271 272
/***************************************************************************/

#if 0
static guint
gnm_expr_name_hash (GnmExprName const *expr)
{
	return GPOINTER_TO_INT (expr->name);
}
#endif

273 274
GnmExpr const *
gnm_expr_new_name (GnmNamedExpr *name,
275
		   Sheet *optional_scope, Workbook *optional_wb_scope)
Morten Welinder's avatar
Morten Welinder committed
276
{
277
	GnmExprName *ans;
Morten Welinder's avatar
Morten Welinder committed
278

279
	ans = CHUNK_ALLOC (GnmExprName, expression_pool_big);
280 281
	if (!ans)
		return NULL;
282

283
	GNM_EXPR_SET_OPER_REF1 (ans, GNM_EXPR_OP_NAME);
284
	ans->name = name;
285
	expr_name_ref (name);
286

287 288 289
	ans->optional_scope = optional_scope;
	ans->optional_wb_scope = optional_wb_scope;

290
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
291
}
292

Jody Goldberg's avatar
Jody Goldberg committed
293 294 295 296 297 298 299 300 301
/***************************************************************************/

#if 0
static guint
gnm_expr_cellref_hash (GnmExprCellRef const *expr)
{
}
#endif

302
GnmExpr const *
Jody Goldberg's avatar
Jody Goldberg committed
303
gnm_expr_new_cellref (GnmCellRef const *cr)
304
{
305
	GnmExprCellRef *ans;
306

307
	ans = CHUNK_ALLOC (GnmExprCellRef, expression_pool_big);
308 309
	if (!ans)
		return NULL;
310

311
	GNM_EXPR_SET_OPER_REF1 (ans, GNM_EXPR_OP_CELLREF);
312 313
	ans->ref = *cr;

314
	return (GnmExpr *)ans;
315 316
}

Jody Goldberg's avatar
Jody Goldberg committed
317 318 319 320 321 322 323 324 325 326
/***************************************************************************/

#if 0
static guint
gnm_expr_array_hash (GnmExprArray const *expr)
{
}
#endif

/**
327
 * gnm_expr_new_array_corner :
Jody Goldberg's avatar
Jody Goldberg committed
328 329 330 331 332 333
 * @cols :
 * @rows :
 * @expr : optionally NULL.
 *
 * Absorb a referernce to @expr if it is non NULL.
 **/
334
GnmExpr const *
335
gnm_expr_new_array_corner(int cols, int rows, GnmExpr const *expr)
336
{
337
	GnmExprArrayCorner *ans;
338

339
	ans = CHUNK_ALLOC (GnmExprArrayCorner, expression_pool_big);
340 341
	if (ans == NULL)
		return NULL;
342

343
	GNM_EXPR_SET_OPER_REF1 (ans, GNM_EXPR_OP_ARRAY_CORNER);
344 345
	ans->rows = rows;
	ans->cols = cols;
346 347 348 349 350 351 352 353 354 355
	ans->value = NULL;
	ans->expr = expr;
	return (GnmExpr *)ans;
}

GnmExpr const *
gnm_expr_new_array_elem  (int x, int y)
{
	GnmExprArrayElem *ans;

356
	ans = CHUNK_ALLOC (GnmExprArrayElem, expression_pool_small);
357 358 359
	if (ans == NULL)
		return NULL;

360
	GNM_EXPR_SET_OPER_REF1 (ans, GNM_EXPR_OP_ARRAY_ELEM);
361 362
	ans->x = x;
	ans->y = y;
363
	return (GnmExpr *)ans;
364 365
}

Jody Goldberg's avatar
Jody Goldberg committed
366 367 368 369 370 371
/***************************************************************************/

#if 0
static guint
gnm_expr_set_hash (GnmExprSet const *expr)
{
372
	guint h = GNM_EXPR_GET_OPER (expr);
Jody Goldberg's avatar
Jody Goldberg committed
373 374 375 376 377 378 379
	GnmExprList *l;
	for (l = expr->set; l; l = l->next)
		h = (h * 3) ^ (GPOINTER_TO_INT (l->data));
	return h;
}
#endif

380 381
GnmExpr const *
gnm_expr_new_set (GnmExprList *set)
382
{
383
	GnmExprSet *ans = CHUNK_ALLOC (GnmExprSet, expression_pool_small);
384

385
	GNM_EXPR_SET_OPER_REF1 (ans, GNM_EXPR_OP_SET);
386 387
	ans->argc = gnm_expr_list_length (set);
	if (set) {
388
		GnmExprList *set0 = set;
389
		int i;
390
		ans->argv = g_new (GnmExprConstPtr, ans->argc);
391 392
		for (i = 0; set; i++, set = set->next)
			ans->argv[i] = set->data;
393
		gnm_expr_list_free (set0);
394 395
	} else
		ans->argv = NULL;
396

397
	return (GnmExpr *)ans;
398 399
}

Jody Goldberg's avatar
Jody Goldberg committed
400 401
/***************************************************************************/

402 403 404
/**
 * gnm_expr_ref:
 * Increments the ref_count for an expression node.
Arturo Espinosa's avatar
Arturo Espinosa committed
405
 */
406
void
407
gnm_expr_ref (GnmExpr const *expr)
408
{
409
	g_return_if_fail (expr != NULL);
410
	g_return_if_fail (GNM_EXPR_GET_REFCOUNT (expr) > 0);
411

412 413
	/* We're screwed if the refcount overflows.  */
	((GnmExpr *)expr)->oper_and_refcount++;
Arturo Espinosa's avatar
Arturo Espinosa committed
414 415 416
}

static void
417
do_gnm_expr_unref (GnmExpr const *expr)
Arturo Espinosa's avatar
Arturo Espinosa committed
418
{
419 420 421 422
	/* We're screwed if the refcount underflows.  */
	((GnmExpr *)expr)->oper_and_refcount--;

	if (GNM_EXPR_GET_REFCOUNT (expr) > 0)
Morten Welinder's avatar
Morten Welinder committed
423 424
		return;

425
	switch (GNM_EXPR_GET_OPER (expr)) {
426
	case GNM_EXPR_OP_RANGE_CTOR:
427
	case GNM_EXPR_OP_INTERSECT:
428 429 430
	case GNM_EXPR_OP_ANY_BINARY:
		do_gnm_expr_unref (expr->binary.value_a);
		do_gnm_expr_unref (expr->binary.value_b);
431
		CHUNK_FREE (expression_pool_small, (gpointer)expr);
Arturo Espinosa's avatar
Arturo Espinosa committed
432
		break;
433

434 435 436 437 438
	case GNM_EXPR_OP_FUNCALL: {
		int i;

		for (i = 0; i < expr->func.argc; i++)
			do_gnm_expr_unref (expr->func.argv[i]);
Morten Welinder's avatar
Morten Welinder committed
439
		g_free (expr->func.argv);
Jody Goldberg's avatar
Jody Goldberg committed
440
		gnm_func_unref (expr->func.func);
441
		CHUNK_FREE (expression_pool_small, (gpointer)expr);
Arturo Espinosa's avatar
Arturo Espinosa committed
442
		break;
443
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
444

445
	case GNM_EXPR_OP_NAME:
446
		expr_name_unref (expr->name.name);
447
		CHUNK_FREE (expression_pool_big, (gpointer)expr);
Michael Meeks's avatar
Michael Meeks committed
448 449
		break;

450
	case GNM_EXPR_OP_CONSTANT:
Jody Goldberg's avatar
Jody Goldberg committed
451
		value_release ((GnmValue *)expr->constant.value);
452
		CHUNK_FREE (expression_pool_small, (gpointer)expr);
453 454 455
		break;

	case GNM_EXPR_OP_CELLREF:
456
		CHUNK_FREE (expression_pool_big, (gpointer)expr);
Arturo Espinosa's avatar
Arturo Espinosa committed
457 458
		break;

459 460
	case GNM_EXPR_OP_ANY_UNARY:
		do_gnm_expr_unref (expr->unary.value);
461
		CHUNK_FREE (expression_pool_small, (gpointer)expr);
Arturo Espinosa's avatar
Arturo Espinosa committed
462
		break;
463

464 465 466 467
	case GNM_EXPR_OP_ARRAY_CORNER:
		if (expr->array_corner.value)
			value_release (expr->array_corner.value);
		do_gnm_expr_unref (expr->array_corner.expr);
468
		CHUNK_FREE (expression_pool_big, (gpointer)expr);
469 470 471
		break;

	case GNM_EXPR_OP_ARRAY_ELEM:
472
		CHUNK_FREE (expression_pool_small, (gpointer)expr);
Jody Goldberg's avatar
Jody Goldberg committed
473
		break;
474

475 476 477 478 479
	case GNM_EXPR_OP_SET: {
		int i;

		for (i = 0; i < expr->set.argc; i++)
			do_gnm_expr_unref (expr->set.argv[i]);
Morten Welinder's avatar
Morten Welinder committed
480
		g_free (expr->set.argv);
481
		CHUNK_FREE (expression_pool_small, (gpointer)expr);
482
		break;
483
	}
484 485

#ifndef DEBUG_SWITCH_ENUM
486
	default:
487
		g_assert_not_reached ();
488
		break;
489
#endif
Arturo Espinosa's avatar
Arturo Espinosa committed
490
	}
491 492
}

Morten Welinder's avatar
Morten Welinder committed
493
/*
494 495
 * gnm_expr_unref:
 * Decrements the ref_count for part of a expression.  (All trees are expected
Morten Welinder's avatar
Morten Welinder committed
496 497 498
 * to have been created with a ref-count of one, so when we hit zero, we
 * go down over the tree and unref the tree and its leaves stuff.)
 */
499
void
500
gnm_expr_unref (GnmExpr const *expr)
501
{
502
	g_return_if_fail (expr != NULL);
503
	g_return_if_fail (GNM_EXPR_GET_REFCOUNT (expr) > 0);
504

505
	if (GNM_EXPR_GET_REFCOUNT (expr) == 1)
506
		do_gnm_expr_unref (expr);
507
	else
508
		((GnmExpr *)expr)->oper_and_refcount--;
509 510
}

Jody Goldberg's avatar
Jody Goldberg committed
511
/**
512
 * gnm_expr_is_shared : Returns TRUE if the reference count
Jody Goldberg's avatar
Jody Goldberg committed
513 514 515
 *   for the supplied expression is > 1
 */
gboolean
516
gnm_expr_is_shared (GnmExpr const *expr)
Jody Goldberg's avatar
Jody Goldberg committed
517
{
518
	g_return_val_if_fail (expr != NULL, FALSE);
Jody Goldberg's avatar
Jody Goldberg committed
519

520
	return (GNM_EXPR_GET_REFCOUNT (expr) > 1);
Jody Goldberg's avatar
Jody Goldberg committed
521 522
}

Jody Goldberg's avatar
Jody Goldberg committed
523
/**
524
 * gnm_expr_equal : Returns TRUE if the supplied expressions are exactly the
Jody Goldberg's avatar
Jody Goldberg committed
525 526 527 528 529
 *   same.  No eval position is used to see if they are effectively the same.
 *   Named expressions must refer the the same name, having equivalent names is
 *   insufficeient.
 */
gboolean
530
gnm_expr_equal (GnmExpr const *a, GnmExpr const *b)
Jody Goldberg's avatar
Jody Goldberg committed
531 532 533 534 535 536 537
{
	if (a == b)
		return TRUE;

	g_return_val_if_fail (a != NULL, FALSE);
	g_return_val_if_fail (b != NULL, FALSE);

538
	if (GNM_EXPR_GET_OPER (a) != GNM_EXPR_GET_OPER (b))
Jody Goldberg's avatar
Jody Goldberg committed
539 540
		return FALSE;

541
	switch (GNM_EXPR_GET_OPER (a)) {
542
	case GNM_EXPR_OP_RANGE_CTOR:
543
	case GNM_EXPR_OP_INTERSECT:
544 545 546
	case GNM_EXPR_OP_ANY_BINARY:
		return	gnm_expr_equal (a->binary.value_a, b->binary.value_a) &&
			gnm_expr_equal (a->binary.value_b, b->binary.value_b);
Jody Goldberg's avatar
Jody Goldberg committed
547

548 549
	case GNM_EXPR_OP_ANY_UNARY:
		return gnm_expr_equal (a->unary.value, b->unary.value);
Jody Goldberg's avatar
Jody Goldberg committed
550

551 552 553 554 555 556 557 558 559 560 561 562
	case GNM_EXPR_OP_FUNCALL: {
		int i;

		if (a->func.func != b->func.func ||
		    a->func.argc != b->func.argc)
			return FALSE;

		for (i = 0; i < a->func.argc; i++)
			if (!gnm_expr_equal (a->func.argv[i], b->func.argv[i]))
				return FALSE;
		return TRUE;
	}
Jody Goldberg's avatar
Jody Goldberg committed
563

564
	case GNM_EXPR_OP_NAME:
565 566 567
		return	a->name.name == b->name.name &&
			a->name.optional_scope == b->name.optional_scope &&
			a->name.optional_wb_scope == b->name.optional_wb_scope;
Jody Goldberg's avatar
Jody Goldberg committed
568

569
	case GNM_EXPR_OP_CELLREF:
570
		return gnm_cellref_equal (&a->cellref.ref, &b->cellref.ref);
Jody Goldberg's avatar
Jody Goldberg committed
571

572 573
	case GNM_EXPR_OP_CONSTANT:
		return value_equal (a->constant.value, b->constant.value);
Jody Goldberg's avatar
Jody Goldberg committed
574

575 576 577
	case GNM_EXPR_OP_ARRAY_CORNER: {
		GnmExprArrayCorner const *aa = &a->array_corner;
		GnmExprArrayCorner const *ab = &b->array_corner;
Jody Goldberg's avatar
Jody Goldberg committed
578 579 580

		return	aa->cols == ab->cols &&
			aa->rows == ab->rows &&
581 582 583 584 585 586
			gnm_expr_equal (aa->expr, ab->expr);
	}
	case GNM_EXPR_OP_ARRAY_ELEM: {
		GnmExprArrayElem const *aa = &a->array_elem;
		GnmExprArrayElem const *ab = &b->array_elem;
		return	aa->x == ab->x && aa->y == ab->y;
Jody Goldberg's avatar
Jody Goldberg committed
587 588
	}

589 590 591 592 593 594 595 596 597 598 599
	case GNM_EXPR_OP_SET: {
		int i;

		if (a->set.argc != b->set.argc)
			return FALSE;

		for (i = 0; i < a->set.argc; i++)
			if (!gnm_expr_equal (a->set.argv[i], b->set.argv[i]))
				return FALSE;
		return TRUE;
	}
Jody Goldberg's avatar
Jody Goldberg committed
600 601 602 603 604
	}

	return FALSE;
}

605
static GnmCell *
606 607
array_elem_get_corner (GnmExprArrayElem const *elem,
		       Sheet const *sheet, GnmCellPos const *pos)
608
{
609
	GnmCell *corner = sheet_cell_get (sheet,
610
		pos->col - elem->x, pos->row - elem->y);
611 612 613 614 615

	/* Sanity check incase the corner gets removed for some reason */
	g_return_val_if_fail (corner != NULL, NULL);
	g_return_val_if_fail (cell_has_expr (corner), NULL);
	g_return_val_if_fail (corner->base.expression != (void *)0xdeadbeef, NULL);
616
	g_return_val_if_fail (GNM_EXPR_GET_OPER (corner->base.expression) == GNM_EXPR_OP_ARRAY_CORNER, NULL);
617 618 619 620 621

	return corner;
}

static gboolean
Jody Goldberg's avatar
Jody Goldberg committed
622
gnm_expr_extract_ref (GnmRangeRef *res, GnmExpr const *expr,
Morten Welinder's avatar
Morten Welinder committed
623
		      GnmEvalPos const *pos, GnmExprEvalFlags flags)
624
{
625
	switch (GNM_EXPR_GET_OPER (expr)) {
626 627
	case GNM_EXPR_OP_FUNCALL : {
		gboolean failed = TRUE;
Jody Goldberg's avatar
Jody Goldberg committed
628
		GnmValue *v;
629 630
		FunctionEvalInfo ei;
		ei.pos = pos;
631
		ei.func_call = &expr->func;
632

633 634 635 636
		v = function_call_with_exprs (&ei,
					      expr->func.argc,
					      expr->func.argv,
					      flags);
637
		if (v != NULL) {
Jody Goldberg's avatar
Jody Goldberg committed
638 639
			if (v->type == VALUE_CELLRANGE) {
				*res = v->v_range.cell;
640 641 642 643 644 645 646 647
				failed = FALSE;
			}
			value_release (v);
		}
		return failed;
	}

	case GNM_EXPR_OP_CELLREF :
Jody Goldberg's avatar
Jody Goldberg committed
648 649
		res->a = expr->cellref.ref;
		res->b = expr->cellref.ref;
650 651 652
		return FALSE;

	case GNM_EXPR_OP_CONSTANT: {
Jody Goldberg's avatar
Jody Goldberg committed
653
		GnmValue const *v = expr->constant.value;
Jody Goldberg's avatar
Jody Goldberg committed
654 655
		if (v->type == VALUE_CELLRANGE) {
			*res = v->v_range.cell;
656 657 658 659 660 661
			return FALSE;
		}
		return TRUE;
	}

	case GNM_EXPR_OP_NAME:
662
		if (!expr->name.name->active)
663
			return TRUE;
664
		return gnm_expr_extract_ref (res, expr->name.name->expr, pos, flags);
665 666 667 668 669 670
	default :
		break;
	}
	return TRUE;
}

Jody Goldberg's avatar
Jody Goldberg committed
671 672
static inline GnmValue *
handle_empty (GnmValue *res, GnmExprEvalFlags flags)
673 674 675 676 677 678 679 680 681 682 683 684 685
{
	if (res == NULL)
		return (flags & GNM_EXPR_EVAL_PERMIT_EMPTY)
		    ? NULL : value_new_int (0);

	if (res->type == VALUE_EMPTY) {
		value_release (res);
		return (flags & GNM_EXPR_EVAL_PERMIT_EMPTY)
		    ? NULL : value_new_int (0);
	}
	return res;
}

Jody Goldberg's avatar
Jody Goldberg committed
686 687
/**
 * value_intersection :
688
 * @v   : a VALUE_CELLRANGE or VALUE_ARRAY
Morten Welinder's avatar
Morten Welinder committed
689
 * @pos :
Jody Goldberg's avatar
Jody Goldberg committed
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
 *
 * Handle the implicit union of a single row or column with the eval position.
 *
 * NOTE : We do not need to know if this is expression is being evaluated as an
 * array or not because we can differentiate based on the required type for the
 * argument.
 *
 * Always release the value passed in.
 *
 * Return value:
 *     If the intersection succeeded return a duplicate of the value
 *     at the intersection point.  This value needs to be freed.
 *     NULL if there is no intersection
 * Returns the upper left corner of an array.
 **/
Jody Goldberg's avatar
Jody Goldberg committed
705
static GnmValue *
Morten Welinder's avatar
Morten Welinder committed
706
value_intersection (GnmValue *v, GnmEvalPos const *pos)
Jody Goldberg's avatar
Jody Goldberg committed
707
{
Jody Goldberg's avatar
Jody Goldberg committed
708 709
	GnmValue *res = NULL;
	GnmRange r;
Jody Goldberg's avatar
Jody Goldberg committed
710 711 712 713
	Sheet *start_sheet, *end_sheet;
	gboolean found = FALSE;

	if (v->type == VALUE_ARRAY) {
714
		res = value_dup (v->v_array.vals[0][0]);
Jody Goldberg's avatar
Jody Goldberg committed
715 716 717 718 719
		value_release (v);
		return res;
	}

	/* inverted ranges */
720
	gnm_rangeref_normalize (&v->v_range.cell, pos, &start_sheet, &end_sheet, &r);
Jody Goldberg's avatar
Jody Goldberg committed
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
	value_release (v);

	if (start_sheet == end_sheet || end_sheet == NULL) {
		int col = pos->eval.col;
		int row = pos->eval.row;

		if (r.start.row == r.end.row) {
			if (r.start.col <= col && col <= r.end.col) {
				row = r.start.row;
				found = TRUE;
			} else if (r.start.col == r.end.col) {
				col = r.start.col;
				row = r.start.row;
				found = TRUE;
			}
		} else if (r.start.col == r.end.col) {
			if (r.start.row <= row && row <= r.end.row) {
				col = r.start.col;
				found = TRUE;
			}
		}
		if (found) {
743
			GnmCell *cell = sheet_cell_get (
Jody Goldberg's avatar
Jody Goldberg committed
744 745 746 747 748
				eval_sheet (start_sheet, pos->sheet),
				col, row);
			if (cell == NULL)
				return value_new_empty ();
			cell_eval (cell);
749
			return value_dup (cell->value);
Jody Goldberg's avatar
Jody Goldberg committed
750 751 752
		}
	}

753
	return value_new_error_VALUE (pos);
Jody Goldberg's avatar
Jody Goldberg committed
754
}
755

Jody Goldberg's avatar
Jody Goldberg committed
756
static GnmValue *
757 758
bin_arith (GnmExpr const *expr, GnmEvalPos const *ep,
	   GnmValue const *a, GnmValue const *b)
Jody Goldberg's avatar
Jody Goldberg committed
759
{
760 761 762 763 764 765 766 767
	if (a->type != VALUE_FLOAT && b->type != VALUE_FLOAT){
		int ia = value_get_as_int (a);
		int ib = value_get_as_int (b);
		gnm_float dres;
		int ires;

		/* FIXME: we could use simple (cheap) heuristics to
		   catch most cases where overflow will not happen.  */
768
		switch (GNM_EXPR_GET_OPER (expr)){
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
		case GNM_EXPR_OP_ADD:
			dres = (gnm_float)ia + (gnm_float)ib;
			break;

		case GNM_EXPR_OP_SUB:
			dres = (gnm_float)ia - (gnm_float)ib;
			break;

		case GNM_EXPR_OP_MULT:
			dres = (gnm_float)ia * (gnm_float)ib;
			break;

		case GNM_EXPR_OP_DIV:
			if (ib == 0)
				return value_new_error_DIV0 (ep);
			dres = (gnm_float)ia / (gnm_float)ib;
			break;

		case GNM_EXPR_OP_EXP:
			if (ia == 0 && ib <= 0)
				return value_new_error_NUM (ep);
790 791
			dres = gnm_pow ((gnm_float)ia, (gnm_float)ib);
			if (!gnm_finite (dres))
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
				return value_new_error_NUM (ep);
			break;

		default:
			abort ();
		}

		ires = (int)dres;
		if (dres == ires)
			return value_new_int (ires);
		else
			return value_new_float (dres);
	} else {
		gnm_float const va = value_get_as_float (a);
		gnm_float const vb = value_get_as_float (b);

808
		switch (GNM_EXPR_GET_OPER (expr)){
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
		case GNM_EXPR_OP_ADD:
			return value_new_float (va + vb);

		case GNM_EXPR_OP_SUB:
			return value_new_float (va - vb);

		case GNM_EXPR_OP_MULT:
			return value_new_float (va * vb);

		case GNM_EXPR_OP_DIV:
			return (vb == 0.0)
				? value_new_error_DIV0 (ep)
				: value_new_float (va / vb);

		case GNM_EXPR_OP_EXP: {
			gnm_float res;
			if ((va == 0 && vb <= 0) ||
			    (va < 0 && vb != (int)vb))
				return value_new_error_NUM (ep);

829 830
			res = gnm_pow (va, vb);
			return gnm_finite (res)
831 832 833 834 835 836 837 838 839
				? value_new_float (res)
				: value_new_error_NUM (ep);
		}

		default:
			break;
		}
	}
	return value_new_error (ep, _("Unknown operator"));
Jody Goldberg's avatar
Jody Goldberg committed
840 841
}

Jody Goldberg's avatar
Jody Goldberg committed
842
static GnmValue *
843
bin_cmp (GnmExprOp op, GnmValDiff comp, GnmEvalPos const *ep)
844 845 846 847 848 849 850 851 852 853 854
{
	if (comp == TYPE_MISMATCH) {
		/* TODO TODO TODO : Make error more informative
		 *    regarding what is comparing to what
		 */
		/* For equality comparisons even errors are ok */
		if (op == GNM_EXPR_OP_EQUAL)
			return value_new_bool (FALSE);
		if (op == GNM_EXPR_OP_NOT_EQUAL)
			return value_new_bool (TRUE);

855
		return value_new_error_VALUE (ep);
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
	}

	switch (op) {
	case GNM_EXPR_OP_EQUAL:     return value_new_bool (comp == IS_EQUAL);
	case GNM_EXPR_OP_GT:	    return value_new_bool (comp == IS_GREATER);
	case GNM_EXPR_OP_LT:	    return value_new_bool (comp == IS_LESS);
	case GNM_EXPR_OP_NOT_EQUAL: return value_new_bool (comp != IS_EQUAL);
	case GNM_EXPR_OP_LTE: 	    return value_new_bool (comp != IS_GREATER);
	case GNM_EXPR_OP_GTE:	    return value_new_bool (comp != IS_LESS);

#ifndef DEBUG_SWITCH_ENUM
	default:
		g_assert_not_reached ();
#endif
	}
871
	return value_new_error (ep, _("Internal type error"));
872 873
}

Jody Goldberg's avatar
Jody Goldberg committed
874
static GnmValue *
875 876
cb_bin_cmp (GnmEvalPos const *ep, GnmValue const *a, GnmValue const *b,
	    GnmExpr const *expr)
877
{
878 879 880 881
	if (a != NULL && a->type == VALUE_ERROR)
		return value_dup (a);
	if (b != NULL && b->type == VALUE_ERROR)
		return value_dup (b);
882
	return bin_cmp (GNM_EXPR_GET_OPER (expr), value_compare (a, b, FALSE), ep);
883 884 885 886 887 888 889 890 891 892 893 894
}

static GnmValue *
cb_bin_arith (GnmEvalPos const *ep, GnmValue const *a, GnmValue const *b,
	      GnmExpr const *expr)
{
	GnmValue *res, *va, *vb;

	if (a != NULL && a->type == VALUE_ERROR)
		return value_dup (a);
	if (b != NULL && b->type == VALUE_ERROR)
		return value_dup (b);
Jody Goldberg's avatar
Jody Goldberg committed
895
	if (VALUE_IS_EMPTY (a))
896
		a = va = (GnmValue *)value_zero;
897 898 899 900 901 902 903 904 905
	else if (a->type == VALUE_STRING) {
		va = format_match_number (a->v_str.val->str, NULL,
			workbook_date_conv (ep->sheet->workbook));
		if (va == NULL)
			return value_new_error_VALUE (ep);
	} else if (!VALUE_IS_NUMBER (a))
		return value_new_error_VALUE (ep);
	else
		va = (GnmValue *)a;
Jody Goldberg's avatar
Jody Goldberg committed
906
	if (VALUE_IS_EMPTY (b))
907
		b = vb = (GnmValue *)value_zero;
908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
	else if (b->type == VALUE_STRING) {
		vb = format_match_number (b->v_str.val->str, NULL,
			workbook_date_conv (ep->sheet->workbook));
		if (vb == NULL) {
			if (va != a)
				value_release (va);
			return value_new_error_VALUE (ep);
		}
	} else if (!VALUE_IS_NUMBER (b)) {
		if (va != a)
			value_release (va);
		return value_new_error_VALUE (ep);
	} else
		vb = (GnmValue *)b;

	res = bin_arith (expr, ep, va, vb);
	if (va != a)
		value_release (va);
	if (vb != b)
		value_release (vb);
	return res;
}

static GnmValue *
cb_bin_cat (GnmEvalPos const *ep, GnmValue const *a, GnmValue const *b,
	    GnmExpr const *expr)
{
	if (a != NULL && a->type == VALUE_ERROR)
		return value_dup (a);
	if (b != NULL && b->type == VALUE_ERROR)
		return value_dup (b);
	if (a == NULL) {
		if (b != NULL)
			return value_new_string (value_peek_string (b));
		else
			return value_new_string ("");
	} else if (b == NULL)
		return value_new_string (value_peek_string (a));
	else {
		char *tmp = g_strconcat (value_peek_string (a),
					 value_peek_string (b), NULL);
		return value_new_string_nocopy (tmp);
	}
}

typedef GnmValue *(*BinOpImplicitIteratorFunc) (GnmEvalPos const *ep,
						GnmValue const *a,
						GnmValue const *b,
						gpointer user_data);
typedef struct {
	GnmValue *res;
	GnmValue const *a, *b;
	BinOpImplicitIteratorFunc	func;
	gpointer	user_data;
} BinOpImplicitIteratorState;

static GnmValue *
cb_implicit_iter_a_to_b (GnmValue const *v, GnmEvalPos const *ep,
			 int x, int y, BinOpImplicitIteratorState const *state)
{
	state->res->v_array.vals [x][y] = (*state->func) (ep,
		v, value_area_get_x_y (state->b, x, y, ep), state->user_data);
	return NULL;
}
static GnmValue *
cb_implicit_iter_a_to_scalar_b (GnmValue const *v, GnmEvalPos const *ep,
				int x, int y, BinOpImplicitIteratorState const *state)
{
	state->res->v_array.vals [x][y] = (*state->func) (ep,
		v, state->b, state->user_data);
	return NULL;
}
static GnmValue *
cb_implicit_iter_b_to_scalar_a (GnmValue const *v, GnmEvalPos const *ep,
				int x, int y, BinOpImplicitIteratorState const *state)
{
	state->res->v_array.vals [x][y] = (*state->func) (ep,
		state->a, v, state->user_data);
	return NULL;
}

static GnmValue *
bin_array_op (GnmEvalPos const *ep, GnmValue *sizer, GnmValue *a, GnmValue *b,
	      BinOpImplicitIteratorFunc func, gpointer user_data)
{
	BinOpImplicitIteratorState iter_info;
	
	if (sizer != a || b == NULL || b->type != VALUE_ERROR) {
		iter_info.func = func;
		iter_info.user_data = user_data;
		iter_info.a = a;
		iter_info.b = b;
		iter_info.res = value_new_array_empty (
			value_area_get_width  (sizer, ep),
			value_area_get_height (sizer, ep));
		if (sizer == b)
			value_area_foreach (b, ep, CELL_ITER_ALL,
				(ValueAreaFunc) cb_implicit_iter_b_to_scalar_a, &iter_info);
		else if (b != NULL &&
			   (b->type == VALUE_CELLRANGE || b->type == VALUE_ARRAY))
			value_area_foreach (a, ep, CELL_ITER_ALL,
				(ValueAreaFunc) cb_implicit_iter_a_to_b, &iter_info);
		else
			value_area_foreach (a, ep, CELL_ITER_ALL,
				(ValueAreaFunc) cb_implicit_iter_a_to_scalar_b, &iter_info);
	} else
		/* you have to love the aymetry of MS XL */
		iter_info.res = value_new_error_VALUE (ep);
	if (a != NULL)
		value_release (a);
	if (b != NULL)
		value_release (b);
	return iter_info.res;
}

1023 1024
static inline GnmValue *
negate_value (GnmValue const *v)
1025
{
1026
	GnmValue *tmp;
1027
	GOFormat *fmt; 
1028 1029

	if (v->type == VALUE_INTEGER) {
1030 1031 1032 1033 1034
		int i = v->v_int.val;
		if (i < 0 && -i < 0)
			tmp = value_new_float (-(gnm_float)i);
		else
			tmp = value_new_int (-i);
1035 1036 1037 1038 1039
		fmt = VALUE_FMT (v);
	} else if (v->type == VALUE_FLOAT) {
		tmp = value_new_float (-v->v_float.val);
		fmt = VALUE_FMT (v);
	} else if (v->type == VALUE_BOOLEAN) {
1040
		/* Silly, but XL compatible.  */
1041 1042 1043
		tmp = value_new_int (v->v_bool.val ? -1 : 0);
		fmt = VALUE_FMT (v);
	} else
1044
		return NULL;
1045 1046 1047

	if (fmt != NULL) {
		VALUE_FMT (tmp) = fmt;
1048
		go_format_ref (fmt);
1049
	}
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077

	return tmp;
}

static GnmValue *
cb_iter_unary_neg (GnmValue const *v, GnmEvalPos const *ep,
		   int x, int y, GnmValue *res)
{
	GnmValue *tmp = NULL;

	if (VALUE_IS_EMPTY (v))
		tmp = value_new_int (0);
	else if (v->type == VALUE_ERROR)
		tmp = value_dup (v);
	else if (v->type == VALUE_STRING) {
		GnmValue *conv = format_match_number
			(v->v_str.val->str, NULL,
			 workbook_date_conv (ep->sheet->workbook));
		if (conv != NULL) {
			tmp = negate_value (conv);
			value_release (conv);
		}
	} else
		tmp = negate_value (v);

	if (!tmp)
		tmp = value_new_error_VALUE (ep);

1078 1079 1080 1081 1082 1083 1084 1085
	res->v_array.vals [x][y] = tmp;
	return NULL;
}

static GnmValue *
cb_iter_percentage (GnmValue const *v, GnmEvalPos const *ep,
		    int x, int y, GnmValue *res)
{
1086
	GnmValue *tmp;
1087 1088 1089 1090 1091

	if (VALUE_IS_EMPTY (v))
		tmp = value_new_int (0);
	else if (v->type == VALUE_ERROR)
		tmp = value_dup (v);
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
	else {
		GnmValue *conv = NULL;
		if (v->type == VALUE_STRING) {
			conv = format_match_number (v->v_str.val->str, NULL,
						    workbook_date_conv (ep->sheet->workbook));
			if (conv != NULL)
				v = conv;
		}

		if (VALUE_IS_NUMBER (v)){
			tmp = value_new_float (value_get_as_float (v) / 100);
1103 1104
			VALUE_FMT (tmp) = go_format_default_percentage ();
			go_format_ref (VALUE_FMT (tmp));
1105 1106 1107
		} else
			tmp = value_new_error_VALUE (ep);

1108
		if (conv != NULL)
1109
			value_release (conv);
1110 1111 1112 1113
	}

	res->v_array.vals [x][y] = tmp;
	return NULL;
1114 1115
}

Jody Goldberg's avatar
Jody Goldberg committed
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128
static GnmValue *
gnm_expr_range_op (GnmExpr const *expr, GnmEvalPos const *ep,
		   GnmExprEvalFlags flags)
{
	GnmRangeRef a_ref, b_ref;
	GnmRange a_range, b_range, res_range;
	Sheet *a_start, *a_end, *b_start, *b_end;
	GnmValue *res = NULL;

	if (gnm_expr_extract_ref (&a_ref, expr->binary.value_a, ep, flags) ||
	    gnm_expr_extract_ref (&b_ref, expr->binary.value_b, ep, flags))
		return value_new_error_REF (ep);

1129 1130
	gnm_rangeref_normalize (&a_ref, ep, &a_start, &a_end, &a_range);
	gnm_rangeref_normalize (&b_ref, ep, &b_start, &b_end, &b_range);
Jody Goldberg's avatar
Jody Goldberg committed
1131

1132
	if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_INTERSECT)
Jody Goldberg's avatar
Jody Goldberg committed
1133 1134 1135 1136 1137
		res_range = range_union (&a_range, &b_range);
	else if (!range_intersection  (&res_range, &a_range, &b_range))
		return value_new_error_NULL (ep);

	res = value_new_cellrange_r (a_start, &res_range);
1138
	dependent_add_dynamic_dep (ep->dep, &res->v_range.cell);
Jody Goldberg's avatar
Jody Goldberg committed
1139 1140 1141 1142 1143 1144 1145 1146 1147
	if (!(flags & GNM_EXPR_EVAL_PERMIT_NON_SCALAR)) {
		res = value_intersection (res, ep);
		return (res != NULL)
			? handle_empty (res, flags)
			: value_new_error_VALUE (ep);
	}
	return res;
}

1148 1149 1150 1151 1152 1153 1154 1155
/**
 * gnm_expr_eval :
 * @expr :
 * @ep   :
 * @flags:
 *
 * if GNM_EXPR_EVAL_PERMIT_EMPTY is not set then return int(0) if the
 * expression returns empty, or the  value of an unused cell.
1156
 **/
Jody Goldberg's avatar
Jody Goldberg committed
1157
GnmValue *
Morten Welinder's avatar
Morten Welinder committed
1158
gnm_expr_eval (GnmExpr const *expr, GnmEvalPos const *pos,
1159
	       GnmExprEvalFlags flags)
Arturo Espinosa's avatar
Arturo Espinosa committed
1160
{
Jody Goldberg's avatar
Jody Goldberg committed
1161
	GnmValue *res = NULL, *a = NULL, *b = NULL;
1162

1163 1164
	g_return_val_if_fail (expr != NULL, handle_empty (NULL, flags));
	g_return_val_if_fail (pos != NULL, handle_empty (NULL, flags));
1165

1166
	switch (GNM_EXPR_GET_OPER (expr)){
1167 1168 1169 1170 1171
	case GNM_EXPR_OP_EQUAL:
	case GNM_EXPR_OP_NOT_EQUAL:
	case GNM_EXPR_OP_GT:
	case GNM_EXPR_OP_GTE:
	case GNM_EXPR_OP_LT:
1172
	case GNM_EXPR_OP_LTE:
Jody Goldberg's avatar
Jody Goldberg committed
1173
		flags |= GNM_EXPR_EVAL_PERMIT_EMPTY;
Morten Welinder's avatar
Morten Welinder committed
1174

Jody Goldberg's avatar
Jody Goldberg committed
1175
		a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1176 1177 1178 1179 1180 1181 1182 1183 1184
		if (a != NULL) {
			if (a->type == VALUE_ERROR)
				return a;
			if (a->type == VALUE_CELLRANGE || a->type == VALUE_ARRAY)
				return bin_array_op (pos, a, a,
					gnm_expr_eval (expr->binary.value_b, pos, flags),
					(BinOpImplicitIteratorFunc) cb_bin_cmp,
					(gpointer) expr);
		}
Jody Goldberg's avatar
Jody Goldberg committed
1185 1186

		b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
		if (b != NULL) {
			if (b->type == VALUE_ERROR) {
				if (a != NULL)
					value_release (a);
				return b;
			}
			if (b->type == VALUE_CELLRANGE || b->type == VALUE_ARRAY)
				return bin_array_op (pos, b, a, b,
					(BinOpImplicitIteratorFunc) cb_bin_cmp,
					(gpointer) expr);
Morten Welinder's avatar
Morten Welinder committed
1197