expr.c 68.8 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>
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 58
/*
 * 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.  */
59 60 61
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))
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);
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 106 107 108 109 110 111 112 113 114 115 116 117 118
/***************************************************************************/

#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

119
GnmExpr const *
Jody Goldberg's avatar
Jody Goldberg committed
120
gnm_expr_new_funcall (GnmFunc *func, GnmExprList *args)
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);
126 127
	if (!ans)
		return NULL;
128

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

135
	return (GnmExpr *)ans;
136
}
137

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

#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

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

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

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

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

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

#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
182

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

253
	return (GnmExpr *)ans;
254 255
}

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

#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.
 **/
275
GnmExpr const *
Jody Goldberg's avatar
Jody Goldberg committed
276
gnm_expr_new_array (int x, int y, int cols, int rows, GnmExpr const *expr)
277
{
278
	GnmExprArray *ans;
279

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

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

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

#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

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

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

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

322
	return (GnmExpr *)ans;
323 324
}

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

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

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

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

346
	switch (expr->any.oper) {
347
	case GNM_EXPR_OP_RANGE_CTOR:
348
	case GNM_EXPR_OP_INTERSECT:
349 350 351
	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
352
		break;
353

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

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

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

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

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

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

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

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

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

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

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

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

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

Jody Goldberg's avatar
Jody Goldberg committed
426
/**
427
 * gnm_expr_equal : Returns TRUE if the supplied expressions are exactly the
Jody Goldberg's avatar
Jody Goldberg committed
428 429 430 431 432
 *   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
433
gnm_expr_equal (GnmExpr const *a, GnmExpr const *b)
Jody Goldberg's avatar
Jody Goldberg committed
434 435 436 437 438 439 440 441 442 443 444
{
	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) {
445
	case GNM_EXPR_OP_RANGE_CTOR:
446
	case GNM_EXPR_OP_INTERSECT:
447 448 449
	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
450

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

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

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

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

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

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

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

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

	return FALSE;
}

487
static GnmCell *
488
expr_array_corner (GnmExpr const *expr,
Jody Goldberg's avatar
Jody Goldberg committed
489
		   Sheet const *sheet, GnmCellPos const *pos)
490
{
491
	GnmCell *corner = sheet_cell_get (sheet,
492 493 494 495 496 497 498 499 500 501 502 503 504 505
		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
506
gnm_expr_extract_ref (GnmRangeRef *res, GnmExpr const *expr,
Morten Welinder's avatar
Morten Welinder committed
507
		      GnmEvalPos const *pos, GnmExprEvalFlags flags)
508 509 510 511
{
	switch (expr->any.oper) {
	case GNM_EXPR_OP_FUNCALL : {
		gboolean failed = TRUE;
Jody Goldberg's avatar
Jody Goldberg committed
512
		GnmValue *v;
513 514 515 516
		FunctionEvalInfo ei;
		ei.pos = pos;
		ei.func_call = (GnmExprFunction const *)expr;

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

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

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

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

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

	if (v->type == VALUE_ARRAY) {
595
		res = value_dup (v->v_array.vals[0][0]);
Jody Goldberg's avatar
Jody Goldberg committed
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 623
		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) {
624
			GnmCell *cell = sheet_cell_get (
Jody Goldberg's avatar
Jody Goldberg committed
625 626 627 628 629
				eval_sheet (start_sheet, pos->sheet),
				col, row);
			if (cell == NULL)
				return value_new_empty ();
			cell_eval (cell);
630
			return value_dup (cell->value);
Jody Goldberg's avatar
Jody Goldberg committed
631 632 633
		}
	}

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

Jody Goldberg's avatar
Jody Goldberg committed
637
static GnmValue *
638 639
bin_arith (GnmExpr const *expr, GnmEvalPos const *ep,
	   GnmValue const *a, GnmValue const *b)
Jody Goldberg's avatar
Jody Goldberg committed
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 670
	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);
671 672
			dres = gnm_pow ((gnm_float)ia, (gnm_float)ib);
			if (!gnm_finite (dres))
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 709
				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);

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

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

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

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

Jody Goldberg's avatar
Jody Goldberg committed
755
static GnmValue *
756 757
cb_bin_cmp (GnmEvalPos const *ep, GnmValue const *a, GnmValue const *b,
	    GnmExpr const *expr)
758
{
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
	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
776
	if (VALUE_IS_EMPTY (a))
777
		a = va = (GnmValue *)value_zero;
778 779 780 781 782 783 784 785 786
	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
787
	if (VALUE_IS_EMPTY (b))
788
		b = vb = (GnmValue *)value_zero;
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 903
	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;
}

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

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

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

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

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

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

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

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

Jody Goldberg's avatar
Jody Goldberg committed
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 1028
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;
}

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

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

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

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

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

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

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

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

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

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

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

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

			value_release (b);
			if (tmp == NULL) {
				value_release (a);
1149
				return value_new_error_VALUE (pos);
1150 1151
			}
			b = tmp;
1152 1153 1154 1155
		} 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
1156 1157 1158 1159 1160 1161 1162
		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);
1163 1164 1165
		value_release (a);
		value_release (b);
		return res;
1166

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

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

1179 1180 1181 1182 1183
		/* 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));

1184
			value_release (a);
1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
			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;
1198
		}
1199 1200
		if (!VALUE_IS_NUMBER (a))
			res = value_new_error_VALUE (pos);
1201 1202 1203
		else if (expr->any.oper == GNM_EXPR_OP_UNARY_NEG)
			res = negate_value (a);
		else {
Morten Welinder's avatar
Morten Welinder committed
1204
			res = value_new_float (value_get_as_float (a) / 100);
1205 1206 1207
			VALUE_FMT (res) = style_format_default_percentage ();
			style_format_ref (VALUE_FMT (res));
		}
1208
		value_release (a);
Morten Welinder's avatar
Morten Welinder committed
1209
		return res;
1210

1211
	case GNM_EXPR_OP_CAT:
1212
		flags |= GNM_EXPR_EVAL_PERMIT_EMPTY;
Jody Goldberg's avatar
Jody Goldberg committed
1213
		a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1214 1215 1216 1217 1218 1219 1220 1221 1222
		if (a != NULL) {
			if (a->type == VALUE_ERROR)
				return a;
			if (a->type