Commit 36ab057f authored by Michael Meeks's avatar Michael Meeks

New array backend throuought, and docs on function tokens.

parent edd35c18
1999-04-11 Michael Meeks <michael@imaginator.com>
* src/expr.c (eval_funccall): New array / 'area' tokens added,
error strings simplified ( int type_mismatch added )
(value_area_get_width, value_area_get_height): Implemented,
(value_area_get_at_x_y): Implemented.
(value_array_new, value_array_resize): Implemented.
(value_release): Updated.
(value_copy_to, value_array_copy_to): Updated, created.
Added const to a scad of helper 'value_get' style functions.
* src/expr.h: Value: Changed 'array' from GList to a
structure.
Added struct _Value for self reference.
Added const to a scad of helper 'value_get' style functions.
* src/func.c (function_iterate_do_value): Updated Array code.
* src/eval.c (add_value_deps): Updated Array stuff.
(add_value_deps): const added to Value *
* src/dialog-function-wizard.c (function_type_input):
Updated text for new tokens.
* src/fn-sheet.c (gnumeric_selection): Update to new array code.
* src/fn-lookup.c (columns, rows): Updated to clean new API.
(vlookup, hlookup): Large clean.
* src/parser.y (value_dump): Updated Array section.
* docs/C/writing-functions.smgl: Added section explaining tokens,
and new API.
1999-04-09 Michael Meeks <michael@imaginator.com>
* src/sheet.c (sheet_destroy): Move destruction of cell_hash to
......
1999-04-11 Michael Meeks <michael@imaginator.com>
* src/expr.c (eval_funccall): New array / 'area' tokens added,
error strings simplified ( int type_mismatch added )
(value_area_get_width, value_area_get_height): Implemented,
(value_area_get_at_x_y): Implemented.
(value_array_new, value_array_resize): Implemented.
(value_release): Updated.
(value_copy_to, value_array_copy_to): Updated, created.
Added const to a scad of helper 'value_get' style functions.
* src/expr.h: Value: Changed 'array' from GList to a
structure.
Added struct _Value for self reference.
Added const to a scad of helper 'value_get' style functions.
* src/func.c (function_iterate_do_value): Updated Array code.
* src/eval.c (add_value_deps): Updated Array stuff.
(add_value_deps): const added to Value *
* src/dialog-function-wizard.c (function_type_input):
Updated text for new tokens.
* src/fn-sheet.c (gnumeric_selection): Update to new array code.
* src/fn-lookup.c (columns, rows): Updated to clean new API.
(vlookup, hlookup): Large clean.
* src/parser.y (value_dump): Updated Array section.
* docs/C/writing-functions.smgl: Added section explaining tokens,
and new API.
1999-04-09 Michael Meeks <michael@imaginator.com>
* src/sheet.c (sheet_destroy): Move destruction of cell_hash to
......
1999-04-11 Michael Meeks <michael@imaginator.com>
* src/expr.c (eval_funccall): New array / 'area' tokens added,
error strings simplified ( int type_mismatch added )
(value_area_get_width, value_area_get_height): Implemented,
(value_area_get_at_x_y): Implemented.
(value_array_new, value_array_resize): Implemented.
(value_release): Updated.
(value_copy_to, value_array_copy_to): Updated, created.
Added const to a scad of helper 'value_get' style functions.
* src/expr.h: Value: Changed 'array' from GList to a
structure.
Added struct _Value for self reference.
Added const to a scad of helper 'value_get' style functions.
* src/func.c (function_iterate_do_value): Updated Array code.
* src/eval.c (add_value_deps): Updated Array stuff.
(add_value_deps): const added to Value *
* src/dialog-function-wizard.c (function_type_input):
Updated text for new tokens.
* src/fn-sheet.c (gnumeric_selection): Update to new array code.
* src/fn-lookup.c (columns, rows): Updated to clean new API.
(vlookup, hlookup): Large clean.
* src/parser.y (value_dump): Updated Array section.
* docs/C/writing-functions.smgl: Added section explaining tokens,
and new API.
1999-04-09 Michael Meeks <michael@imaginator.com>
* src/sheet.c (sheet_destroy): Move destruction of cell_hash to
......
1999-04-11 Michael Meeks <michael@imaginator.com>
* src/expr.c (eval_funccall): New array / 'area' tokens added,
error strings simplified ( int type_mismatch added )
(value_area_get_width, value_area_get_height): Implemented,
(value_area_get_at_x_y): Implemented.
(value_array_new, value_array_resize): Implemented.
(value_release): Updated.
(value_copy_to, value_array_copy_to): Updated, created.
Added const to a scad of helper 'value_get' style functions.
* src/expr.h: Value: Changed 'array' from GList to a
structure.
Added struct _Value for self reference.
Added const to a scad of helper 'value_get' style functions.
* src/func.c (function_iterate_do_value): Updated Array code.
* src/eval.c (add_value_deps): Updated Array stuff.
(add_value_deps): const added to Value *
* src/dialog-function-wizard.c (function_type_input):
Updated text for new tokens.
* src/fn-sheet.c (gnumeric_selection): Update to new array code.
* src/fn-lookup.c (columns, rows): Updated to clean new API.
(vlookup, hlookup): Large clean.
* src/parser.y (value_dump): Updated Array section.
* docs/C/writing-functions.smgl: Added section explaining tokens,
and new API.
1999-04-09 Michael Meeks <michael@imaginator.com>
* src/sheet.c (sheet_destroy): Move destruction of cell_hash to
......
......@@ -239,6 +239,19 @@ cell it is being invoked) and it is used when invoking the expr_eval
function.
Function Tokens
---------------
There are several function tokens to cover most situations.
f : A floating point (double) value.
s : A string (char*)
b : A boolean
r : A Range eg. A1:A5 - See 'A'
a : An Array eg. {1,2,3;4,5,6} ( a 3x2 array ) - See 'A'
A : Either an Array or a Range: Use the
value_area set of functions to simplify the code.
see expr.h.
? : Any type, the type must be checked from value->type.
| : This designates that the arguments in the token string
following this character are optional.
......@@ -31,7 +31,7 @@ static char *help_vlookup = {
};
static int
lookup_similar (Value *data, Value *templ, Value *next_largest, int approx)
lookup_similar (const Value *data, const Value *templ, const Value *next_largest, int approx)
{
int ans ;
......@@ -93,28 +93,16 @@ lookup_similar (Value *data, Value *templ, Value *next_largest, int approx)
static Value *
gnumeric_vlookup (struct FunctionDefinition *i, Value *argv [], char **error_string)
{
CellRef *a, *b ;
Value *next_largest = NULL ;
const Value *next_largest = NULL ;
int height, lp, approx, col_idx, next_largest_row=0 ;
a = &argv[1]->v.cell_range.cell_a ;
b = &argv[1]->v.cell_range.cell_b ;
g_return_val_if_fail (a->sheet != NULL, NULL) ;
/* a->sheet must be used as inter-sheet references specify the other sheet in 'a' */
/* g_return_val_if_fail (a->sheet == b->sheet, NULL) ; */
g_return_val_if_fail (!a->col_relative, NULL) ;
g_return_val_if_fail (!b->col_relative, NULL) ;
g_return_val_if_fail (!a->row_relative, NULL) ;
g_return_val_if_fail (!b->row_relative, NULL) ;
g_return_val_if_fail (a->col<=b->col, NULL) ;
g_return_val_if_fail (a->row<=b->row, NULL) ;
height = value_area_get_height (argv[1]) ;
col_idx = value_get_as_int (argv[2]) ;
if (col_idx<=0) {
*error_string = _("#NUM!") ;
return NULL ;
}
if (col_idx>b->col-a->col+1) {
if (col_idx>value_area_get_width(argv[1])) {
*error_string = _("#REF!") ;
return NULL ;
}
......@@ -130,32 +118,28 @@ gnumeric_vlookup (struct FunctionDefinition *i, Value *argv [], char **error_str
else
approx = 1 ;
height = b->row - a->row + 1 ;
for (lp=0;lp<height;lp++) {
int compare ;
Cell *cell = sheet_cell_get (a->sheet, a->col, a->row+lp) ;
int compare;
const Value *v = value_area_get_at_x_y(argv[1], 0, lp);
g_return_val_if_fail (cell != NULL, NULL) ;
g_return_val_if_fail (cell->value != NULL, NULL) ;
g_return_val_if_fail (v != NULL, NULL) ;
compare = lookup_similar (cell->value, argv[0], next_largest, approx) ;
compare = lookup_similar (v, argv[0], next_largest, approx) ;
/* printf ("Compare '%s' with '%s' : %d (%d)\n", value_string(cell->value), value_string(argv[0]), compare, approx) ; */
if (compare == 1) {
Cell *cell = sheet_cell_get (a->sheet, a->col+col_idx-1, a->row+lp) ;
g_return_val_if_fail (cell != NULL, NULL) ;
g_return_val_if_fail (cell->value != NULL, NULL) ;
return value_duplicate (cell->value) ;
const Value *v = value_area_get_at_x_y(argv[1],col_idx-1, lp);
g_return_val_if_fail (v != NULL, NULL);
return value_duplicate (v);
}
if (compare < 0) {
next_largest = cell->value ;
next_largest = v ;
next_largest_row = lp ;
}
}
if (approx && next_largest) {
Cell *cell = sheet_cell_get (a->sheet, a->col+col_idx-1, a->row+next_largest_row) ;
g_return_val_if_fail (cell != NULL, NULL) ;
g_return_val_if_fail (cell->value != NULL, NULL) ;
return value_duplicate (cell->value) ;
const Value *v= value_area_get_at_x_y(argv[1],col_idx-1, next_largest_row);
g_return_val_if_fail (v != NULL, NULL) ;
return value_duplicate (v) ;
}
else
*error_string = _("#N/A") ;
......@@ -183,28 +167,16 @@ static char *help_hlookup = {
static Value *
gnumeric_hlookup (struct FunctionDefinition *i, Value *argv [], char **error_string)
{
CellRef *a, *b ;
Value *next_largest = NULL ;
const Value *next_largest = NULL ;
int height, lp, approx, row_idx, next_largest_col=0 ;
a = &argv[1]->v.cell_range.cell_a ;
b = &argv[1]->v.cell_range.cell_b ;
g_return_val_if_fail (a->sheet != NULL, NULL) ;
/* a->sheet must be used as inter-sheet references specify the other sheet in 'a' */
/* g_return_val_if_fail (a->sheet == b->sheet, NULL) ; */
g_return_val_if_fail (!a->col_relative, NULL) ;
g_return_val_if_fail (!b->col_relative, NULL) ;
g_return_val_if_fail (!a->row_relative, NULL) ;
g_return_val_if_fail (!b->row_relative, NULL) ;
g_return_val_if_fail (a->col<=b->col, NULL) ;
g_return_val_if_fail (a->row<=b->row, NULL) ;
row_idx = value_get_as_int (argv[2]) ;
height = value_area_get_width (argv[1]);
if (row_idx<=0) {
*error_string = _("#NUM!") ;
return NULL ;
}
if (row_idx>b->row-a->row+1) {
if (row_idx>value_area_get_height(argv[1])) {
*error_string = _("#REF!") ;
return NULL ;
}
......@@ -220,32 +192,28 @@ gnumeric_hlookup (struct FunctionDefinition *i, Value *argv [], char **error_str
else
approx = 1 ;
height = b->col - a->col + 1 ;
for (lp=0;lp<height;lp++) {
int compare ;
Cell *cell = sheet_cell_get (a->sheet, a->col+lp, a->row) ;
int compare;
const Value *v = value_area_get_at_x_y (argv[1],lp, 0);
g_return_val_if_fail (cell != NULL, NULL) ;
g_return_val_if_fail (cell->value != NULL, NULL) ;
g_return_val_if_fail (v != NULL, NULL) ;
compare = lookup_similar (cell->value, argv[0], next_largest, approx) ;
compare = lookup_similar (v, argv[0], next_largest, approx) ;
/* printf ("Compare '%s' with '%s' : %d (%d)\n", value_string(cell->value), value_string(argv[0]), compare, approx) ; */
if (compare == 1) {
Cell *cell = sheet_cell_get (a->sheet, a->col+lp, a->row+row_idx-1) ;
g_return_val_if_fail (cell != NULL, NULL) ;
g_return_val_if_fail (cell->value != NULL, NULL) ;
return value_duplicate (cell->value) ;
const Value *v = value_area_get_at_x_y (argv[1],lp, row_idx-1) ;
g_return_val_if_fail (v != NULL, NULL) ;
return value_duplicate (v) ;
}
if (compare < 0) {
next_largest = cell->value ;
next_largest = v ;
next_largest_col = lp ;
}
}
if (approx && next_largest) {
Cell *cell = sheet_cell_get (a->sheet, a->col+next_largest_col, a->row+row_idx-1) ;
g_return_val_if_fail (cell != NULL, NULL) ;
g_return_val_if_fail (cell->value != NULL, NULL) ;
return value_duplicate (cell->value) ;
const Value *v = value_area_get_at_x_y (argv[1], next_largest_col, row_idx-1);
g_return_val_if_fail (v != NULL, NULL) ;
return value_duplicate (v) ;
}
else
*error_string = _("#N/A") ;
......@@ -307,16 +275,7 @@ static char *help_columns = {
static Value *
gnumeric_columns (struct FunctionDefinition *i, Value *argv [], char **error_string)
{
switch (argv[0]->type) {
case VALUE_CELLRANGE:
return value_int (argv[0]->v.cell_range.cell_b.col - argv[0]->v.cell_range.cell_a.col + 1) ;
case VALUE_ARRAY:
*error_string = _("Unimplemented\n") ;
return NULL ;
default:
*error_string = _("#VALUE!") ;
return NULL ;
}
return value_int(value_area_get_width (argv[0])) ;
}
static char *help_row = {
......@@ -373,25 +332,16 @@ static char *help_rows = {
static Value *
gnumeric_rows (struct FunctionDefinition *i, Value *argv [], char **error_string)
{
switch (argv[0]->type) {
case VALUE_CELLRANGE:
return value_int (argv[0]->v.cell_range.cell_b.row - argv[0]->v.cell_range.cell_a.row + 1) ;
case VALUE_ARRAY:
*error_string = _("Unimplemented\n") ;
return NULL ;
default:
*error_string = _("#VALUE!") ;
return NULL ;
}
return value_int(value_area_get_height (argv[0])) ;
}
FunctionDefinition lookup_functions [] = {
{ "column", "?", "ref", &help_column, gnumeric_column, NULL },
{ "columns", "?", "ref", &help_column, NULL, gnumeric_columns },
{ "columns", "A", "ref", &help_column, NULL, gnumeric_columns },
{ "hlookup", "?rf|b","val,range,col_idx,approx", &help_hlookup, NULL, gnumeric_hlookup },
{ "row", "?", "ref", &help_row, gnumeric_row, NULL },
{ "rows", "?", "ref", &help_rows, NULL, gnumeric_rows },
{ "rows", "A", "ref", &help_rows, NULL, gnumeric_rows },
{ "vlookup", "?rf|b","val,range,col_idx,approx", &help_vlookup, NULL, gnumeric_vlookup },
{ NULL, NULL }
} ;
......
......@@ -143,7 +143,7 @@ add_cell_range_deps (Cell *cell, CellRef *a, CellRef *b)
* Adds the dependencies for a Value
*/
static void
add_value_deps (Cell *cell, Value *value)
add_value_deps (Cell *cell, const Value *value)
{
GList *l;
......@@ -156,10 +156,14 @@ add_value_deps (Cell *cell, Value *value)
/* Check every element of the array */
case VALUE_ARRAY:
for (l = value->v.array; l; l = l->next)
add_value_deps (cell, l->data);
{
int lpx, lpy ;
for (lpx=0;lpx<value->v.array.x;lpx++)
for (lpy=0;lpy<value->v.array.y;lpy++)
add_value_deps (cell,
&value->v.array.vals[lpx][lpy]);
break;
}
case VALUE_CELLRANGE:
add_cell_range_deps (
cell,
......
......@@ -203,6 +203,12 @@ function_type_input (ARG_DATA *ad)
txt = _("Boolean");
break;
case 'r':
txt = _("Range");
break;
case 'a':
txt = _("Array");
break;
case 'A':
txt = _("Range/Array");
break;
case '?':
......
......@@ -203,6 +203,12 @@ function_type_input (ARG_DATA *ad)
txt = _("Boolean");
break;
case 'r':
txt = _("Range");
break;
case 'a':
txt = _("Array");
break;
case 'A':
txt = _("Range/Array");
break;
case '?':
......
......@@ -203,6 +203,12 @@ function_type_input (ARG_DATA *ad)
txt = _("Boolean");
break;
case 'r':
txt = _("Range");
break;
case 'a':
txt = _("Array");
break;
case 'A':
txt = _("Range/Array");
break;
case '?':
......
......@@ -143,7 +143,7 @@ add_cell_range_deps (Cell *cell, CellRef *a, CellRef *b)
* Adds the dependencies for a Value
*/
static void
add_value_deps (Cell *cell, Value *value)
add_value_deps (Cell *cell, const Value *value)
{
GList *l;
......@@ -156,10 +156,14 @@ add_value_deps (Cell *cell, Value *value)
/* Check every element of the array */
case VALUE_ARRAY:
for (l = value->v.array; l; l = l->next)
add_value_deps (cell, l->data);
{
int lpx, lpy ;
for (lpx=0;lpx<value->v.array.x;lpx++)
for (lpy=0;lpy<value->v.array.y;lpy++)
add_value_deps (cell,
&value->v.array.vals[lpx][lpy]);
break;
}
case VALUE_CELLRANGE:
add_cell_range_deps (
cell,
......
......@@ -174,7 +174,7 @@ expr_tree_unref (ExprTree *tree)
* simplistic value rendering
*/
char *
value_string (Value *value)
value_string (const Value *value)
{
switch (value->type){
case VALUE_STRING:
......@@ -215,13 +215,12 @@ value_release (Value *value)
break;
case VALUE_ARRAY: {
GList *l;
for (l = value->v.array; l; l = l->next)
value_release (l->data);
g_list_free (l);
guint lp ;
for (lp=0;lp<value->v.array.x;lp++)
g_free (value->v.array.vals[lp]) ;
g_free (value->v.array.vals) ;
}
case VALUE_CELLRANGE:
break;
......@@ -233,7 +232,7 @@ value_release (Value *value)
* Copies a Value.
*/
void
value_copy_to (Value *dest, Value *source)
value_copy_to (Value *dest, const Value *source)
{
g_return_if_fail (dest != NULL);
g_return_if_fail (source != NULL);
......@@ -255,16 +254,7 @@ value_copy_to (Value *dest, Value *source)
break;
case VALUE_ARRAY: {
GList *l, *new = NULL;
for (l = source->v.array; l; l = l->next){
Value *copy;
copy = value_duplicate (l->data);
new = g_list_append (new, copy);
}
dest->v.array = new;
value_array_copy_to (dest, source) ;
break;
}
case VALUE_CELLRANGE:
......@@ -277,7 +267,7 @@ value_copy_to (Value *dest, Value *source)
* Makes a copy of a Value
*/
Value *
value_duplicate (Value *value)
value_duplicate (const Value *value)
{
Value *new_value;
......@@ -344,7 +334,7 @@ value_cast_to_float (Value *v)
}
int
value_get_bool (Value *v, int *err)
value_get_bool (const Value *v, int *err)
{
*err = 0;
......@@ -371,7 +361,7 @@ value_get_bool (Value *v, int *err)
}
float_t
value_get_as_double (Value *v)
value_get_as_double (const Value *v)
{
if (v->type == VALUE_STRING){
return atof (v->v.str->str);
......@@ -392,7 +382,7 @@ value_get_as_double (Value *v)
}
int
value_get_as_int (Value *v)
value_get_as_int (const Value *v)
{
if (v->type == VALUE_STRING){
return atoi (v->v.str->str);
......@@ -412,6 +402,139 @@ value_get_as_int (Value *v)
return (int) v->v.v_float;
}
Value *
value_array_new (guint width, guint height)
{
int lpx, lpy;
Value *v = g_new (Value, 1);
v->type = VALUE_ARRAY;
v->v.array.x = width;
v->v.array.y = height;
v->v.array.vals = g_new (Value *, width);
for (lpx=0;lpx<width;lpx++) {
v->v.array.vals[lpx] = g_new (Value,height);
for (lpy=0;lpy<height;lpy++) {
v->v.array.vals[lpx][lpy].type = VALUE_INTEGER;
v->v.array.vals[lpx][lpy].v.v_int = 0;
}
}
return v;
}
void
value_array_resize (Value *v, guint width, guint height)
{
int lpx, lpy, xcpy, ycpy;
Value *newval;
g_return_if_fail (v);
g_return_if_fail (v->type == VALUE_ARRAY);
newval = value_array_new (width, height);
if (width>v->v.array.x)
xcpy = v->v.array.x;
else
ycpy = width;
if (height>v->v.array.y)
ycpy = v->v.array.y;
else
ycpy = height;
for (lpx=0;lpx<xcpy;lpx++) {
memcpy (newval->v.array.vals[lpx],
v->v.array.vals[lpx],
sizeof(Value)*ycpy);
}
v->v.array.vals = newval->v.array.vals;
v->v.array.x = width;
v->v.array.y = height;
value_release (newval) ;
}
void
value_array_copy_to (Value *v, const Value *src)
{
int lpx, lpy;
g_return_if_fail (src->type == VALUE_ARRAY);
v->type = VALUE_ARRAY;
v->v.array.x = src->v.array.x;
v->v.array.y = src->v.array.y;
v->v.array.vals = g_new (Value *, v->v.array.x);
for (lpx=0;lpx<v->v.array.x;lpx++) {
v->v.array.vals[lpx] = g_new (Value,v->v.array.y);
memcpy (v->v.array.vals[lpx], src->v.array.vals[lpx],
sizeof(Value)*v->v.array.y) ;
}
}
guint
value_area_get_width (Value *v)
{
g_return_val_if_fail (v, 0);
g_return_val_if_fail (v->type == VALUE_ARRAY ||
v->type == VALUE_CELLRANGE, 1);
if (v->type == VALUE_ARRAY)
return v->v.array.x;
else
return v->v.cell_range.cell_b.col -
v->v.cell_range.cell_a.col + 1;
}
guint
value_area_get_height (Value *v)
{
g_return_val_if_fail (v, 0);
g_return_val_if_fail (v->type == VALUE_ARRAY ||
v->type == VALUE_CELLRANGE, 1);
if (v->type == VALUE_ARRAY)
return v->v.array.y;
else
return v->v.cell_range.cell_b.row -
v->v.cell_range.cell_a.row + 1;
}
const Value *
value_area_get_at_x_y (Value *v, guint x, guint y)
{
g_return_val_if_fail (v, 0);
g_return_val_if_fail (v->type == VALUE_ARRAY ||
v->type == VALUE_CELLRANGE,
value_int(0));
if (v->type == VALUE_ARRAY) {
g_return_val_if_fail (v->v.array.x<x ||
v->v.array.y<y,
value_int(0));
return &v->v.array.vals[x][y];
} else {
CellRef *a, *b;
Cell *cell;
a = &v->v.cell_range.cell_a;
b = &v->v.cell_range.cell_b;
g_return_val_if_fail (!a->col_relative,
value_int(0)) ;
g_return_val_if_fail (!b->col_relative,
value_int(0)) ;
g_return_val_if_fail (!a->row_relative,
value_int(0)) ;
g_return_val_if_fail (!b->row_relative,
value_int(0)) ;
g_return_val_if_fail (a->col<=b->col,
value_int(0)) ;
g_return_val_if_fail (a->row<=b->row,
value_int(0)) ;
cell = sheet_cell_get (a->sheet, a->col+x, a->row+y);
if (cell && cell->value)
return cell->value;
else
return value_int(0) ;
}
return value_int(0) ;
}
static void
cell_ref_make_absolute (CellRef *cell_ref, int eval_col, int eval_row)
{
......@@ -517,6 +640,7 @@ eval_funcall (Sheet *sheet, ExprTree *tree, int eval_col, int eval_row, char **e
for (arg = 0; l; l = l->next, arg++, arg_type++) {
ExprTree *t = (ExprTree *) l->data;
int type_mismatch = 0;
v = eval_expr (sheet, t, eval_col, eval_row, error_string);
if (v == NULL)
......@@ -527,31 +651,36 @@ eval_funcall (Sheet *sheet, ExprTree *tree, int eval_col, int eval_row, char **e
switch (*arg_type){
case 'f':
if (v->type == VALUE_INTEGER ||
v->type == VALUE_FLOAT)
break;
free_values (values, arg);
*error_string = _("Type mismatch");
return NULL;
if (v->type != VALUE_INTEGER &&
v->type != VALUE_FLOAT)
type_mismatch = 1;
break;
case 's':
if (v->type != VALUE_STRING){
free_values (values, arg);