Commit 86c717b2 authored by Arturo Espinosa's avatar Arturo Espinosa

We got functions today.


We got functions today.

Miguel.
parent 5908feed
1998-08-04 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/func.c: More functions added.
* src/symbol.c (g_strcase_equal): Symbol hash table does is
case-insensitive.
* src/expr.c (eval_funcall): Added function evaluation.
1998-08-03 Miguel de Icaza <miguel@nuclecu.unam.mx> 1998-08-03 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/eval.c: New file. Move the evaluation routines here. * src/eval.c: New file. Move the evaluation routines here.
......
1998-08-04 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/func.c: More functions added.
* src/symbol.c (g_strcase_equal): Symbol hash table does is
case-insensitive.
* src/expr.c (eval_funcall): Added function evaluation.
1998-08-03 Miguel de Icaza <miguel@nuclecu.unam.mx> 1998-08-03 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/eval.c: New file. Move the evaluation routines here. * src/eval.c: New file. Move the evaluation routines here.
......
1998-08-04 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/func.c: More functions added.
* src/symbol.c (g_strcase_equal): Symbol hash table does is
case-insensitive.
* src/expr.c (eval_funcall): Added function evaluation.
1998-08-03 Miguel de Icaza <miguel@nuclecu.unam.mx> 1998-08-03 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/eval.c: New file. Move the evaluation routines here. * src/eval.c: New file. Move the evaluation routines here.
......
1998-08-04 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/func.c: More functions added.
* src/symbol.c (g_strcase_equal): Symbol hash table does is
case-insensitive.
* src/expr.c (eval_funcall): Added function evaluation.
1998-08-03 Miguel de Icaza <miguel@nuclecu.unam.mx> 1998-08-03 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/eval.c: New file. Move the evaluation routines here. * src/eval.c: New file. Move the evaluation routines here.
......
...@@ -140,6 +140,24 @@ value_cast_to_float (Value *v) ...@@ -140,6 +140,24 @@ value_cast_to_float (Value *v)
return newv; return newv;
} }
float_t
value_get_as_double (Value *v)
{
if (v->type == VALUE_STRING){
return atof (v->v.str->str);
}
if (v->type == VALUE_CELLRANGE){
g_warning ("Getting range as a double: what to do?");
return 0.0;
}
if (v->type == VALUE_INTEGER)
return (float_t) v->v.v_int;
return v->v.v_float;
}
static Value * static Value *
eval_cell_value (Sheet *sheet, Value *value) eval_cell_value (Sheet *sheet, Value *value)
{ {
...@@ -171,6 +189,60 @@ eval_cell_value (Sheet *sheet, Value *value) ...@@ -171,6 +189,60 @@ eval_cell_value (Sheet *sheet, Value *value)
return res; return res;
} }
static Value *
eval_funcall (Sheet *sheet, ExprTree *tree, int eval_col, int eval_row, char **error_string)
{
FunctionDefinition *fd;
GList *l;
int argc, arg, i;
Value *v;
fd = (FunctionDefinition *) tree->u.function.symbol->data;
l = tree->u.function.arg_list;
argc = g_list_length (l);
if (fd->expr_fn)
{
/* Functions that deal with ExprNodes */
v = fd->expr_fn (sheet, l, eval_col, eval_row, error_string);
}
else
{
/* Functions that take pre-computed Values */
Value **values;
int fn_argc;
char *arg_type = fd->args;
fn_argc = strlen (fd->args);
if (fn_argc != argc){
*error_string = _("Invalid number of arguments");
return NULL;
}
values = g_new (Value *, argc);
for (arg = 0; l; l = l->next, arg++, arg_type++){
ExprTree *t = (ExprTree *) l->data;
v = eval_expr (sheet, t, eval_col, eval_row, error_string);
if (v == NULL)
goto free_list;
values [arg] = v;
}
v = fd->fn (arg+1, values, error_string);
free_list:
for (i = 0; i < arg; i++)
value_release (values [i]);
g_free (values);
return v;
}
return v;
}
Value * Value *
eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **error_string) eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **error_string)
{ {
...@@ -291,9 +363,7 @@ eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **erro ...@@ -291,9 +363,7 @@ eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **erro
return NULL; return NULL;
case OP_FUNCALL: case OP_FUNCALL:
g_warning ("Function call not implemented yet\n"); return eval_funcall (sheet, tree, eval_col, eval_row, error_string);
*error_string = _("OOPS");
return NULL;
case OP_CONSTANT: case OP_CONSTANT:
return eval_cell_value (sheet, tree->u.constant); return eval_cell_value (sheet, tree->u.constant);
......
...@@ -90,6 +90,35 @@ typedef enum { ...@@ -90,6 +90,35 @@ typedef enum {
PARSE_ERR_SYNTAX PARSE_ERR_SYNTAX
} ParseErr; } ParseErr;
/*
* Functions come in two fashions: Those that only deal with
* very specific data types and a constant number of arguments,
* and those who dont.
*
* The former kind of functions receives a precomputed array of
* Value pointers.
*
* The latter sort of functions receives the plain ExprNodes and
* it is up to that routine to do the value computations and range
* processing.
*/
typedef struct {
/* The function name */
char *name;
/* The types accepted:
* f for float
* s for string
* b for boolean
*/
char *args;
ValueType ret_type;
Value *(*expr_fn)(void *sheet, GList *expr_node_list, int eval_col, int eval_row, char **error_string);
Value *(*fn)(int argc, Value *argv [], char **error_string);
} FunctionDefinition;
/* For communication with yyparse */ /* For communication with yyparse */
extern char *parser_expr; extern char *parser_expr;
extern ParseErr parser_error; extern ParseErr parser_error;
...@@ -109,7 +138,9 @@ Value *value_cast_to_float (Value *v); ...@@ -109,7 +138,9 @@ Value *value_cast_to_float (Value *v);
void value_dump (Value *value); void value_dump (Value *value);
char *value_string (Value *value); char *value_string (Value *value);
float_t value_get_as_double (Value *v);
int yyparse (void); int yyparse (void);
void functions_init (void);
#endif #endif
...@@ -8,21 +8,210 @@ ...@@ -8,21 +8,210 @@
*/ */
#include <config.h> #include <config.h>
#include <gnome.h> #include <gnome.h>
#include "math.h"
#include "gnumeric.h" #include "gnumeric.h"
#include "gnumeric-sheet.h" #include "gnumeric-sheet.h"
#include "utils.h" #include "utils.h"
static void static Value *
gnumeric_sin (void) gnumeric_abs (int argc, Value *argv [], char **error_string)
{ {
printf ("Sinning\n"); Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = fabs (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_acos (int argc, Value *argv [], char **error_string)
{
Value *v;
float_t t;
t = value_get_as_double (argv [0]);
if ((t < -1.0) || (t > 1.0)){
*error_string = _("acos - domain error");
return NULL;
}
v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = acos (t);
return v;
}
static Value *
gnumeric_asin (int argc, Value *argv [], char **error_string)
{
Value *v;
float_t t;
t = value_get_as_double (argv [0]);
if ((t < -1.0) || (t > 1.0)){
*error_string = _("asin - domain error");
return NULL;
}
v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = asin (t);
return v;
}
static Value *
gnumeric_atan (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = atan (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_atan2 (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = atan2 (value_get_as_double (argv [0]),
value_get_as_double (argv [1]));
return v;
}
static Value *
gnumeric_ceil (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = ceil (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_cos (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = cos (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_exp (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = exp (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_floor (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = floor (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_int (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
float_t t;
t = value_get_as_double (argv [0]);
v->type = VALUE_FLOAT;
v->v.v_float = t > 0.0 ? floor (t) : ceil (t);
return v;
}
static Value *
gnumeric_log (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = log (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_log10 (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = log10 (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_sin (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = sin (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_tan (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = tan (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_pi (int argc, Value *argv [], char *error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = M_PI;
return v;
} }
static struct { FunctionDefinition internal_functions [] = {
char *name; { "abs", "f", VALUE_FLOAT, NULL, gnumeric_abs },
void (*fn)(void); { "acos", "f", VALUE_FLOAT, NULL, gnumeric_acos },
} internal_functions [] = { { "asin", "f", VALUE_FLOAT, NULL, gnumeric_asin },
{ "sin", gnumeric_sin }, { "atan", "f", VALUE_FLOAT, NULL, gnumeric_atan },
{ "atan2", "ff", VALUE_FLOAT, NULL, gnumeric_atan2 },
{ "cos", "f", VALUE_FLOAT, NULL, gnumeric_cos },
{ "ceil", "f", VALUE_FLOAT, NULL, gnumeric_ceil },
{ "exp", "f", VALUE_FLOAT, NULL, gnumeric_exp },
{ "floor", "f", VALUE_FLOAT, NULL, gnumeric_floor },
{ "int", "f", VALUE_FLOAT, NULL, gnumeric_int },
{ "log", "f", VALUE_FLOAT, NULL, gnumeric_log },
{ "log10", "f", VALUE_FLOAT, NULL, gnumeric_log10 },
{ "sin", "f", VALUE_FLOAT, NULL, gnumeric_sin },
{ "tan", "f", VALUE_FLOAT, NULL, gnumeric_tan },
{ "pi", "", VALUE_FLOAT, NULL, gnumeric_pi },
{ NULL, NULL }, { NULL, NULL },
}; };
...@@ -32,7 +221,8 @@ functions_init (void) ...@@ -32,7 +221,8 @@ functions_init (void)
int i; int i;
for (i = 0; internal_functions [i].name; i++){ for (i = 0; internal_functions [i].name; i++){
symbol_install (internal_functions [i].name, SYMBOL_FUNCTION, symbol_install (internal_functions [i].name,
internal_functions [i].fn); SYMBOL_FUNCTION,
&internal_functions [i]);
} }
} }
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <gnome.h> #include <gnome.h>
#include "gnumeric.h" #include "gnumeric.h"
#include "gnumeric-sheet.h"
#include "item-bar.h" #include "item-bar.h"
#include "item-debug.h" #include "item-debug.h"
...@@ -265,27 +266,38 @@ set_cursor (ItemBar *item_bar, int pos) ...@@ -265,27 +266,38 @@ set_cursor (ItemBar *item_bar, int pos)
} }
static void static void
item_bar_start_resize (ItemBar *item_bar, int pos) item_bar_start_resize (ItemBar *item_bar, int pos, int pixels)
{ {
GnomeCanvas *canvas = GNOME_CANVAS (item_bar->sheet->sheet_view); GnomeCanvas *canvas = GNOME_CANVAS (item_bar->sheet->sheet_view);
GnomeCanvasGroup *group = GNOME_CANVAS_GROUP (canvas->root); GnomeCanvasGroup *group = GNOME_CANVAS_GROUP (canvas->root);
GnomeCanvasItem *item; GnomeCanvasItem *item;
GnomeCanvasPoints *points; GnomeCanvasPoints *points;
GnumericSheet *gsheet;
double x1, x2, y1, y2; double x1, x2, y1, y2;
int division_pos;
gsheet = GNUMERIC_SHEET (item_bar->sheet->sheet_view);
if (item_bar->orientation == GTK_ORIENTATION_VERTICAL){ if (item_bar->orientation == GTK_ORIENTATION_VERTICAL){
division_pos = sheet_col_get_distance (item_bar->sheet,
gsheet->top_row,
pos);
x1 = 0.0; x1 = 0.0;
x2 = INT_MAX; x2 = canvas->width;
y1 = GNOME_CANVAS_ITEM (item_bar)->y1 + pos; y1 = division_pos;
y2 = GNOME_CANVAS_ITEM (item_bar)->y1 + pos; y2 = division_pos;
} else {
division_pos = sheet_row_get_distance (item_bar->sheet,
gsheet->top_col,
pos);
x1 = division_pos;
x2 = division_pos;
y1 = 0.0;
y2 = canvas->height;
} }
x1 = 0.0; item_bar->resize_guide_offset = division_pos - pixels;
x2 = 1000.0;
y1 = 0.0;
y2 = 1000.0;
/* Add a guideline to the sheet canvas */ /* Add a guideline to the sheet canvas */
points = gnome_canvas_points_new (2); points = gnome_canvas_points_new (2);
points->coords[0] = x1; points->coords[0] = x1;
...@@ -296,7 +308,7 @@ item_bar_start_resize (ItemBar *item_bar, int pos) ...@@ -296,7 +308,7 @@ item_bar_start_resize (ItemBar *item_bar, int pos)
gnome_canvas_line_get_type (), gnome_canvas_line_get_type (),
"points", points, "points", points,
"fill_color", "black", "fill_color", "black",
"width_pixels", 4, "width_pixels", 1,
NULL); NULL);
gnome_canvas_points_free (points); gnome_canvas_points_free (points);
...@@ -349,22 +361,22 @@ item_bar_event (GnomeCanvasItem *item, GdkEvent *e) ...@@ -349,22 +361,22 @@ item_bar_event (GnomeCanvasItem *item, GdkEvent *e)
case GDK_MOTION_NOTIFY: case GDK_MOTION_NOTIFY:
convert (canvas, e->motion.x, e->motion.y, &x, &y); convert (canvas, e->motion.x, e->motion.y, &x, &y);
if (item_bar->orientation == GTK_ORIENTATION_VERTICAL) if (item_bar->orientation == GTK_ORIENTATION_VERTICAL){
pos = y; pos = y;
else } else {
pos = x; pos = x;
}
/* Do column resizing or incremental marking */ /* Do column resizing or incremental marking */
if (resizing){ if (resizing){
int npos; int npos;
npos = pos - item_bar->resize_start_pos; npos = pos - item_bar->resize_start_pos;
if (npos > 0){ if (npos <= 0)
item_bar->resize_width = npos; break;
gnome_canvas_request_redraw ( item_bar->resize_width = npos;
GNOME_CANVAS_ITEM(item_bar)->canvas, gnome_canvas_request_redraw (GNOME_CANVAS_ITEM(item_bar)->canvas, 0, 0, INT_MAX, INT_MAX);
0, 0, INT_MAX, INT_MAX); gnome_canvas_item_move (GNOME_CANVAS_ITEM (item_bar->resize_guide), 0, pos);
}
} else if (ITEM_BAR_IS_SELECTING (item_bar)){ } else if (ITEM_BAR_IS_SELECTING (item_bar)){
element = get_col_from_pos (item_bar, pos); element = get_col_from_pos (item_bar, pos);
...@@ -390,9 +402,10 @@ item_bar_event (GnomeCanvasItem *item, GdkEvent *e) ...@@ -390,9 +402,10 @@ item_bar_event (GnomeCanvasItem *item, GdkEvent *e)
item_bar->resize_start_pos = start - cri->pixels; item_bar->resize_start_pos = start - cri->pixels;
item_bar->resize_width = cri->pixels; item_bar->resize_width = cri->pixels;
item_bar_start_resize (item_bar, pos); item_bar_start_resize (item_bar, element, pos);
gnome_canvas_item_grab (item, gnome_canvas_item_grab (item,
GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, GDK_POINTER_MOTION_MASK |
GDK_BUTTON_RELEASE_MASK,
item_bar->change_cursor, item_bar->change_cursor,
e->button.time); e->button.time);
} else { } else {
......
...@@ -20,7 +20,8 @@ typedef struct { ...@@ -20,7 +20,8 @@ typedef struct {
int resize_width; int resize_width;
int resize_start_pos; int resize_start_pos;
GtkObject *resize_guide; GtkObject *resize_guide;
int resize_guide_offset;
int dragging : 1; int dragging : 1;
int start_selection; int start_selection;
} ItemBar; } ItemBar;
......
...@@ -129,16 +129,7 @@ exp: NUMBER { $$ = $1 } ...@@ -129,16 +129,7 @@ exp: NUMBER { $$ = $1 }
| CELLREF ':' CELLREF {} | CELLREF ':' CELLREF {}
| FUNCALL '(' arg_list ')' { | FUNCALL '(' arg_list ')' {
GList *l; $$ = $1;
int i;
for (i = 0, l = $3; l; l = l->next){
printf ("Arg %d\n", i++);
dump_tree (l->data);
}
$$ = p_new (ExprTree);
$$->oper = OP_FUNCALL;
$$->u.function.symbol = $1->u.function.symbol;
$$->u.function.arg_list = $3; $$->u.function.arg_list = $3;
} }
; ;
...@@ -151,7 +142,8 @@ arg_list: exp { ...@@ -151,7 +142,8 @@ arg_list: exp {
forget_glist ($3); forget_glist ($3);
$$ = g_list_prepend ($3, $1); $$ = g_list_prepend ($3, $1);
alloc_glist ($$); alloc_glist ($$);
} }
| { $$ = NULL; }