genius r647 - in trunk: . help/C src
- From: jirka svn gnome org
- To: svn-commits-list gnome org
- Subject: genius r647 - in trunk: . help/C src
- Date: Mon, 25 Feb 2008 00:35:47 +0000 (GMT)
Author: jirka
Date: Mon Feb 25 00:35:46 2008
New Revision: 647
URL: http://svn.gnome.org/viewvc/genius?rev=647&view=rev
Log:
Sun Feb 24 18:35:45 2008 Jiri (George) Lebl <jirka 5z com>
* src/calc.c: print extra dict of a function by printing a list
of variable assignments before the function body.
* src/dict.c: a little cleanup and fix the problem with subst list
updating and d_replacefunc which happened when a local variable
which was previously set to something else was set to a function.
* src/geniustests.txt: add more tests on returning functions
and the subst list handling
* help/C/genius.xml: add section on returning functions from
functions
Modified:
trunk/ChangeLog
trunk/NEWS
trunk/TODO
trunk/help/C/genius.txt
trunk/help/C/genius.xml
trunk/src/calc.c
trunk/src/dict.c
trunk/src/geniustests.txt
Modified: trunk/NEWS
==============================================================================
--- trunk/NEWS (original)
+++ trunk/NEWS Mon Feb 25 00:35:46 2008
@@ -6,7 +6,9 @@
* QuadraticFormula built in and more numerically stable
* CHANGE: It's Fibonacci in correct spelling, short name is still fib
* Calling internal functions is now slightly faster
+* Fix crash related to returning custom functions from functions
* Fix some memory leaks
+* Documentation updates
* Translations (FIXME)
Changes to 1.0.2
Modified: trunk/TODO
==============================================================================
--- trunk/TODO (original)
+++ trunk/TODO Mon Feb 25 00:35:46 2008
@@ -5,15 +5,6 @@
with context > 0 on the toplevel context. It's strange. And I can't
repro it now
-* crash:
- function f(x) = (k=1; ff=`()=(k+1) ; k=(`()=0) ; ff); ll=f(5)
-
-* behaviour?:
- function f(x) = (k=1; ff=`()=(k+1) ; k=null ; ff)
- the returned function should return 2 not "((null)+1)" shouldn't it?
- That is, replacement (putting into extra_dict)
- should happen on function definition, not on context pop.
-
* Implement max_nodes in the command line version
* Implement MaxNodes parameter
Modified: trunk/help/C/genius.txt
==============================================================================
--- trunk/help/C/genius.txt (original)
+++ trunk/help/C/genius.txt Mon Feb 25 00:35:46 2008
@@ -12,7 +12,7 @@
<kaiw itee uq edu au>
- Copyright (c) 1997-2007 Jiri (George) Lebl
+ Copyright (c) 1997-2008 Jiri (George) Lebl
Copyright (c) 2004 Kai Willadsen
@@ -167,9 +167,11 @@
7.2. Toplevel Syntax
- 7.3. GEL Startup Procedure
+ 7.3. Global Variables and Scope of Variables
- 7.4. Loading Programs
+ 7.4. GEL Startup Procedure
+
+ 7.5. Loading Programs
8. Matrices in GEL
@@ -1564,7 +1566,52 @@
----------------------------------------------------------------------
-7.3. GEL Startup Procedure
+7.3. Global Variables and Scope of Variables
+
+ It is possible to return functions as value. This way you can build
+ functions which construct special purpose functions according to some
+ parameters. The tricky bit is what variables does the function see. The
+ way this works in GEL is that when a function returns another function,
+ all identifiers referenced in the function body are prepended a private
+ dictionary of the returned function. So the function will see all
+ variables that were in scope when it was defined. For example we define a
+ function which returns a function which adds 5 to its argument.
+
+ function f() = (
+ k = 5;
+ `(x) = (x+k)
+ )
+
+ Notice that the function adds k to x. You could use this as follows.
+
+ g = f();
+ g(5)
+
+ And g(5) should return 10.
+
+ One thing to note is that the value of k that is used is the one that's in
+ effect when the f returns. So for example
+
+ function f() = (
+ k = 5;
+ r = `(x) = (x+k);
+ k = 10;
+ r
+ )
+
+ will return a function that adds 10 to its argument rather than 5. This is
+ because the extra dictionary is created only when the context in which the
+ function was defined ends, which is when the function f returns. This is
+ consistent with how you would expect the function r to work inside the
+ function f according to the rules of scope of variables in GEL. Only those
+ variables are added to the extra dictionary that are in the context that
+ just ended and no longer exists. Variables used in the function that are
+ in still valid contexts will work as usual, using the current value of the
+ variable.
+
+ ----------------------------------------------------------------------
+
+7.4. GEL Startup Procedure
First the program looks for the installed library file (the compiled
version lib.cgel) in the installed directory, then it looks into the
@@ -1576,7 +1623,7 @@
----------------------------------------------------------------------
-7.4. Loading Programs
+7.5. Loading Programs
Sometimes you have a larger program that you wrote into a file and want to
read in that file. In these situations, you have two options. You can keep
@@ -1921,6 +1968,14 @@
Check if argument is a boolean (and not a number).
+ IsDefined
+
+ IsDefined (id)
+
+ Check if an id is defined. You should pass a string or and
+ identifier. If you pass a matrix, each entry will be evaluated
+ separately and the matrix should contain strings or identifiers.
+
IsFunction
IsFunction (arg)
@@ -2079,6 +2134,14 @@
The true boolean value.
+ undefine
+
+ undefine (id)
+
+ Undefine a variable. This includes locals and globals, every value
+ on all context levels is wiped. This function should really not be
+ used on local variables.
+
unprotect
unprotect (id)
Modified: trunk/help/C/genius.xml
==============================================================================
--- trunk/help/C/genius.xml (original)
+++ trunk/help/C/genius.xml Mon Feb 25 00:35:46 2008
@@ -1990,6 +1990,55 @@
</para>
</sect1>
+ <sect1 id="genius-gel-returning-functions">
+ <title>Global Variables and Scope of Variables</title>
+ <para>
+ It is possible to return functions as value. This way you can
+ build functions which construct special purpose functions according
+ to some parameters. The tricky bit is what variables does the
+ function see. The way this works in GEL is that when a function
+ returns another function, all identifiers referenced in the
+ function body are prepended a private dictionary of the returned
+ function. So the function will see all variables that were in scope
+ when it was defined. For example we define a function which
+ returns a function which adds 5 to its argument.
+<programlisting>function f() = (
+ k = 5;
+ `(x) = (x+k)
+)
+</programlisting>
+ Notice that the function adds <varname>k</varname> to
+ <varname>x</varname>. You could use this as follows.
+<programlisting>g = f();
+g(5)
+</programlisting>
+ And <userinput>g(5)</userinput> should return 10.
+ </para>
+ <para>
+ One thing to note is that the value of <varname>k</varname>
+ that is used is the one that's in effect when the
+ <function>f</function> returns. So for example
+<programlisting>function f() = (
+ k = 5;
+ r = `(x) = (x+k);
+ k = 10;
+ r
+)
+</programlisting>
+ will return a function that adds 10 to its argument rather than 5.
+ This is because the extra dictionary is created only when the context
+ in which the function was defined ends, which is when the function
+ <function>f</function> returns. This is consistent with how you
+ would expect the function <function>r</function> to work inside
+ the function <function>f</function> according to the rules of
+ scope of variables in GEL. Only those variables are added to the
+ extra dictionary that are in the context that just ended and
+ no longer exists. Variables
+ used in the function that are in still valid contexts will work
+ as usual, using the current value of the variable.
+ </para>
+ </sect1>
+
<sect1 id="genius-gel-startup-procedure">
<title>GEL Startup Procedure</title>
<para>
Modified: trunk/src/calc.c
==============================================================================
--- trunk/src/calc.c (original)
+++ trunk/src/calc.c Mon Feb 25 00:35:46 2008
@@ -1252,6 +1252,64 @@
return FALSE;
}
+static void
+append_func (GelOutput *gelo, GelEFunc *f)
+{
+ GSList *li;
+
+ if G_UNLIKELY (f == NULL) {
+ gel_errorout (_("NULL function!"));
+ gel_output_string(gelo,"(?)");
+ return;
+ }
+ if(f->type==GEL_BUILTIN_FUNC) {
+ gel_output_string(gelo,"(<builtin function>)");
+ return;
+ }
+
+ gel_output_string(gelo,"(`(");
+
+ for(li=f->named_args; li!=NULL; li=g_slist_next(li)) {
+ GelToken *id = li->data;
+ if (li != f->named_args)
+ gel_output_string (gelo, ",");
+ gel_output_string(gelo,id->token);
+ }
+
+ if (f->vararg)
+ gel_output_string (gelo, "...");
+
+ if G_LIKELY (f->type==GEL_USER_FUNC) {
+ gel_output_string(gelo,")=");
+ D_ENSURE_USER_BODY (f);
+ if (f->extra_dict != NULL) {
+ GSList *li;
+ gel_output_string(gelo,"(");
+ for (li = f->extra_dict; li != NULL; li = li->next) {
+ GelEFunc *ff = li->data;
+ gel_output_string (gelo, ff->id->token);
+ gel_output_string (gelo, "=");
+ if (ff->type == GEL_VARIABLE_FUNC) {
+ gel_print_etree (gelo, ff->data.user, FALSE);
+ } else {
+ append_func (gelo, ff);
+ }
+ gel_output_string (gelo, ";");
+ }
+ }
+ gel_print_etree (gelo, f->data.user, FALSE);
+ if (f->extra_dict != NULL) {
+ gel_output_string(gelo,")");
+ }
+ gel_output_string(gelo,")");
+ } else {
+ /*variable and reference functions should
+ never be in the etree*/
+ gel_errorout (_("Unexpected function type!"));
+ gel_output_string(gelo,")(?))");
+ }
+}
+
/*make a string representation of an expression*/
void
gel_print_etree (GelOutput *gelo,
@@ -1340,46 +1398,8 @@
gel_output_string(gelo,"\"");
break;
case FUNCTION_NODE:
- {
- GSList *li;
- GelEFunc *f;
-
- f = n->func.func;
- if G_UNLIKELY (f == NULL) {
- gel_errorout (_("NULL function!"));
- gel_output_string(gelo,"(?)");
- break;
- }
- if(f->type==GEL_BUILTIN_FUNC) {
- gel_output_string(gelo,"(<builtin function>)");
- break;
- }
-
- gel_output_string(gelo,"(`(");
-
- for(li=f->named_args; li!=NULL; li=g_slist_next(li)) {
- GelToken *id = li->data;
- if(li!=f->named_args)
- gel_output_string(gelo,",");
- gel_output_string(gelo,id->token);
- }
-
- if (f->vararg)
- gel_output_string (gelo, "...");
-
- if G_LIKELY (f->type==GEL_USER_FUNC) {
- gel_output_string(gelo,")=");
- D_ENSURE_USER_BODY (f);
- gel_print_etree (gelo, f->data.user, FALSE);
- gel_output_string(gelo,")");
- } else {
- /*variable and reference functions should
- never be in the etree*/
- gel_errorout (_("Unexpected function type!"));
- gel_output_string(gelo,")(?))");
- }
- break;
- }
+ append_func (gelo, n->func.func);
+ break;
case COMPARISON_NODE:
appendcomp(gelo,n);
break;
Modified: trunk/src/dict.c
==============================================================================
--- trunk/src/dict.c (original)
+++ trunk/src/dict.c Mon Feb 25 00:35:46 2008
@@ -499,11 +499,7 @@
{
GSList *li;
for (li = context.stack; li != NULL; li = li->next) {
- GSList *fl = g_slist_find (li->data, func);
- if (fl != NULL) {
- li->data = g_slist_delete_link (li->data, fl);
- return;
- }
+ li->data = g_slist_remove (li->data, func);
}
}
@@ -556,7 +552,7 @@
}
static void
-whack_from_lists (GelEFunc *func)
+whack_from_subst_lists (GelEFunc *func)
{
GSList *li;
for (li = context.subststack; li != NULL; li = li->next) {
@@ -576,7 +572,7 @@
/* On a lower stackframe? */
/* weird but true. So whack it and put it here,
* it will get to the lower one eventually */
- whack_from_lists (func);
+ whack_from_subst_lists (func);
}
context.subststack->data =
g_slist_prepend (context.subststack->data, func);
@@ -594,7 +590,7 @@
*/
if (n->on_subst_list) {
- whack_from_lists (n);
+ whack_from_subst_lists (n);
n->on_subst_list = 0;
}
@@ -628,14 +624,22 @@
d_replacefunc(GelEFunc *old,GelEFunc *_new)
{
GSList *li;
-
- /* assert some things we don't deal with. Should we? */
- g_assert ( ! _new->on_subst_list);
- g_assert ( ! old->on_subst_list);
+ gboolean put_on_subst = FALSE;
g_return_if_fail(old && _new);
g_return_if_fail(old->id == _new->id);
+ if (old->on_subst_list) {
+ whack_from_subst_lists (old);
+ old->on_subst_list = 0;
+ }
+
+ if (_new->on_subst_list) {
+ whack_from_subst_lists (_new);
+ _new->on_subst_list = 0;
+ put_on_subst = TRUE;
+ }
+
if(old->type == GEL_USER_FUNC ||
old->type == GEL_VARIABLE_FUNC)
gel_freetree(old->data.user);
@@ -650,6 +654,11 @@
memcpy(old,_new,sizeof(GelEFunc));
+ /* FIXME: this is inefficient */
+ if (put_on_subst) {
+ d_put_on_subst_list (old);
+ }
+
#ifndef MEM_DEBUG_FRIENDLY
/*prepend to free list*/
_new->data.next = free_funcs;
Modified: trunk/src/geniustests.txt
==============================================================================
--- trunk/src/geniustests.txt (original)
+++ trunk/src/geniustests.txt Mon Feb 25 00:35:46 2008
@@ -889,7 +889,15 @@
IsDefined("IsDefined") true
IsDefined(`IsDefined) true
IsDefined(`UguUguUgu) false
+undefine(`UguUguUgu)+1 ((null)+1)
a=9;undefine(`a);a a
a=9;undefine("a");a a
+function f(x)=(k=1;ff=`()=(k+1);k=(`()=0);ff);ll=f(5) (`()=(k=(`()=0);(k+1)))
+function f(x)=(k=1;ff=`()=(k+1);k=2;ff);ll=f(5) (`()=(k=2;(k+1)))
+function f(x)=(k=1;ff=`()=(k+1);k=2;ff);ll=f(5);ll() 3
+function f(x)=(k=1;(function ff()=(k+1));k=2;ff);ll=f(5);ll() 3
+function f(x)=(ff=`()=(k+1);ff);ll=f(5) (`()=(k+1))
+k=9;function f(x)=(ff=`()=(k+1);ff);ll=f(5) (`()=(k+1))
+k=9;function f(x)=(ff=`()=(k+1);ff);ll=f(5);ll() 10
load "nullspacetest.gel" true
load "longtest.gel" true
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]