expr.c 68.9 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 19 20
 *
 * 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
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * 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>
47

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
/* Memory pool for expressions.  */
58 59 60
static GOMemChunk *expression_pool;
#define CHUNK_ALLOC(T,p) ((T*)go_mem_chunk_alloc (p))
#define CHUNK_FREE(p,v) go_mem_chunk_free ((p), (v))
61 62 63 64 65
#else
#define CHUNK_ALLOC(T,c) g_new (T,1)
#define CHUNK_FREE(p,v) g_free ((v))
#endif

66 67
/***************************************************************************/

Jody Goldberg's avatar
Jody Goldberg committed
68 69 70 71 72 73 74 75 76 77 78 79
#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
80 81 82 83 84 85
/**
 * gnm_expr_new_constant :
 * @v :
 *
 * Absorbs the value.
 **/
86
GnmExpr const *
Jody Goldberg's avatar
Jody Goldberg committed
87
gnm_expr_new_constant (GnmValue *v)
88
{
89
	GnmExprConstant *ans;
90

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

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

Jody Goldberg's avatar
Jody Goldberg committed
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
/***************************************************************************/

#if 0
static guint
gnm_expr_function_hash (GnmExprFunction const *expr)
{
	guint h = expr->oper;
	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

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

124
	ans = CHUNK_ALLOC (GnmExprFunction, expression_pool);
125 126
	if (!ans)
		return NULL;
127

128
	ans->ref_count = 1;
129
	ans->oper = GNM_EXPR_OP_FUNCALL;
Jody Goldberg's avatar
Jody Goldberg committed
130
	gnm_func_ref (func);
Jody Goldberg's avatar
Jody Goldberg committed
131
	ans->func = func;;
132 133
	ans->arg_list = args;

134
	return (GnmExpr *)ans;
135
}
136

Jody Goldberg's avatar
Jody Goldberg committed
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
/***************************************************************************/

#if 0
static guint
gnm_expr_unary_hash (GnmExprUnary const *expr)
{
	return  (GPOINTER_TO_INT (expr->value) * 7) ^
		(guint)(expr->oper);
}
static gboolean
gnm_expr_unary_eq (GnmExprUnary const *a,
		   GnmExprUnary const *b)
{
	return  a->oper == b->oper && a->value == b->value;
}
#endif

154 155
GnmExpr const *
gnm_expr_new_unary  (GnmExprOp op, GnmExpr const *e)
Morten Welinder's avatar
Morten Welinder committed
156
{
157
	GnmExprUnary *ans;
Morten Welinder's avatar
Morten Welinder committed
158

159
	ans = CHUNK_ALLOC (GnmExprUnary, expression_pool);
160 161 162 163
	if (!ans)
		return NULL;

	ans->ref_count = 1;
164
	ans->oper = op;
165
	ans->value = e;
166

167
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
168 169
}

Jody Goldberg's avatar
Jody Goldberg committed
170 171 172 173 174 175 176 177 178 179 180
/***************************************************************************/

#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) ^
		(guint)(expr->oper);
}
#endif
Morten Welinder's avatar
Morten Welinder committed
181

182 183
GnmExpr const *
gnm_expr_new_binary (GnmExpr const *l, GnmExprOp op, GnmExpr const *r)
Morten Welinder's avatar
Morten Welinder committed
184
{
185
	GnmExprBinary *ans;
Morten Welinder's avatar
Morten Welinder committed
186

187
	ans = CHUNK_ALLOC (GnmExprBinary, expression_pool);
188 189
	if (!ans)
		return NULL;
190

191
	ans->ref_count = 1;
192
	ans->oper = op;
193 194
	ans->value_a = l;
	ans->value_b = r;
195

196
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
197 198
}

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

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

209 210
GnmExpr const *
gnm_expr_new_name (GnmNamedExpr *name,
211
		   Sheet *optional_scope, Workbook *optional_wb_scope)
Morten Welinder's avatar
Morten Welinder committed
212
{
213
	GnmExprName *ans;
Morten Welinder's avatar
Morten Welinder committed
214

215
	ans = CHUNK_ALLOC (GnmExprName, expression_pool);
216 217
	if (!ans)
		return NULL;
218

219
	ans->ref_count = 1;
220
	ans->oper = GNM_EXPR_OP_NAME;
221
	ans->name = name;
222
	expr_name_ref (name);
223

224 225 226
	ans->optional_scope = optional_scope;
	ans->optional_wb_scope = optional_wb_scope;

227
	return (GnmExpr *)ans;
Morten Welinder's avatar
Morten Welinder committed
228
}
229

Jody Goldberg's avatar
Jody Goldberg committed
230 231 232 233 234 235 236 237 238
/***************************************************************************/

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

239
GnmExpr const *
Jody Goldberg's avatar
Jody Goldberg committed
240
gnm_expr_new_cellref (GnmCellRef const *cr)
241
{
242
	GnmExprCellRef *ans;
243

244
	ans = CHUNK_ALLOC (GnmExprCellRef, expression_pool);
245 246
	if (!ans)
		return NULL;
247

248
	ans->ref_count = 1;
249
	ans->oper = GNM_EXPR_OP_CELLREF;
250 251
	ans->ref = *cr;

252
	return (GnmExpr *)ans;
253 254
}

Jody Goldberg's avatar
Jody Goldberg committed
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
/***************************************************************************/

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

/**
 * gnm_expr_new_array :
 * @x :
 * @y :
 * @cols :
 * @rows :
 * @expr : optionally NULL.
 *
 * Absorb a referernce to @expr if it is non NULL.
 **/
274
GnmExpr const *
Jody Goldberg's avatar
Jody Goldberg committed
275
gnm_expr_new_array (int x, int y, int cols, int rows, GnmExpr const *expr)
276
{
277
	GnmExprArray *ans;
278

279
	ans = CHUNK_ALLOC (GnmExprArray, expression_pool);
280 281
	if (ans == NULL)
		return NULL;
282

283
	ans->ref_count = 1;
284
	ans->oper = GNM_EXPR_OP_ARRAY;
285 286 287 288
	ans->x = x;
	ans->y = y;
	ans->rows = rows;
	ans->cols = cols;
289
	ans->corner.value = NULL;
Jody Goldberg's avatar
Jody Goldberg committed
290
	ans->corner.expr = expr;
291
	return (GnmExpr *)ans;
292 293
}

Jody Goldberg's avatar
Jody Goldberg committed
294 295 296 297 298 299 300 301 302 303 304 305 306 307
/***************************************************************************/

#if 0
static guint
gnm_expr_set_hash (GnmExprSet const *expr)
{
	guint h = expr->oper;
	GnmExprList *l;
	for (l = expr->set; l; l = l->next)
		h = (h * 3) ^ (GPOINTER_TO_INT (l->data));
	return h;
}
#endif

308 309
GnmExpr const *
gnm_expr_new_set (GnmExprList *set)
310
{
311
	GnmExprSet *ans;
312

313
	ans = CHUNK_ALLOC (GnmExprSet, expression_pool);
314 315
	if (!ans)
		return NULL;
316

317
	ans->ref_count = 1;
318
	ans->oper = GNM_EXPR_OP_SET;
319
	ans->set = set;
320

321
	return (GnmExpr *)ans;
322 323
}

Jody Goldberg's avatar
Jody Goldberg committed
324 325
/***************************************************************************/

326 327 328
/**
 * gnm_expr_ref:
 * Increments the ref_count for an expression node.
Arturo Espinosa's avatar
Arturo Espinosa committed
329
 */
330
void
331
gnm_expr_ref (GnmExpr const *expr)
332
{
333 334
	g_return_if_fail (expr != NULL);
	g_return_if_fail (expr->any.ref_count > 0);
335

336
	((GnmExpr *)expr)->any.ref_count++;
Arturo Espinosa's avatar
Arturo Espinosa committed
337 338 339
}

static void
340
do_gnm_expr_unref (GnmExpr const *expr)
Arturo Espinosa's avatar
Arturo Espinosa committed
341
{
342
	if (--((GnmExpr *)expr)->any.ref_count > 0)
Morten Welinder's avatar
Morten Welinder committed
343 344
		return;

345
	switch (expr->any.oper) {
346
	case GNM_EXPR_OP_RANGE_CTOR:
347
	case GNM_EXPR_OP_INTERSECT:
348 349 350
	case GNM_EXPR_OP_ANY_BINARY:
		do_gnm_expr_unref (expr->binary.value_a);
		do_gnm_expr_unref (expr->binary.value_b);
Arturo Espinosa's avatar
Arturo Espinosa committed
351
		break;
352

353 354
	case GNM_EXPR_OP_FUNCALL:
		gnm_expr_list_unref (expr->func.arg_list);
Jody Goldberg's avatar
Jody Goldberg committed
355
		gnm_func_unref (expr->func.func);
Arturo Espinosa's avatar
Arturo Espinosa committed
356 357
		break;

358
	case GNM_EXPR_OP_NAME:
359
		expr_name_unref (expr->name.name);
Michael Meeks's avatar
Michael Meeks committed
360 361
		break;

362
	case GNM_EXPR_OP_CONSTANT:
Jody Goldberg's avatar
Jody Goldberg committed
363
		value_release ((GnmValue *)expr->constant.value);
364 365 366
		break;

	case GNM_EXPR_OP_CELLREF:
Arturo Espinosa's avatar
Arturo Espinosa committed
367 368
		break;

369 370
	case GNM_EXPR_OP_ANY_UNARY:
		do_gnm_expr_unref (expr->unary.value);
Arturo Espinosa's avatar
Arturo Espinosa committed
371
		break;
372

373
	case GNM_EXPR_OP_ARRAY:
374 375 376
		if (expr->array.x == 0 && expr->array.y == 0) {
			if (expr->array.corner.value)
				value_release (expr->array.corner.value);
377
			do_gnm_expr_unref (expr->array.corner.expr);
378
		}
Jody Goldberg's avatar
Jody Goldberg committed
379
		break;
380

381 382
	case GNM_EXPR_OP_SET:
		gnm_expr_list_unref (expr->set.set);
383
		break;
384 385

#ifndef DEBUG_SWITCH_ENUM
386
	default:
387
		g_assert_not_reached ();
388
		break;
389
#endif
Arturo Espinosa's avatar
Arturo Espinosa committed
390
	}
391

392
	CHUNK_FREE (expression_pool, (gpointer)expr);
393 394
}

Morten Welinder's avatar
Morten Welinder committed
395
/*
396 397
 * gnm_expr_unref:
 * Decrements the ref_count for part of a expression.  (All trees are expected
Morten Welinder's avatar
Morten Welinder committed
398 399 400
 * 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.)
 */
401
void
402
gnm_expr_unref (GnmExpr const *expr)
403
{
404 405
	g_return_if_fail (expr != NULL);
	g_return_if_fail (expr->any.ref_count > 0);
406

407
	if (expr->any.ref_count == 1)
408
		do_gnm_expr_unref (expr);
409
	else
410
		((GnmExpr *)expr)->any.ref_count--;
411 412
}

Jody Goldberg's avatar
Jody Goldberg committed
413
/**
414
 * gnm_expr_is_shared : Returns TRUE if the reference count
Jody Goldberg's avatar
Jody Goldberg committed
415 416 417
 *   for the supplied expression is > 1
 */
gboolean
418
gnm_expr_is_shared (GnmExpr const *expr)
Jody Goldberg's avatar
Jody Goldberg committed
419
{
420
	g_return_val_if_fail (expr != NULL, FALSE);
Jody Goldberg's avatar
Jody Goldberg committed
421

422
	return (expr->any.ref_count > 1);
Jody Goldberg's avatar
Jody Goldberg committed
423 424
}

Jody Goldberg's avatar
Jody Goldberg committed
425
/**
426
 * gnm_expr_equal : Returns TRUE if the supplied expressions are exactly the
Jody Goldberg's avatar
Jody Goldberg committed
427 428 429 430 431
 *   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
432
gnm_expr_equal (GnmExpr const *a, GnmExpr const *b)
Jody Goldberg's avatar
Jody Goldberg committed
433 434 435 436 437 438 439 440 441 442 443
{
	if (a == b)
		return TRUE;

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

	if (a->any.oper != b->any.oper)
		return FALSE;

	switch (a->any.oper) {
444
	case GNM_EXPR_OP_RANGE_CTOR:
445
	case GNM_EXPR_OP_INTERSECT:
446 447 448
	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
449

450 451
	case GNM_EXPR_OP_ANY_UNARY:
		return gnm_expr_equal (a->unary.value, b->unary.value);
Jody Goldberg's avatar
Jody Goldberg committed
452

453
	case GNM_EXPR_OP_FUNCALL:
454
		return (a->func.func == b->func.func) &&
455
			gnm_expr_list_equal (a->func.arg_list, b->func.arg_list);
Jody Goldberg's avatar
Jody Goldberg committed
456

457
	case GNM_EXPR_OP_NAME:
458 459 460
		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
461

462 463
	case GNM_EXPR_OP_CELLREF:
		return cellref_equal (&a->cellref.ref, &b->cellref.ref);
Jody Goldberg's avatar
Jody Goldberg committed
464

465 466
	case GNM_EXPR_OP_CONSTANT:
		return value_equal (a->constant.value, b->constant.value);
Jody Goldberg's avatar
Jody Goldberg committed
467

468 469 470
	case GNM_EXPR_OP_ARRAY: {
		GnmExprArray const *aa = &a->array;
		GnmExprArray const *ab = &b->array;
Jody Goldberg's avatar
Jody Goldberg committed
471 472 473 474 475

		return	aa->cols == ab->cols &&
			aa->rows == ab->rows &&
			aa->x == ab->x &&
			aa->y == ab->y &&
476
			gnm_expr_equal (aa->corner.expr, ab->corner.expr);
Jody Goldberg's avatar
Jody Goldberg committed
477 478
	}

479 480
	case GNM_EXPR_OP_SET:
		return gnm_expr_list_equal (a->set.set, b->set.set);
Jody Goldberg's avatar
Jody Goldberg committed
481 482 483 484 485
	}

	return FALSE;
}

486
static GnmCell *
487
expr_array_corner (GnmExpr const *expr,
Jody Goldberg's avatar
Jody Goldberg committed
488
		   Sheet const *sheet, GnmCellPos const *pos)
489
{
490
	GnmCell *corner = sheet_cell_get (sheet,
491 492 493 494 495 496 497 498 499 500 501 502 503 504
		pos->col - expr->array.x, pos->row - expr->array.y);

	/* 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);
	g_return_val_if_fail (corner->base.expression->any.oper == GNM_EXPR_OP_ARRAY, NULL);
	g_return_val_if_fail (corner->base.expression->array.x == 0, NULL);
	g_return_val_if_fail (corner->base.expression->array.y == 0, NULL);

	return corner;
}

static gboolean
Jody Goldberg's avatar
Jody Goldberg committed
505
gnm_expr_extract_ref (GnmRangeRef *res, GnmExpr const *expr,
Morten Welinder's avatar
Morten Welinder committed
506
		      GnmEvalPos const *pos, GnmExprEvalFlags flags)
507 508 509 510
{
	switch (expr->any.oper) {
	case GNM_EXPR_OP_FUNCALL : {
		gboolean failed = TRUE;
Jody Goldberg's avatar
Jody Goldberg committed
511
		GnmValue *v;
512 513 514 515
		FunctionEvalInfo ei;
		ei.pos = pos;
		ei.func_call = (GnmExprFunction const *)expr;

516
		v = function_call_with_list (&ei, expr->func.arg_list, flags);
517
		if (v != NULL) {
Jody Goldberg's avatar
Jody Goldberg committed
518 519
			if (v->type == VALUE_CELLRANGE) {
				*res = v->v_range.cell;
520 521 522 523 524 525 526 527
				failed = FALSE;
			}
			value_release (v);
		}
		return failed;
	}

	case GNM_EXPR_OP_CELLREF :
Jody Goldberg's avatar
Jody Goldberg committed
528 529
		res->a = expr->cellref.ref;
		res->b = expr->cellref.ref;
530 531 532
		return FALSE;

	case GNM_EXPR_OP_CONSTANT: {
Jody Goldberg's avatar
Jody Goldberg committed
533
		GnmValue const *v = expr->constant.value;
Jody Goldberg's avatar
Jody Goldberg committed
534 535
		if (v->type == VALUE_CELLRANGE) {
			*res = v->v_range.cell;
536 537 538 539 540 541
			return FALSE;
		}
		return TRUE;
	}

	case GNM_EXPR_OP_NAME:
542
		if (!expr->name.name->active)
543
			return TRUE;
544
		return gnm_expr_extract_ref (res, expr->name.name->expr, pos, flags);
545 546 547 548 549 550
	default :
		break;
	}
	return TRUE;
}

Jody Goldberg's avatar
Jody Goldberg committed
551 552
static inline GnmValue *
handle_empty (GnmValue *res, GnmExprEvalFlags flags)
553 554 555 556 557 558 559 560 561 562 563 564 565
{
	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
566 567
/**
 * value_intersection :
568
 * @v   : a VALUE_CELLRANGE or VALUE_ARRAY
Morten Welinder's avatar
Morten Welinder committed
569
 * @pos :
Jody Goldberg's avatar
Jody Goldberg committed
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
 *
 * 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
585
static GnmValue *
Morten Welinder's avatar
Morten Welinder committed
586
value_intersection (GnmValue *v, GnmEvalPos const *pos)
Jody Goldberg's avatar
Jody Goldberg committed
587
{
Jody Goldberg's avatar
Jody Goldberg committed
588 589
	GnmValue *res = NULL;
	GnmRange r;
Jody Goldberg's avatar
Jody Goldberg committed
590 591 592 593
	Sheet *start_sheet, *end_sheet;
	gboolean found = FALSE;

	if (v->type == VALUE_ARRAY) {
594
		res = value_dup (v->v_array.vals[0][0]);
Jody Goldberg's avatar
Jody Goldberg committed
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
		value_release (v);
		return res;
	}

	/* inverted ranges */
	rangeref_normalize (&v->v_range.cell, pos, &start_sheet, &end_sheet, &r);
	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) {
623
			GnmCell *cell = sheet_cell_get (
Jody Goldberg's avatar
Jody Goldberg committed
624 625 626 627 628
				eval_sheet (start_sheet, pos->sheet),
				col, row);
			if (cell == NULL)
				return value_new_empty ();
			cell_eval (cell);
629
			return value_dup (cell->value);
Jody Goldberg's avatar
Jody Goldberg committed
630 631 632
		}
	}

633
	return value_new_error_VALUE (pos);
Jody Goldberg's avatar
Jody Goldberg committed
634
}
635

Jody Goldberg's avatar
Jody Goldberg committed
636
static GnmValue *
637 638
bin_arith (GnmExpr const *expr, GnmEvalPos const *ep,
	   GnmValue const *a, GnmValue const *b)
Jody Goldberg's avatar
Jody Goldberg committed
639
{
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
	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.  */
		switch (expr->any.oper){
		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);
670 671
			dres = gnm_pow ((gnm_float)ia, (gnm_float)ib);
			if (!gnm_finite (dres))
672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
				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);

		switch (expr->any.oper){
		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);

709 710
			res = gnm_pow (va, vb);
			return gnm_finite (res)
711 712 713 714 715 716 717 718 719
				? 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
720 721
}

Jody Goldberg's avatar
Jody Goldberg committed
722
static GnmValue *
723
bin_cmp (GnmExprOp op, GnmValDiff comp, GnmEvalPos const *ep)
724 725 726 727 728 729 730 731 732 733 734
{
	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);

735
		return value_new_error_VALUE (ep);
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
	}

	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
	}
751
	return value_new_error (ep, _("Internal type error"));
752 753
}

Jody Goldberg's avatar
Jody Goldberg committed
754
static GnmValue *
755 756
cb_bin_cmp (GnmEvalPos const *ep, GnmValue const *a, GnmValue const *b,
	    GnmExpr const *expr)
757
{
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
	if (a != NULL && a->type == VALUE_ERROR)
		return value_dup (a);
	if (b != NULL && b->type == VALUE_ERROR)
		return value_dup (b);
	return bin_cmp (expr->any.oper, value_compare (a, b, FALSE), ep);
}

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
775
	if (VALUE_IS_EMPTY (a))
776
		a = va = (GnmValue *)value_zero;
777 778 779 780 781 782 783 784 785
	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
786
	if (VALUE_IS_EMPTY (b))
787
		b = vb = (GnmValue *)value_zero;
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 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
	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;
}

903 904
static inline GnmValue *
negate_value (GnmValue const *v)
905
{
906
	GnmValue *tmp;
907
	GOFormat *fmt; 
908 909

	if (v->type == VALUE_INTEGER) {
910 911 912 913 914
		int i = v->v_int.val;
		if (i < 0 && -i < 0)
			tmp = value_new_float (-(gnm_float)i);
		else
			tmp = value_new_int (-i);
915 916 917 918 919
		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) {
920
		/* Silly, but XL compatible.  */
921 922 923
		tmp = value_new_int (v->v_bool.val ? -1 : 0);
		fmt = VALUE_FMT (v);
	} else
924
		return NULL;
925 926 927 928 929

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

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

958 959 960 961 962 963 964 965
	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)
{
966
	GnmValue *tmp;
967 968 969 970 971

	if (VALUE_IS_EMPTY (v))
		tmp = value_new_int (0);
	else if (v->type == VALUE_ERROR)
		tmp = value_dup (v);
972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987
	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);
			VALUE_FMT (tmp) = style_format_default_percentage ();
			style_format_ref (VALUE_FMT (tmp));
		} else
			tmp = value_new_error_VALUE (ep);

988
		if (conv != NULL)
989
			value_release (conv);
990 991 992 993
	}

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

Jody Goldberg's avatar
Jody Goldberg committed
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 1023 1024 1025 1026 1027
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);

	rangeref_normalize (&a_ref, ep, &a_start, &a_end, &a_range);
	rangeref_normalize (&b_ref, ep, &b_start, &b_end, &b_range);

	if (expr->any.oper != GNM_EXPR_OP_INTERSECT)
		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);
	dependent_add_dynamic_dep (ep->dep, &res->v_range);
	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;
}

1028 1029 1030 1031 1032 1033 1034 1035
/**
 * 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.
1036
 **/
Jody Goldberg's avatar
Jody Goldberg committed
1037
GnmValue *
Morten Welinder's avatar
Morten Welinder committed
1038
gnm_expr_eval (GnmExpr const *expr, GnmEvalPos const *pos,
1039
	       GnmExprEvalFlags flags)
Arturo Espinosa's avatar
Arturo Espinosa committed
1040
{
Jody Goldberg's avatar
Jody Goldberg committed
1041
	GnmValue *res = NULL, *a = NULL, *b = NULL;
1042

1043 1044
	g_return_val_if_fail (expr != NULL, handle_empty (NULL, flags));
	g_return_val_if_fail (pos != NULL, handle_empty (NULL, flags));
1045

1046
	switch (expr->any.oper){
1047 1048 1049 1050 1051
	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:
1052
	case GNM_EXPR_OP_LTE:
Jody Goldberg's avatar
Jody Goldberg committed
1053
		flags |= GNM_EXPR_EVAL_PERMIT_EMPTY;
Morten Welinder's avatar
Morten Welinder committed
1054

Jody Goldberg's avatar
Jody Goldberg committed
1055
		a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1056 1057 1058 1059 1060 1061 1062 1063 1064
		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
1065 1066

		b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076
		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
1077
		}
1078

1079
		res = bin_cmp (expr->any.oper, value_compare (a, b, FALSE), pos);
1080 1081 1082 1083
		if (a != NULL)
			value_release (a);
		if (b != NULL)
			value_release (b);
1084
		return res;
1085

1086 1087 1088 1089 1090
	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:
1091 1092 1093 1094 1095 1096 1097 1098 1099
		/*
		 * 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
1100
	        /* Guarantees value != NULL */
1101
		flags &= ~GNM_EXPR_EVAL_PERMIT_EMPTY;
Jody Goldberg's avatar
Jody Goldberg committed
1102

1103
		/* 1) Error from A */
Jody Goldberg's avatar
Jody Goldberg committed
1104
		a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1105
		if (a->type == VALUE_ERROR)
1106
			return value_error_set_pos (&a->v_err, pos);
1107

1108
		/* 2) #!VALUE error if A is not a number */
1109
		if (a->type == VALUE_STRING) {
Jody Goldberg's avatar
Jody Goldberg committed
1110
			GnmValue *tmp = format_match_number (a->v_str.val->str, NULL,
1111
				workbook_date_conv (pos->sheet->workbook));
1112 1113 1114

			value_release (a);
			if (tmp == NULL)
1115
				return value_new_error_VALUE (pos);
1116
			a = tmp;
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
		} 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);
1128
		} else if (!VALUE_IS_NUMBER (a)) {
1129
			value_release (a);
1130
			return value_new_error_VALUE (pos);
1131 1132 1133
		}

		/* 3) Error from B */
Jody Goldberg's avatar
Jody Goldberg committed
1134
		b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1135
		if (b->type == VALUE_ERROR) {
1136
			value_release (a);
1137
			return value_error_set_pos (&b->v_err, pos);
Arturo Espinosa's avatar
Arturo Espinosa committed
1138
		}
1139

1140
		/* 4) #!VALUE error if B is not a number */
1141
		if (b->type == VALUE_STRING) {
Jody Goldberg's avatar
Jody Goldberg committed
1142
			GnmValue *tmp = format_match_number (b->v_str.val->str, NULL,
1143
				workbook_date_conv (pos->sheet->workbook));
1144 1145 1146 1147

			value_release (b);
			if (tmp == NULL) {
				value_release (a);
1148
				return value_new_error_VALUE (pos);
1149 1150
			}
			b = tmp;
1151 1152 1153 1154
		} else if (b->type == VALUE_CELLRANGE || b->type == VALUE_ARRAY)
			return bin_array_op (pos, b, a, b,
				(BinOpImplicitIteratorFunc) cb_bin_arith,
				(gpointer) expr);
Jody Goldberg's avatar
Jody Goldberg committed
1155 1156 1157 1158 1159 1160 1161
		else if (!VALUE_IS_NUMBER (b)) {
			value_release (a);
			value_release (b);
			return value_new_error_VALUE (pos);
		}

		res = bin_arith (expr, pos, a, b);
1162 1163 1164
		value_release (a);
		value_release (b);
		return res;
1165

1166 1167 1168
	case GNM_EXPR_OP_PERCENTAGE:
	case GNM_EXPR_OP_UNARY_NEG:
	case GNM_EXPR_OP_UNARY_PLUS:
Jody Goldberg's avatar
Jody Goldberg committed
1169
	        /* Guarantees value != NULL */
Jody Goldberg's avatar
Jody Goldberg committed
1170
		flags &= ~GNM_EXPR_EVAL_PERMIT_EMPTY;
Jody Goldberg's avatar
Jody Goldberg committed
1171

Jody Goldberg's avatar
Jody Goldberg committed
1172
		a = gnm_expr_eval (expr->unary.value, pos, flags);
1173 1174
		if (a->type == VALUE_ERROR)
			return a;
1175
		if (expr->any.oper == GNM_EXPR_OP_UNARY_PLUS)
Jody Goldberg's avatar
Jody Goldberg committed
1176 1177
			return a;

1178 1179 1180 1181 1182
		/* 2) #!VALUE error if A is not a number */
		if (a->type == VALUE_STRING) {
			GnmValue *tmp = format_match_number (a->v_str.val->str, NULL,
				workbook_date_conv (pos->sheet->workbook));

1183
			value_release (a);
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
			if (tmp == NULL)
				return value_new_error_VALUE (pos);
			a = tmp;
		} else if (a->type == VALUE_CELLRANGE || a->type == VALUE_ARRAY) {
			res = value_new_array_empty (
				value_area_get_width  (a, pos),
				value_area_get_height (a, pos));
			value_area_foreach (a, pos, CELL_ITER_ALL,
				(ValueAreaFunc) ((expr->any.oper == GNM_EXPR_OP_UNARY_NEG) 
					? cb_iter_unary_neg : cb_iter_percentage),
				res);
			value_release (a);
			return res;
1197
		}
1198 1199
		if (!VALUE_IS_NUMBER (a))
			res = value_new_error_VALUE (pos);
1200 1201 1202
		else if (expr->any.oper == GNM_EXPR_OP_UNARY_NEG)
			res = negate_value (a);
		else {
Morten Welinder's avatar
Morten Welinder committed
1203
			res = value_new_float (value_get_as_float (a) / 100);
1204 1205 1206
			VALUE_FMT (res) = style_format_default_percentage ();
			style_format_ref (VALUE_FMT (res));
		}
1207
		value_release (a);
Morten Welinder's avatar
Morten Welinder committed
1208
		return res;
1209

1210
	case GNM_EXPR_OP_CAT:
1211
		flags |= GNM_EXPR_EVAL_PERMIT_EMPTY;
Jody Goldberg's avatar
Jody Goldberg committed
1212
		a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1213 1214 1215 1216 1217 1218 1219 1220 1221
		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_cat