GitLab repository storage has been migrated to hashed layout. Please contact Infrastructure team if you notice any issues with repositories or hooks.

expr.c 74.1 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
/**
 * gnm_expr_new_constant :
 * @v :
 *
 * Absorbs the value.
 **/
75
GnmExpr const *
Jody Goldberg's avatar
Jody Goldberg committed
76
gnm_expr_new_constant (GnmValue *v)
77
{
78
	GnmExprConstant *ans;
79

80
	ans = CHUNK_ALLOC (GnmExprConstant, expression_pool_small);
81 82
	if (!ans)
		return NULL;
83
	gnm_expr_constant_init (ans, v);
84

85
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
86 87
}

Jody Goldberg's avatar
Jody Goldberg committed
88 89
/***************************************************************************/

90 91
static GnmExpr const *
gnm_expr_new_funcallv (GnmFunc *func, int argc, GnmExprConstPtr *argv)
92
{
93
	GnmExprFunction *ans;
Jody Goldberg's avatar
Jody Goldberg committed
94
	g_return_val_if_fail (func, NULL);
95

96
	ans = CHUNK_ALLOC (GnmExprFunction, expression_pool_small);
97

98
	ans->oper = GNM_EXPR_OP_FUNCALL;
Jody Goldberg's avatar
Jody Goldberg committed
99
	gnm_func_ref (func);
100
	ans->func = func;
101 102
	ans->argc = argc;
	ans->argv = argv;
103

104
	return (GnmExpr *)ans;
105
}
106

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
GnmExpr const *
gnm_expr_new_funcall (GnmFunc *func, GnmExprList *arg_list)
{
	GnmExprList *arg_list0 = arg_list;
	int argc = gnm_expr_list_length (arg_list);
	GnmExprConstPtr *argv = argc ? g_new (GnmExprConstPtr, argc) : NULL;
	int i;

	for (i = 0; arg_list; i++, arg_list = arg_list->next)
		argv[i] = arg_list->data;
	gnm_expr_list_free (arg_list0);

	return gnm_expr_new_funcallv (func, argc, argv);
}

Morten Welinder's avatar
Morten Welinder committed
122 123 124 125
GnmExpr const *
gnm_expr_new_funcall1 (GnmFunc *func,
		       GnmExpr const *arg0)
{
126 127 128
	GnmExprConstPtr *argv = g_new (GnmExprConstPtr, 1);
	argv[0] = arg0;
	return gnm_expr_new_funcallv (func, 1, argv);
Morten Welinder's avatar
Morten Welinder committed
129 130 131 132 133 134 135
}

GnmExpr const *
gnm_expr_new_funcall2 (GnmFunc *func,
		       GnmExpr const *arg0,
		       GnmExpr const *arg1)
{
136 137 138 139
	GnmExprConstPtr *argv = g_new (GnmExprConstPtr, 2);
	argv[0] = arg0;
	argv[1] = arg1;
	return gnm_expr_new_funcallv (func, 2, argv);
Morten Welinder's avatar
Morten Welinder committed
140 141 142 143 144 145 146 147
}

GnmExpr const *
gnm_expr_new_funcall3 (GnmFunc *func,
		       GnmExpr const *arg0,
		       GnmExpr const *arg1,
		       GnmExpr const *arg2)
{
148 149 150 151 152
	GnmExprConstPtr *argv = g_new (GnmExprConstPtr, 3);
	argv[0] = arg0;
	argv[1] = arg1;
	argv[2] = arg2;
	return gnm_expr_new_funcallv (func, 3, argv);
Morten Welinder's avatar
Morten Welinder committed
153 154 155
}


Jody Goldberg's avatar
Jody Goldberg committed
156 157
/***************************************************************************/

158 159
GnmExpr const *
gnm_expr_new_unary  (GnmExprOp op, GnmExpr const *e)
Morten Welinder's avatar
Morten Welinder committed
160
{
161
	GnmExprUnary *ans;
Morten Welinder's avatar
Morten Welinder committed
162

163
	ans = CHUNK_ALLOC (GnmExprUnary, expression_pool_small);
164 165 166
	if (!ans)
		return NULL;

167
	ans->oper = op;
168
	ans->value = e;
169

170
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
171 172
}

Jody Goldberg's avatar
Jody Goldberg committed
173 174
/***************************************************************************/

175 176
GnmExpr const *
gnm_expr_new_binary (GnmExpr const *l, GnmExprOp op, GnmExpr const *r)
Morten Welinder's avatar
Morten Welinder committed
177
{
178
	GnmExprBinary *ans;
Morten Welinder's avatar
Morten Welinder committed
179

180
	ans = CHUNK_ALLOC (GnmExprBinary, expression_pool_small);
181 182
	if (!ans)
		return NULL;
183

184
	ans->oper = op;
185 186
	ans->value_a = l;
	ans->value_b = r;
187

188
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
189 190
}

Jody Goldberg's avatar
Jody Goldberg committed
191 192
/***************************************************************************/

193 194
GnmExpr const *
gnm_expr_new_name (GnmNamedExpr *name,
195
		   Sheet *optional_scope, Workbook *optional_wb_scope)
Morten Welinder's avatar
Morten Welinder committed
196
{
197
	GnmExprName *ans;
Morten Welinder's avatar
Morten Welinder committed
198

199
	ans = CHUNK_ALLOC (GnmExprName, expression_pool_big);
200 201
	if (!ans)
		return NULL;
202

203
	ans->oper = GNM_EXPR_OP_NAME;
204
	ans->name = name;
205
	expr_name_ref (name);
206

207 208 209
	ans->optional_scope = optional_scope;
	ans->optional_wb_scope = optional_wb_scope;

210
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
211
}
212

Jody Goldberg's avatar
Jody Goldberg committed
213 214
/***************************************************************************/

215
GnmExpr const *
Jody Goldberg's avatar
Jody Goldberg committed
216
gnm_expr_new_cellref (GnmCellRef const *cr)
217
{
218
	GnmExprCellRef *ans;
219

220
	ans = CHUNK_ALLOC (GnmExprCellRef, expression_pool_big);
221 222
	if (!ans)
		return NULL;
223

224
	ans->oper = GNM_EXPR_OP_CELLREF;
225 226
	ans->ref = *cr;

227
	return (GnmExpr *)ans;
228 229
}

Jody Goldberg's avatar
Jody Goldberg committed
230 231 232
/***************************************************************************/

/**
233
 * gnm_expr_new_array_corner :
Jody Goldberg's avatar
Jody Goldberg committed
234 235 236 237 238 239
 * @cols :
 * @rows :
 * @expr : optionally NULL.
 *
 * Absorb a referernce to @expr if it is non NULL.
 **/
240
GnmExpr const *
241
gnm_expr_new_array_corner(int cols, int rows, GnmExpr const *expr)
242
{
243
	GnmExprArrayCorner *ans;
244

245
	ans = CHUNK_ALLOC (GnmExprArrayCorner, expression_pool_big);
246 247
	if (ans == NULL)
		return NULL;
248

249
	ans->oper = GNM_EXPR_OP_ARRAY_CORNER;
250 251
	ans->rows = rows;
	ans->cols = cols;
252 253 254 255 256 257 258 259 260 261
	ans->value = NULL;
	ans->expr = expr;
	return (GnmExpr *)ans;
}

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

262
	ans = CHUNK_ALLOC (GnmExprArrayElem, expression_pool_small);
263 264 265
	if (ans == NULL)
		return NULL;

266
	ans->oper = GNM_EXPR_OP_ARRAY_ELEM;
267 268
	ans->x = x;
	ans->y = y;
269
	return (GnmExpr *)ans;
270 271
}

Jody Goldberg's avatar
Jody Goldberg committed
272 273
/***************************************************************************/

274 275
static GnmExpr const *
gnm_expr_new_setv (int argc, GnmExprConstPtr *argv)
Jody Goldberg's avatar
Jody Goldberg committed
276
{
277 278
	GnmExprSet *ans = CHUNK_ALLOC (GnmExprSet, expression_pool_small);

279
	ans->oper = GNM_EXPR_OP_SET;
280 281 282 283
	ans->argc = argc;
	ans->argv = argv;

	return (GnmExpr *)ans;
Jody Goldberg's avatar
Jody Goldberg committed
284 285
}

286 287
GnmExpr const *
gnm_expr_new_set (GnmExprList *set)
288
{
289 290 291
	int i, argc;
	GnmExprConstPtr *argv;
	GnmExprList *set0 = set;
292

293 294 295 296 297
	argc = gnm_expr_list_length (set);
	argv = argc ? g_new (GnmExprConstPtr, argc) : NULL;
	for (i = 0; set; i++, set = set->next)
		argv[i] = set->data;
	gnm_expr_list_free (set0);
298

299
	return gnm_expr_new_setv (argc, argv);
300 301
}

Jody Goldberg's avatar
Jody Goldberg committed
302 303
/***************************************************************************/

304 305
GnmExpr const *
gnm_expr_copy (GnmExpr const *expr)
306
{
307 308
	g_return_val_if_fail (expr != NULL, NULL);

309 310 311 312 313 314 315 316
	switch (GNM_EXPR_GET_OPER (expr)) {
	case GNM_EXPR_OP_RANGE_CTOR:
	case GNM_EXPR_OP_INTERSECT:
	case GNM_EXPR_OP_ANY_BINARY:
		return gnm_expr_new_binary
			(gnm_expr_copy (expr->binary.value_a),
			 GNM_EXPR_GET_OPER (expr),
			 gnm_expr_copy (expr->binary.value_b));
317

318 319 320 321
	case GNM_EXPR_OP_ANY_UNARY:
		return gnm_expr_new_unary
			(GNM_EXPR_GET_OPER (expr),
			 gnm_expr_copy (expr->unary.value));
322

323 324 325 326
	case GNM_EXPR_OP_FUNCALL: {
		GnmExprConstPtr *argv =
			g_new (GnmExprConstPtr, expr->func.argc);
		int i;
Arturo Espinosa's avatar
Arturo Espinosa committed
327

328 329
		for (i = 0; i < expr->func.argc; i++)
			argv[i] = gnm_expr_copy (expr->func.argv[i]);
330

331 332 333 334 335
		return gnm_expr_new_funcallv
			(expr->func.func,
			 expr->func.argc,
			 argv);
	}
336

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
	case GNM_EXPR_OP_NAME:
		return gnm_expr_new_name
			(expr->name.name,
			 expr->name.optional_scope,
			 expr->name.optional_wb_scope);

	case GNM_EXPR_OP_CONSTANT:
		return gnm_expr_new_constant
			(value_dup (expr->constant.value));

	case GNM_EXPR_OP_CELLREF:
		return gnm_expr_new_cellref (&expr->cellref.ref);

	case GNM_EXPR_OP_ARRAY_CORNER:
		return gnm_expr_new_array_corner
			(expr->array_corner.cols, expr->array_corner.rows,
			 gnm_expr_copy (expr->array_corner.expr));

	case GNM_EXPR_OP_ARRAY_ELEM:
		return gnm_expr_new_array_elem
			(expr->array_elem.x,
			 expr->array_elem.y);

	case GNM_EXPR_OP_SET: {
		GnmExprConstPtr *argv =
			g_new (GnmExprConstPtr, expr->set.argc);
		int i;

		for (i = 0; i < expr->set.argc; i++)
			argv[i] = gnm_expr_copy (expr->set.argv[i]);

		return gnm_expr_new_setv
			(expr->set.argc,
			 argv);
	}

#ifndef DEBUG_SWITCH_ENUM
	default:
		g_assert_not_reached ();
		break;
#endif
	}
}

/*
 * gnm_expr_free:
 */
void
gnm_expr_free (GnmExpr const *expr)
{
	g_return_if_fail (expr != NULL);
Morten Welinder's avatar
Morten Welinder committed
388

389
	switch (GNM_EXPR_GET_OPER (expr)) {
390
	case GNM_EXPR_OP_RANGE_CTOR:
391
	case GNM_EXPR_OP_INTERSECT:
392
	case GNM_EXPR_OP_ANY_BINARY:
393 394
		gnm_expr_free (expr->binary.value_a);
		gnm_expr_free (expr->binary.value_b);
395
		CHUNK_FREE (expression_pool_small, (gpointer)expr);
Arturo Espinosa's avatar
Arturo Espinosa committed
396
		break;
397

398 399 400 401
	case GNM_EXPR_OP_FUNCALL: {
		int i;

		for (i = 0; i < expr->func.argc; i++)
402
			gnm_expr_free (expr->func.argv[i]);
Morten Welinder's avatar
Morten Welinder committed
403
		g_free (expr->func.argv);
Jody Goldberg's avatar
Jody Goldberg committed
404
		gnm_func_unref (expr->func.func);
405
		CHUNK_FREE (expression_pool_small, (gpointer)expr);
Arturo Espinosa's avatar
Arturo Espinosa committed
406
		break;
407
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
408

409
	case GNM_EXPR_OP_NAME:
410
		expr_name_unref (expr->name.name);
411
		CHUNK_FREE (expression_pool_big, (gpointer)expr);
Michael Meeks's avatar
Michael Meeks committed
412 413
		break;

414
	case GNM_EXPR_OP_CONSTANT:
Jody Goldberg's avatar
Jody Goldberg committed
415
		value_release ((GnmValue *)expr->constant.value);
416
		CHUNK_FREE (expression_pool_small, (gpointer)expr);
417 418 419
		break;

	case GNM_EXPR_OP_CELLREF:
420
		CHUNK_FREE (expression_pool_big, (gpointer)expr);
Arturo Espinosa's avatar
Arturo Espinosa committed
421 422
		break;

423
	case GNM_EXPR_OP_ANY_UNARY:
424
		gnm_expr_free (expr->unary.value);
425
		CHUNK_FREE (expression_pool_small, (gpointer)expr);
Arturo Espinosa's avatar
Arturo Espinosa committed
426
		break;
427

428 429 430
	case GNM_EXPR_OP_ARRAY_CORNER:
		if (expr->array_corner.value)
			value_release (expr->array_corner.value);
431
		gnm_expr_free (expr->array_corner.expr);
432
		CHUNK_FREE (expression_pool_big, (gpointer)expr);
433 434 435
		break;

	case GNM_EXPR_OP_ARRAY_ELEM:
436
		CHUNK_FREE (expression_pool_small, (gpointer)expr);
Jody Goldberg's avatar
Jody Goldberg committed
437
		break;
438

439 440 441 442
	case GNM_EXPR_OP_SET: {
		int i;

		for (i = 0; i < expr->set.argc; i++)
443
			gnm_expr_free (expr->set.argv[i]);
Morten Welinder's avatar
Morten Welinder committed
444
		g_free (expr->set.argv);
445
		CHUNK_FREE (expression_pool_small, (gpointer)expr);
446
		break;
447
	}
448 449

#ifndef DEBUG_SWITCH_ENUM
450
	default:
451
		g_assert_not_reached ();
452
		break;
453
#endif
Arturo Espinosa's avatar
Arturo Espinosa committed
454
	}
455 456
}

Jody Goldberg's avatar
Jody Goldberg committed
457
/**
458
 * gnm_expr_equal : Returns TRUE if the supplied expressions are exactly the
Jody Goldberg's avatar
Jody Goldberg committed
459 460 461 462
 *   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.
 */
463
static gboolean
464
gnm_expr_equal (GnmExpr const *a, GnmExpr const *b)
Jody Goldberg's avatar
Jody Goldberg committed
465 466 467 468 469 470 471
{
	if (a == b)
		return TRUE;

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

472
	if (GNM_EXPR_GET_OPER (a) != GNM_EXPR_GET_OPER (b))
Jody Goldberg's avatar
Jody Goldberg committed
473 474
		return FALSE;

475
	switch (GNM_EXPR_GET_OPER (a)) {
476
	case GNM_EXPR_OP_RANGE_CTOR:
477
	case GNM_EXPR_OP_INTERSECT:
478 479 480
	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
481

482 483
	case GNM_EXPR_OP_ANY_UNARY:
		return gnm_expr_equal (a->unary.value, b->unary.value);
Jody Goldberg's avatar
Jody Goldberg committed
484

485 486 487 488 489 490 491 492 493 494 495 496
	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
497

498
	case GNM_EXPR_OP_NAME:
499 500 501
		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
502

503
	case GNM_EXPR_OP_CELLREF:
504
		return gnm_cellref_equal (&a->cellref.ref, &b->cellref.ref);
Jody Goldberg's avatar
Jody Goldberg committed
505

506 507
	case GNM_EXPR_OP_CONSTANT:
		return value_equal (a->constant.value, b->constant.value);
Jody Goldberg's avatar
Jody Goldberg committed
508

509 510 511
	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
512 513 514

		return	aa->cols == ab->cols &&
			aa->rows == ab->rows &&
515 516 517 518 519 520
			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
521 522
	}

523 524 525 526 527 528 529 530 531 532 533
	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
534 535 536 537 538
	}

	return FALSE;
}

539
static GnmCell *
540 541
array_elem_get_corner (GnmExprArrayElem const *elem,
		       Sheet const *sheet, GnmCellPos const *pos)
542
{
543
	GnmCell *corner = sheet_cell_get (sheet,
544
		pos->col - elem->x, pos->row - elem->y);
545 546 547 548

	/* 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);
549 550
	g_return_val_if_fail (corner->base.texpr != (void *)0xdeadbeef, NULL);
	g_return_val_if_fail (IS_GNM_EXPR_TOP (corner->base.texpr), NULL);
551 552 553 554 555

	return corner;
}

static gboolean
Jody Goldberg's avatar
Jody Goldberg committed
556
gnm_expr_extract_ref (GnmRangeRef *res, GnmExpr const *expr,
Morten Welinder's avatar
Morten Welinder committed
557
		      GnmEvalPos const *pos, GnmExprEvalFlags flags)
558
{
559
	switch (GNM_EXPR_GET_OPER (expr)) {
560 561
	case GNM_EXPR_OP_FUNCALL : {
		gboolean failed = TRUE;
Jody Goldberg's avatar
Jody Goldberg committed
562
		GnmValue *v;
563 564
		FunctionEvalInfo ei;
		ei.pos = pos;
565
		ei.func_call = &expr->func;
566

567 568 569 570
		v = function_call_with_exprs (&ei,
					      expr->func.argc,
					      expr->func.argv,
					      flags);
571
		if (v != NULL) {
Jody Goldberg's avatar
Jody Goldberg committed
572 573
			if (v->type == VALUE_CELLRANGE) {
				*res = v->v_range.cell;
574 575 576 577 578 579 580 581
				failed = FALSE;
			}
			value_release (v);
		}
		return failed;
	}

	case GNM_EXPR_OP_CELLREF :
Jody Goldberg's avatar
Jody Goldberg committed
582 583
		res->a = expr->cellref.ref;
		res->b = expr->cellref.ref;
584 585 586
		return FALSE;

	case GNM_EXPR_OP_CONSTANT: {
Jody Goldberg's avatar
Jody Goldberg committed
587
		GnmValue const *v = expr->constant.value;
Jody Goldberg's avatar
Jody Goldberg committed
588 589
		if (v->type == VALUE_CELLRANGE) {
			*res = v->v_range.cell;
590 591 592 593 594 595
			return FALSE;
		}
		return TRUE;
	}

	case GNM_EXPR_OP_NAME:
596
		if (!expr->name.name->active)
597
			return TRUE;
598 599
		return gnm_expr_extract_ref (res, expr->name.name->texpr->expr,
					     pos, flags);
600 601 602 603 604 605
	default :
		break;
	}
	return TRUE;
}

Jody Goldberg's avatar
Jody Goldberg committed
606 607
static inline GnmValue *
handle_empty (GnmValue *res, GnmExprEvalFlags flags)
608 609 610 611 612 613 614 615 616 617 618 619 620
{
	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
621 622
/**
 * value_intersection :
623
 * @v   : a VALUE_CELLRANGE or VALUE_ARRAY
Morten Welinder's avatar
Morten Welinder committed
624
 * @pos :
Jody Goldberg's avatar
Jody Goldberg committed
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
 *
 * 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
640
static GnmValue *
Morten Welinder's avatar
Morten Welinder committed
641
value_intersection (GnmValue *v, GnmEvalPos const *pos)
Jody Goldberg's avatar
Jody Goldberg committed
642
{
Jody Goldberg's avatar
Jody Goldberg committed
643 644
	GnmValue *res = NULL;
	GnmRange r;
Jody Goldberg's avatar
Jody Goldberg committed
645 646 647 648
	Sheet *start_sheet, *end_sheet;
	gboolean found = FALSE;

	if (v->type == VALUE_ARRAY) {
649
		res = value_dup (v->v_array.vals[0][0]);
Jody Goldberg's avatar
Jody Goldberg committed
650 651 652 653 654
		value_release (v);
		return res;
	}

	/* inverted ranges */
655
	gnm_rangeref_normalize (&v->v_range.cell, pos, &start_sheet, &end_sheet, &r);
Jody Goldberg's avatar
Jody Goldberg committed
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
	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) {
678
			GnmCell *cell = sheet_cell_get (
Jody Goldberg's avatar
Jody Goldberg committed
679 680 681 682 683
				eval_sheet (start_sheet, pos->sheet),
				col, row);
			if (cell == NULL)
				return value_new_empty ();
			cell_eval (cell);
684
			return value_dup (cell->value);
Jody Goldberg's avatar
Jody Goldberg committed
685 686 687
		}
	}

688
	return value_new_error_VALUE (pos);
Jody Goldberg's avatar
Jody Goldberg committed
689
}
690

Jody Goldberg's avatar
Jody Goldberg committed
691
static GnmValue *
692 693
bin_arith (GnmExpr const *expr, GnmEvalPos const *ep,
	   GnmValue const *a, GnmValue const *b)
Jody Goldberg's avatar
Jody Goldberg committed
694
{
695 696 697 698 699 700 701 702
	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.  */
703
		switch (GNM_EXPR_GET_OPER (expr)){
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
		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);
725 726
			dres = gnm_pow ((gnm_float)ia, (gnm_float)ib);
			if (!gnm_finite (dres))
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
				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);

743
		switch (GNM_EXPR_GET_OPER (expr)){
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
		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);

764 765
			res = gnm_pow (va, vb);
			return gnm_finite (res)
766 767 768 769 770 771 772 773 774
				? 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
775 776
}

Jody Goldberg's avatar
Jody Goldberg committed
777
static GnmValue *
778
bin_cmp (GnmExprOp op, GnmValDiff comp, GnmEvalPos const *ep)
779 780 781 782 783 784 785 786 787 788 789
{
	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);

790
		return value_new_error_VALUE (ep);
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
	}

	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
	}
806
	return value_new_error (ep, _("Internal type error"));
807 808
}

Jody Goldberg's avatar
Jody Goldberg committed
809
static GnmValue *
810 811
cb_bin_cmp (GnmEvalPos const *ep, GnmValue const *a, GnmValue const *b,
	    GnmExpr const *expr)
812
{
813 814 815 816
	if (a != NULL && a->type == VALUE_ERROR)
		return value_dup (a);
	if (b != NULL && b->type == VALUE_ERROR)
		return value_dup (b);
817
	return bin_cmp (GNM_EXPR_GET_OPER (expr), value_compare (a, b, FALSE), ep);
818 819 820 821 822 823 824 825 826 827 828 829
}

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
830
	if (VALUE_IS_EMPTY (a))
831
		a = va = (GnmValue *)value_zero;
832 833 834 835 836 837 838 839 840
	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
841
	if (VALUE_IS_EMPTY (b))
842
		b = vb = (GnmValue *)value_zero;
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 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
	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;
}

958 959
static inline GnmValue *
negate_value (GnmValue const *v)
960
{
961
	GnmValue *tmp;
962
	GOFormat *fmt; 
963 964

	if (v->type == VALUE_INTEGER) {
965 966 967 968 969
		int i = v->v_int.val;
		if (i < 0 && -i < 0)
			tmp = value_new_float (-(gnm_float)i);
		else
			tmp = value_new_int (-i);
970 971 972 973 974
		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) {
975
		/* Silly, but XL compatible.  */
976 977 978
		tmp = value_new_int (v->v_bool.val ? -1 : 0);
		fmt = VALUE_FMT (v);
	} else
979
		return NULL;
980 981 982

	if (fmt != NULL) {
		VALUE_FMT (tmp) = fmt;
983
		go_format_ref (fmt);
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

	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);

1013 1014 1015 1016 1017 1018 1019 1020
	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)
{
1021
	GnmValue *tmp;
1022 1023 1024 1025 1026

	if (VALUE_IS_EMPTY (v))
		tmp = value_new_int (0);
	else if (v->type == VALUE_ERROR)
		tmp = value_dup (v);
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
	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);
1038 1039
			VALUE_FMT (tmp) = go_format_default_percentage ();
			go_format_ref (VALUE_FMT (tmp));
1040 1041 1042
		} else
			tmp = value_new_error_VALUE (ep);

1043
		if (conv != NULL)
1044
			value_release (conv);
1045 1046 1047 1048
	}

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

Jody Goldberg's avatar
Jody Goldberg committed
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
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);

1064 1065
	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
1066

1067
	if (GNM_EXPR_GET_OPER (expr) != GNM_EXPR_OP_INTERSECT)
Jody Goldberg's avatar
Jody Goldberg committed
1068 1069 1070 1071 1072
		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);
1073
	dependent_add_dynamic_dep (ep->dep, &res->v_range.cell);
Jody Goldberg's avatar
Jody Goldberg committed
1074 1075 1076 1077 1078 1079 1080 1081 1082
	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;
}

1083 1084 1085 1086 1087 1088 1089 1090
/**
 * 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.
1091
 **/
Jody Goldberg's avatar
Jody Goldberg committed
1092
GnmValue *
Morten Welinder's avatar
Morten Welinder committed
1093
gnm_expr_eval (GnmExpr const *expr, GnmEvalPos const *pos,
1094
	       GnmExprEvalFlags flags)
Arturo Espinosa's avatar
Arturo Espinosa committed
1095
{
Jody Goldberg's avatar
Jody Goldberg committed
1096
	GnmValue *res = NULL, *a = NULL, *b = NULL;
1097

1098 1099
	g_return_val_if_fail (expr != NULL, handle_empty (NULL, flags));
	g_return_val_if_fail (pos != NULL, handle_empty (NULL, flags));
1100

1101
	switch (GNM_EXPR_GET_OPER (expr)){
1102 1103 1104 1105 1106
	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:
1107
	case GNM_EXPR_OP_LTE:
Jody Goldberg's avatar
Jody Goldberg committed
1108
		flags |= GNM_EXPR_EVAL_PERMIT_EMPTY;
Morten Welinder's avatar
Morten Welinder committed
1109

Jody Goldberg's avatar
Jody Goldberg committed
1110
		a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1111 1112 1113 1114 1115 1116 1117 1118 1119
		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
1120 1121

		b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
		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
1132
		}
1133

1134
		res = bin_cmp (GNM_EXPR_GET_OPER (expr), value_compare (a, b, FALSE), pos);
1135 1136 1137 1138
		if (a != NULL)
			value_release (a);
		if (b != NULL)
			value_release (b);
1139
		return res;
1140

1141 1142 1143 1144 1145
	case GNM_EXPR_OP_ADD:
	case GNM_EXPR_OP_SUB:
	case GNM_EXPR_OP_MULT:
	case GNM_EXPR_OP_DIV:
	case GNM_EXPR_OP_EXP:
1146 1147 1148 1149 1150 1151 1152 1153 1154
		/*
		 * Priority
		 * 1) Error from A
		 * 2) #!VALUE error if A is not a number
		 * 3) Error from B
		 * 4) #!VALUE error if B is not a number
		 * 5) result of operation, or error specific to the operation
		 */

Jody Goldberg's avatar
Jody Goldberg committed
1155
	        /* Guarantees value != NULL */
1156
		flags &= ~GNM_EXPR_EVAL_PERMIT_EMPTY;
Jody Goldberg's avatar
Jody Goldberg committed
1157

1158
		/* 1) Error from A */
Jody Goldberg's avatar
Jody Goldberg committed
1159
		a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1160
		if (a->type == VALUE_ERROR)
1161
			return value_error_set_pos (&a->v_err, pos);
1162

1163
		/* 2) #!VALUE error if A is not a number */
1164
		if (a->type == VALUE_STRING) {
Jody Goldberg's avatar
Jody Goldberg committed
1165
			GnmValue *tmp = format_match_number (a->v_str.val->str, NULL,
1166
				workbook_date_conv (pos->sheet->workbook));
1167 1168 1169

			value_release (a);
			if (tmp == NULL)
1170
				return value_new_error_VALUE (pos);
1171
			a = tmp;
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182
		} else if (a->type == VALUE_CELLRANGE || a->type == VALUE_ARRAY) {
			b = gnm_expr_eval (expr->binary.value_b, pos, flags);
			if (b->type == VALUE_STRING) {
				res = format_match_number (b->v_str.val->str, NULL,
					workbook_date_conv (pos->sheet->workbook));
				value_release (b);
				b = (res == NULL) ? value_new_error_VALUE (pos) : res;
			}
			return bin_array_op (pos, a, a, b,
				(BinOpImplicitIteratorFunc) cb_bin_arith,
				(gpointer) expr);
1183
		} else if (!VALUE_IS_NUMBER (a)) {
1184
			value_release (a);
1185
			return value_new_error_VALUE (pos);
1186 1187 1188
		}

		/* 3) Error from B */
Jody Goldberg's avatar
Jody Goldberg committed
1189
		b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1190
		if (b->type == VALUE_ERROR) {
1191
			value_release (a);
1192
			return value_error_set_pos (&b->v_err, pos);
Arturo Espinosa's avatar
Arturo Espinosa committed
1193
		}
1194