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

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

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

49 50 51 52 53 54 55 56 57 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 *
120
gnm_expr_new_funcall (GnmFunc *func, GnmExprList *arg_list)
121
{
122
	GnmExprFunction *ans;
Jody Goldberg's avatar
Jody Goldberg committed
123
	g_return_val_if_fail (func, NULL);
124

125
	ans = CHUNK_ALLOC (GnmExprFunction, expression_pool);
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);
132 133
	ans->func = func;
	ans->arg_list = arg_list;
134

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
/***************************************************************************/

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

/**
266
 * gnm_expr_new_array_corner :
Jody Goldberg's avatar
Jody Goldberg committed
267 268 269 270 271 272
 * @cols :
 * @rows :
 * @expr : optionally NULL.
 *
 * Absorb a referernce to @expr if it is non NULL.
 **/
273
GnmExpr const *
274
gnm_expr_new_array_corner(int cols, int rows, GnmExpr const *expr)
275
{
276
	GnmExprArrayCorner *ans;
277

278
	ans = CHUNK_ALLOC (GnmExprArrayCorner, expression_pool);
279 280
	if (ans == NULL)
		return NULL;
281

282
	ans->ref_count = 1;
283
	ans->oper = GNM_EXPR_OP_ARRAY_CORNER;
284 285
	ans->rows = rows;
	ans->cols = cols;
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
	ans->value = NULL;
	ans->expr = expr;
	return (GnmExpr *)ans;
}

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

	ans = CHUNK_ALLOC (GnmExprArrayElem, expression_pool);
	if (ans == NULL)
		return NULL;

	ans->ref_count = 1;
	ans->oper = GNM_EXPR_OP_ARRAY_ELEM;
	ans->x = x;
	ans->y = y;
304
	return (GnmExpr *)ans;
305 306
}

Jody Goldberg's avatar
Jody Goldberg committed
307 308 309 310 311 312 313 314 315 316 317 318 319 320
/***************************************************************************/

#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

321 322
GnmExpr const *
gnm_expr_new_set (GnmExprList *set)
323
{
324
	GnmExprSet *ans;
325

326
	ans = CHUNK_ALLOC (GnmExprSet, expression_pool);
327 328
	if (!ans)
		return NULL;
329

330
	ans->ref_count = 1;
331
	ans->oper = GNM_EXPR_OP_SET;
332
	ans->set = set;
333

334
	return (GnmExpr *)ans;
335 336
}

Jody Goldberg's avatar
Jody Goldberg committed
337 338
/***************************************************************************/

339 340 341
/**
 * gnm_expr_ref:
 * Increments the ref_count for an expression node.
Arturo Espinosa's avatar
Arturo Espinosa committed
342
 */
343
void
344
gnm_expr_ref (GnmExpr const *expr)
345
{
346 347
	g_return_if_fail (expr != NULL);
	g_return_if_fail (expr->any.ref_count > 0);
348

349
	((GnmExpr *)expr)->any.ref_count++;
Arturo Espinosa's avatar
Arturo Espinosa committed
350 351 352
}

static void
353
do_gnm_expr_unref (GnmExpr const *expr)
Arturo Espinosa's avatar
Arturo Espinosa committed
354
{
355
	if (--((GnmExpr *)expr)->any.ref_count > 0)
Morten Welinder's avatar
Morten Welinder committed
356 357
		return;

358
	switch (expr->any.oper) {
359
	case GNM_EXPR_OP_RANGE_CTOR:
360
	case GNM_EXPR_OP_INTERSECT:
361 362 363
	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
364
		break;
365

366 367
	case GNM_EXPR_OP_FUNCALL:
		gnm_expr_list_unref (expr->func.arg_list);
Jody Goldberg's avatar
Jody Goldberg committed
368
		gnm_func_unref (expr->func.func);
Arturo Espinosa's avatar
Arturo Espinosa committed
369 370
		break;

371
	case GNM_EXPR_OP_NAME:
372
		expr_name_unref (expr->name.name);
Michael Meeks's avatar
Michael Meeks committed
373 374
		break;

375
	case GNM_EXPR_OP_CONSTANT:
Jody Goldberg's avatar
Jody Goldberg committed
376
		value_release ((GnmValue *)expr->constant.value);
377 378 379
		break;

	case GNM_EXPR_OP_CELLREF:
Arturo Espinosa's avatar
Arturo Espinosa committed
380 381
		break;

382 383
	case GNM_EXPR_OP_ANY_UNARY:
		do_gnm_expr_unref (expr->unary.value);
Arturo Espinosa's avatar
Arturo Espinosa committed
384
		break;
385

386 387 388 389 390 391 392
	case GNM_EXPR_OP_ARRAY_CORNER:
		if (expr->array_corner.value)
			value_release (expr->array_corner.value);
		do_gnm_expr_unref (expr->array_corner.expr);
		break;

	case GNM_EXPR_OP_ARRAY_ELEM:
Jody Goldberg's avatar
Jody Goldberg committed
393
		break;
394

395 396
	case GNM_EXPR_OP_SET:
		gnm_expr_list_unref (expr->set.set);
397
		break;
398 399

#ifndef DEBUG_SWITCH_ENUM
400
	default:
401
		g_assert_not_reached ();
402
		break;
403
#endif
Arturo Espinosa's avatar
Arturo Espinosa committed
404
	}
405

406
	CHUNK_FREE (expression_pool, (gpointer)expr);
407 408
}

Morten Welinder's avatar
Morten Welinder committed
409
/*
410 411
 * gnm_expr_unref:
 * Decrements the ref_count for part of a expression.  (All trees are expected
Morten Welinder's avatar
Morten Welinder committed
412 413 414
 * 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.)
 */
415
void
416
gnm_expr_unref (GnmExpr const *expr)
417
{
418 419
	g_return_if_fail (expr != NULL);
	g_return_if_fail (expr->any.ref_count > 0);
420

421
	if (expr->any.ref_count == 1)
422
		do_gnm_expr_unref (expr);
423
	else
424
		((GnmExpr *)expr)->any.ref_count--;
425 426
}

Jody Goldberg's avatar
Jody Goldberg committed
427
/**
428
 * gnm_expr_is_shared : Returns TRUE if the reference count
Jody Goldberg's avatar
Jody Goldberg committed
429 430 431
 *   for the supplied expression is > 1
 */
gboolean
432
gnm_expr_is_shared (GnmExpr const *expr)
Jody Goldberg's avatar
Jody Goldberg committed
433
{
434
	g_return_val_if_fail (expr != NULL, FALSE);
Jody Goldberg's avatar
Jody Goldberg committed
435

436
	return (expr->any.ref_count > 1);
Jody Goldberg's avatar
Jody Goldberg committed
437 438
}

Jody Goldberg's avatar
Jody Goldberg committed
439
/**
440
 * gnm_expr_equal : Returns TRUE if the supplied expressions are exactly the
Jody Goldberg's avatar
Jody Goldberg committed
441 442 443 444 445
 *   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
446
gnm_expr_equal (GnmExpr const *a, GnmExpr const *b)
Jody Goldberg's avatar
Jody Goldberg committed
447 448 449 450 451 452 453 454 455 456 457
{
	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) {
458
	case GNM_EXPR_OP_RANGE_CTOR:
459
	case GNM_EXPR_OP_INTERSECT:
460 461 462
	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
463

464 465
	case GNM_EXPR_OP_ANY_UNARY:
		return gnm_expr_equal (a->unary.value, b->unary.value);
Jody Goldberg's avatar
Jody Goldberg committed
466

467
	case GNM_EXPR_OP_FUNCALL:
468
		return (a->func.func == b->func.func) &&
469
			gnm_expr_list_equal (a->func.arg_list, b->func.arg_list);
Jody Goldberg's avatar
Jody Goldberg committed
470

471
	case GNM_EXPR_OP_NAME:
472 473 474
		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
475

476
	case GNM_EXPR_OP_CELLREF:
477
		return gnm_cellref_equal (&a->cellref.ref, &b->cellref.ref);
Jody Goldberg's avatar
Jody Goldberg committed
478

479 480
	case GNM_EXPR_OP_CONSTANT:
		return value_equal (a->constant.value, b->constant.value);
Jody Goldberg's avatar
Jody Goldberg committed
481

482 483 484
	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
485 486 487

		return	aa->cols == ab->cols &&
			aa->rows == ab->rows &&
488 489 490 491 492 493
			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
494 495
	}

496 497
	case GNM_EXPR_OP_SET:
		return gnm_expr_list_equal (a->set.set, b->set.set);
Jody Goldberg's avatar
Jody Goldberg committed
498 499 500 501 502
	}

	return FALSE;
}

503
static GnmCell *
504 505
array_elem_get_corner (GnmExprArrayElem const *elem,
		       Sheet const *sheet, GnmCellPos const *pos)
506
{
507
	GnmCell *corner = sheet_cell_get (sheet,
508
		pos->col - elem->x, pos->row - elem->y);
509 510 511 512 513

	/* 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);
514
	g_return_val_if_fail (corner->base.expression->any.oper == GNM_EXPR_OP_ARRAY_CORNER, NULL);
515 516 517 518 519

	return corner;
}

static gboolean
Jody Goldberg's avatar
Jody Goldberg committed
520
gnm_expr_extract_ref (GnmRangeRef *res, GnmExpr const *expr,
Morten Welinder's avatar
Morten Welinder committed
521
		      GnmEvalPos const *pos, GnmExprEvalFlags flags)
522 523 524 525
{
	switch (expr->any.oper) {
	case GNM_EXPR_OP_FUNCALL : {
		gboolean failed = TRUE;
Jody Goldberg's avatar
Jody Goldberg committed
526
		GnmValue *v;
527 528 529 530
		FunctionEvalInfo ei;
		ei.pos = pos;
		ei.func_call = (GnmExprFunction const *)expr;

531
		v = function_call_with_list (&ei, expr->func.arg_list, flags);
532
		if (v != NULL) {
Jody Goldberg's avatar
Jody Goldberg committed
533 534
			if (v->type == VALUE_CELLRANGE) {
				*res = v->v_range.cell;
535 536 537 538 539 540 541 542
				failed = FALSE;
			}
			value_release (v);
		}
		return failed;
	}

	case GNM_EXPR_OP_CELLREF :
Jody Goldberg's avatar
Jody Goldberg committed
543 544
		res->a = expr->cellref.ref;
		res->b = expr->cellref.ref;
545 546 547
		return FALSE;

	case GNM_EXPR_OP_CONSTANT: {
Jody Goldberg's avatar
Jody Goldberg committed
548
		GnmValue const *v = expr->constant.value;
Jody Goldberg's avatar
Jody Goldberg committed
549 550
		if (v->type == VALUE_CELLRANGE) {
			*res = v->v_range.cell;
551 552 553 554 555 556
			return FALSE;
		}
		return TRUE;
	}

	case GNM_EXPR_OP_NAME:
557
		if (!expr->name.name->active)
558
			return TRUE;
559
		return gnm_expr_extract_ref (res, expr->name.name->expr, pos, flags);
560 561 562 563 564 565
	default :
		break;
	}
	return TRUE;
}

Jody Goldberg's avatar
Jody Goldberg committed
566 567
static inline GnmValue *
handle_empty (GnmValue *res, GnmExprEvalFlags flags)
568 569 570 571 572 573 574 575 576 577 578 579 580
{
	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
581 582
/**
 * value_intersection :
583
 * @v   : a VALUE_CELLRANGE or VALUE_ARRAY
Morten Welinder's avatar
Morten Welinder committed
584
 * @pos :
Jody Goldberg's avatar
Jody Goldberg committed
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
 *
 * 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
600
static GnmValue *
Morten Welinder's avatar
Morten Welinder committed
601
value_intersection (GnmValue *v, GnmEvalPos const *pos)
Jody Goldberg's avatar
Jody Goldberg committed
602
{
Jody Goldberg's avatar
Jody Goldberg committed
603 604
	GnmValue *res = NULL;
	GnmRange r;
Jody Goldberg's avatar
Jody Goldberg committed
605 606 607 608
	Sheet *start_sheet, *end_sheet;
	gboolean found = FALSE;

	if (v->type == VALUE_ARRAY) {
609
		res = value_dup (v->v_array.vals[0][0]);
Jody Goldberg's avatar
Jody Goldberg committed
610 611 612 613 614
		value_release (v);
		return res;
	}

	/* inverted ranges */
615
	gnm_rangeref_normalize (&v->v_range.cell, pos, &start_sheet, &end_sheet, &r);
Jody Goldberg's avatar
Jody Goldberg committed
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
	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) {
638
			GnmCell *cell = sheet_cell_get (
Jody Goldberg's avatar
Jody Goldberg committed
639 640 641 642 643
				eval_sheet (start_sheet, pos->sheet),
				col, row);
			if (cell == NULL)
				return value_new_empty ();
			cell_eval (cell);
644
			return value_dup (cell->value);
Jody Goldberg's avatar
Jody Goldberg committed
645 646 647
		}
	}

648
	return value_new_error_VALUE (pos);
Jody Goldberg's avatar
Jody Goldberg committed
649
}
650

Jody Goldberg's avatar
Jody Goldberg committed
651
static GnmValue *
652 653
bin_arith (GnmExpr const *expr, GnmEvalPos const *ep,
	   GnmValue const *a, GnmValue const *b)
Jody Goldberg's avatar
Jody Goldberg committed
654
{
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
	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);
685 686
			dres = gnm_pow ((gnm_float)ia, (gnm_float)ib);
			if (!gnm_finite (dres))
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723
				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);

724 725
			res = gnm_pow (va, vb);
			return gnm_finite (res)
726 727 728 729 730 731 732 733 734
				? 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
735 736
}

Jody Goldberg's avatar
Jody Goldberg committed
737
static GnmValue *
738
bin_cmp (GnmExprOp op, GnmValDiff comp, GnmEvalPos const *ep)
739 740 741 742 743 744 745 746 747 748 749
{
	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);

750
		return value_new_error_VALUE (ep);
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
	}

	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
	}
766
	return value_new_error (ep, _("Internal type error"));
767 768
}

Jody Goldberg's avatar
Jody Goldberg committed
769
static GnmValue *
770 771
cb_bin_cmp (GnmEvalPos const *ep, GnmValue const *a, GnmValue const *b,
	    GnmExpr const *expr)
772
{
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
	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
790
	if (VALUE_IS_EMPTY (a))
791
		a = va = (GnmValue *)value_zero;
792 793 794 795 796 797 798 799 800
	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
801
	if (VALUE_IS_EMPTY (b))
802
		b = vb = (GnmValue *)value_zero;
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 904 905 906 907 908 909 910 911 912 913 914 915 916 917
	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;
}

918 919
static inline GnmValue *
negate_value (GnmValue const *v)
920
{
921
	GnmValue *tmp;
922
	GOFormat *fmt; 
923 924

	if (v->type == VALUE_INTEGER) {
925 926 927 928 929
		int i = v->v_int.val;
		if (i < 0 && -i < 0)
			tmp = value_new_float (-(gnm_float)i);
		else
			tmp = value_new_int (-i);
930 931 932 933 934
		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) {
935
		/* Silly, but XL compatible.  */
936 937 938
		tmp = value_new_int (v->v_bool.val ? -1 : 0);
		fmt = VALUE_FMT (v);
	} else
939
		return NULL;
940 941 942

	if (fmt != NULL) {
		VALUE_FMT (tmp) = fmt;
943
		go_format_ref (fmt);
944
	}
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972

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

973 974 975 976 977 978 979 980
	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)
{
981
	GnmValue *tmp;
982 983 984 985 986

	if (VALUE_IS_EMPTY (v))
		tmp = value_new_int (0);
	else if (v->type == VALUE_ERROR)
		tmp = value_dup (v);
987 988 989 990 991 992 993 994 995 996 997
	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);
998 999
			VALUE_FMT (tmp) = go_format_default_percentage ();
			go_format_ref (VALUE_FMT (tmp));
1000 1001 1002
		} else
			tmp = value_new_error_VALUE (ep);

1003
		if (conv != NULL)
1004
			value_release (conv);
1005 1006 1007 1008
	}

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

Jody Goldberg's avatar
Jody Goldberg committed
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
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);

1024 1025
	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
1026 1027 1028 1029 1030 1031 1032

	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);
1033
	dependent_add_dynamic_dep (ep->dep, &res->v_range.cell);
Jody Goldberg's avatar
Jody Goldberg committed
1034 1035 1036 1037 1038 1039 1040 1041 1042
	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;
}

1043 1044 1045 1046 1047 1048 1049 1050
/**
 * 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.
1051
 **/
Jody Goldberg's avatar
Jody Goldberg committed
1052
GnmValue *
Morten Welinder's avatar
Morten Welinder committed
1053
gnm_expr_eval (GnmExpr const *expr, GnmEvalPos const *pos,
1054
	       GnmExprEvalFlags flags)
Arturo Espinosa's avatar
Arturo Espinosa committed
1055
{
Jody Goldberg's avatar
Jody Goldberg committed
1056
	GnmValue *res = NULL, *a = NULL, *b = NULL;
1057

1058 1059
	g_return_val_if_fail (expr != NULL, handle_empty (NULL, flags));
	g_return_val_if_fail (pos != NULL, handle_empty (NULL, flags));
1060

1061
	switch (expr->any.oper){
1062 1063 1064 1065 1066
	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:
1067
	case GNM_EXPR_OP_LTE:
Jody Goldberg's avatar
Jody Goldberg committed
1068
		flags |= GNM_EXPR_EVAL_PERMIT_EMPTY;
Morten Welinder's avatar
Morten Welinder committed
1069

Jody Goldberg's avatar
Jody Goldberg committed
1070
		a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1071 1072 1073 1074 1075 1076 1077 1078 1079
		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
1080 1081

		b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
		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
1092
		}
1093

1094
		res = bin_cmp (expr->any.oper, value_compare (a, b, FALSE), pos);
1095 1096 1097 1098
		if (a != NULL)
			value_release (a);
		if (b != NULL)
			value_release (b);
1099
		return res;
1100

1101 1102 1103 1104 1105
	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:
1106 1107 1108 1109 1110 1111 1112 1113 1114
		/*
		 * 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
1115
	        /* Guarantees value != NULL */
1116
		flags &= ~GNM_EXPR_EVAL_PERMIT_EMPTY;
Jody Goldberg's avatar
Jody Goldberg committed
1117

1118
		/* 1) Error from A */
Jody Goldberg's avatar
Jody Goldberg committed
1119
		a = gnm_expr_eval (expr->binary.value_a, pos, flags);
1120
		if (a->type == VALUE_ERROR)
1121
			return value_error_set_pos (&a->v_err, pos);
1122

1123
		/* 2) #!VALUE error if A is not a number */
1124
		if (a->type == VALUE_STRING) {
Jody Goldberg's avatar
Jody Goldberg committed
1125
			GnmValue *tmp = format_match_number (a->v_str.val->str, NULL,
1126
				workbook_date_conv (pos->sheet->workbook));
1127 1128 1129

			value_release (a);
			if (tmp == NULL)
1130
				return value_new_error_VALUE (pos);
1131
			a = tmp;
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
		} 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);
1143
		} else if (!VALUE_IS_NUMBER (a)) {
1144
			value_release (a);
1145
			return value_new_error_VALUE (pos);
1146 1147 1148
		}

		/* 3) Error from B */
Jody Goldberg's avatar
Jody Goldberg committed
1149
		b = gnm_expr_eval (expr->binary.value_b, pos, flags);
1150
		if (b->type == VALUE_ERROR) {
1151
			value_release (a);
1152
			return value_error_set_pos (&b->v_err, pos);
Arturo Espinosa's avatar
Arturo Espinosa committed
1153
		}
1154

1155
		/* 4) #!VALUE error if B is not a number */
1156
		if (b->type == VALUE_STRING) {
Jody Goldberg's avatar
Jody Goldberg committed
1157
			GnmValue *tmp = format_match_number (b->v_str.val->str, NULL,
1158
				workbook_date_conv (pos->sheet->workbook));
1159 1160 1161 1162

			value_release (b);
			if (tmp == NULL) {
				value_release (a);
1163
				return value_new_error_VALUE (pos);
1164 1165
			}
			b = tmp;
1166 1167 1168 1169
		} 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
1170 1171 1172 1173 1174 1175 1176
		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);
1177 1178 1179
		value_release (a);
		value_release (b);
		return res;
1180

1181 1182 1183
	case GNM_EXPR_OP_PERCENTAGE:
	case GNM_EXPR_OP_UNARY_NEG:
	case GNM_EXPR_OP_UNARY_PLUS:
Jody Goldberg's avatar
Jody Goldberg committed
1184
	        /* Guarantees value != NULL */
Jody Goldberg's avatar
Jody Goldberg committed
1185
		flags &= ~GNM_EXPR_EVAL_PERMIT_EMPTY;
Jody Goldberg's avatar
Jody Goldberg committed
1186

Jody Goldberg's avatar
Jody Goldberg committed
1187
		a = gnm_expr_eval (expr->unary.value, pos, flags);
1188 1189
		if (a->type == VALUE_ERROR)
			return a;
1190
		if (expr->any.oper == GNM_EXPR_OP_UNARY_PLUS)
Jody Goldberg's avatar
Jody Goldberg committed
1191 1192
			return a;

1193 1194 1195 1196 1197
		/* 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));

1198
			value_release (a);
1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
			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;
1212
		}