[genius] Wed Jul 22 14:44:10 2009 Jiri (George) Lebl <jirka 5z com>



commit ef35f07e154614d6d380412141513f45a132f80f
Author: Jiri (George) Lebl <jirka 5z com>
Date:   Wed Jul 22 14:44:22 2009 -0500

    Wed Jul 22 14:44:10 2009  Jiri (George) Lebl <jirka 5z com>
    
    	* configure.in: raise version, require slightly newer glib (2.10)
    
    	* src/compil.c, src/dict.[ch], src/eval.[ch], src/lexer.l,
    	  src/parse.y, src/parseutil.[ch], src/structs.h:  Add local
    	  variables (not seen by higher contexts).  Also fix several minor
    	  issues relating to dictionaries and lookup, mainly subst list
    	  function is not substituted again if it is passed up and down the
    	  contexts, and substitution is done in a smarter way.
    
    	* src/dict.[ch], src/gnome-genius.c: Redo the way contexts are done
    	  to get rid of some gslists
    
    	* src/mpwrap.[ch]: allocate new real nums in a smarter way (by large
    	  blocks) and put no limit on the number of real number structures
    	  on the free list.
    
    	* src/geniustests.txt, src/testscope.gel:  Add scope tests

 ChangeLog           |   22 ++++-
 configure.in        |    6 +-
 src/compil.c        |   62 ++++++++---
 src/dict.c          |  303 +++++++++++++++++++++++++++------------------------
 src/dict.h          |   23 +++-
 src/eval.c          |  217 ++++++++++++++++++++++++++++++------
 src/eval.h          |   14 ++-
 src/geniustests.txt |    1 +
 src/gnome-genius.c  |   12 +-
 src/lexer.l         |    2 +
 src/mpwrap.c        |   59 +++++++----
 src/parse.y         |   20 +++-
 src/parseutil.c     |   86 ++++++++++++++-
 src/parseutil.h     |    3 +
 src/structs.h       |   39 +++++--
 src/testscope.gel   |   50 +++++++++
 16 files changed, 664 insertions(+), 255 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 559eccd..a31e1d9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+Wed Jul 22 14:44:10 2009  Jiri (George) Lebl <jirka 5z com>
+
+	* configure.in: raise version, require slightly newer glib (2.10)
+
+	* src/compil.c, src/dict.[ch], src/eval.[ch], src/lexer.l,
+	  src/parse.y, src/parseutil.[ch], src/structs.h:  Add local
+	  variables (not seen by higher contexts).  Also fix several minor
+	  issues relating to dictionaries and lookup, mainly subst list
+	  function is not substituted again if it is passed up and down the
+	  contexts, and substitution is done in a smarter way.
+
+	* src/dict.[ch], src/gnome-genius.c: Redo the way contexts are done
+	  to get rid of some gslists
+
+	* src/mpwrap.[ch]: allocate new real nums in a smarter way (by large
+	  blocks) and put no limit on the number of real number structures
+	  on the free list.
+
+	* src/geniustests.txt, src/testscope.gel:  Add scope tests
+
 Wed Jul 22 00:30:36 2009  Jiri (George) Lebl <jirka 5z com>
 
 	* lib/number_theory/primes.gel: update for newest info from
@@ -963,7 +983,7 @@ Sat Nov 03 20:51:37 2007  Jiri (George) Lebl <jirka 5z com>
 	* src/Makefile.am:
 	* src/gnome-genius.c: (get_source_language_manager), (new_program):
 	Optionally allow to use GtkSourceView2 instead of GtkSourceView1.
-	Version 2 is preffered if available, otherwise version 1 will be used.
+	Version 2 is preferred if available, otherwise version 1 will be used.
 
 2007-11-03  Sebastian Dröge  <slomo circular-chaos org>
 
diff --git a/configure.in b/configure.in
index 45f72c6..902c3ca 100644
--- a/configure.in
+++ b/configure.in
@@ -1,7 +1,7 @@
 AC_INIT(src/calc.c)
 
 AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(genius,1.0.6)
+AM_INIT_AUTOMAKE(genius,1.0.7)
 
 dnl make sure we keep ACLOCAL_FLAGS around for maintainer builds to work
 AC_SUBST(ACLOCAL_AMFLAGS, "$ACLOCAL_FLAGS")
@@ -14,8 +14,8 @@ dnl ================= Requirements =============================================
 
 VTE_REQUIRED=0.8.19
 LIBGNOMEVFS_REQUIRED=2.0.0
-GTK_REQUIRED=2.6.0
-GLIB_REQUIRED=2.6.0
+GTK_REQUIRED=2.10.0
+GLIB_REQUIRED=2.10.0
 GTKSOURCEVIEW_REQUIRED=0.3.0
 GTKSOURCEVIEW2_REQUIRED=2.0.2
 
diff --git a/src/compil.c b/src/compil.c
index 3d942f1..8d84c05 100644
--- a/src/compil.c
+++ b/src/compil.c
@@ -34,16 +34,16 @@
 
 #include "compil.h"
 
-/*sort of weird encoding, use 'a'+upper 4 bits and 'a'+lower 4 bits*/
+/* sort of weird encoding, for each byte use 'a'+upper 4 bits and 'a'+lower 4 bits */
 static void
 append_string (GString *gs,const char *s)
 {
 	const char *p;
-	char out[3]="aa";
-	for(p=s;*p;p++) {
-		out[0]='a'+((*p)&0xF);
-		out[1]='a'+((*p)>>4);
-		g_string_append(gs,out);
+	char out[3] = "aa";
+	for (p = s; *p != '\0'; p++) {
+		out[0] = 'a' + ((*p)&0xF);
+		out[1] = 'a' + ((*p)>>4);
+		g_string_append (gs, out);
 	}
 }
 
@@ -53,8 +53,8 @@ gel_decode_string (const char *s)
 {
 	int len = strlen(s);
 	const char *ps;
-	char *p,*pp;
-	if(len%2 == 1)
+	char *p, *pp;
+	if (len%2 == 1)
 		return NULL;
 	
 	/*the 0 takes care of the termination*/
@@ -136,14 +136,25 @@ gel_compile_node(GelETree *t,GString *gs)
 	case GEL_FUNCTION_NODE:
 		g_assert(t->func.func->type==GEL_USER_FUNC);
 		/*g_assert(t->func.func->id==NULL);*/
-		g_string_append_printf (gs, ";%s;%s;%d;%d;%d;%d",
+		g_string_append_printf (gs, ";%s;%s;%d;%d;%d;%d;%d;",
 					t->func.func->id ? t->func.func->id->token : "*",
 					t->func.func->symbolic_id ? t->func.func->symbolic_id->token : "*",
 					t->func.func->nargs,
 					t->func.func->vararg,
 					t->func.func->propagate_mod,
-					t->func.func->no_mod_all_args);
-		for(li=t->func.func->named_args;li;li=g_slist_next(li)) {
+					t->func.func->no_mod_all_args,
+					t->func.func->local_all);
+
+		if (t->func.func->local_idents == NULL)
+			g_string_append (gs, "-");
+		for (li = t->func.func->local_idents; li != NULL; li = li->next) {
+			GelToken *tok = li->data;
+			if (li != t->func.func->local_idents)
+				g_string_append_printf (gs, ",%s", tok->token);
+			else
+				g_string_append_printf (gs, "%s", tok->token);
+		}
+		for (li = t->func.func->named_args; li != NULL; li = li->next) {
 			GelToken *tok = li->data;
 			g_string_append_printf (gs, ";%s", tok->token);
 		}
@@ -194,6 +205,7 @@ gel_decompile_node(char **ptrptr)
 	int vararg = -1;
 	int propagate_mod = -1;
 	int no_mod_all_args = -1;
+	int local_all = -1;
 	int quote;
 	int oper;
 	int i,j;
@@ -201,7 +213,7 @@ gel_decompile_node(char **ptrptr)
 	GelMatrixW *m;
 	GelETree *li = NULL;
 	GelETree *args;
-	GSList *oli;
+	GSList *oli, *local_idents;
 	GelEFunc *func;
 	mpw_t tmp;
 
@@ -357,11 +369,29 @@ gel_decompile_node(char **ptrptr)
 		sscanf(p,"%d",&no_mod_all_args);
 		if G_UNLIKELY (no_mod_all_args == -1) return NULL;
 
+		p = strtok_r (NULL,";", ptrptr);
+		if G_UNLIKELY (p == NULL) return NULL;
+		sscanf(p,"%d",&local_all);
+		if G_UNLIKELY (local_all == -1) return NULL;
+
+		p = strtok_r (NULL,";", ptrptr);
+		if G_UNLIKELY (p == NULL) return NULL;
+		local_idents = NULL;
+		if (strcmp (p, "-") != 0) {
+			char **s;
+			s = g_strsplit (p, ",", -1);
+			for (i = 0; s[i] != NULL; i++) {
+				local_idents = g_slist_append (local_idents, d_intern (s[i]));
+			}
+			g_strfreev (s);
+		}
+
 		oli = NULL;
 		for(i=0;i<nargs;i++) {
 			p = strtok_r (NULL,";", ptrptr);
 			if G_UNLIKELY (!p) {
-				g_slist_free(oli);
+				g_slist_free (oli);
+				g_slist_free (local_idents);
 				return NULL;
 			}
 			oli = g_slist_append(oli,d_intern(p));
@@ -369,7 +399,8 @@ gel_decompile_node(char **ptrptr)
 		
 		n = gel_decompile_node (ptrptr);
 		if G_UNLIKELY (!n) {
-			g_slist_free(oli);
+			g_slist_free (oli);
+			g_slist_free (local_idents);
 			return NULL;
 		}
 
@@ -380,6 +411,8 @@ gel_decompile_node(char **ptrptr)
 		func->vararg = vararg ? 1 : 0;
 		func->propagate_mod = propagate_mod ? 1 : 0;
 		func->no_mod_all_args = no_mod_all_args ? 1 : 0;
+		func->local_all = local_all ? 1 : 0;
+		func->local_idents = local_idents;
 
 		GEL_GET_NEW_NODE(n);
 		n->type = GEL_FUNCTION_NODE;
@@ -466,7 +499,6 @@ gel_decompile_tree (char *s)
 	
 	t = gel_decompile_node (&ptrptr);
 	if G_UNLIKELY (t == NULL) {
-		printf ("FOO!\n");
 		gel_errorout (_("Bad tree record when decompiling"));
 		return NULL;
 	}
diff --git a/src/dict.c b/src/dict.c
index c91c509..b1d7e5a 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -34,29 +34,18 @@
 
 /*the context stack structure*/
 typedef struct _GelDictContext {
-	GSList *stack;
-	GSList *subststack;
-	GSList *stackname;
+	GelContextFrame *stack;
+	GelContextFrame *global_frame;
 	int top;
 } GelDictContext;
 
-static GelDictContext context = {NULL, NULL, NULL, -1};
+static GelDictContext context = {NULL, NULL, -1};
 
 static GHashTable *dictionary;
 
 extern const char *genius_toplevels[];
 extern const char *genius_operators[];
 
-GelEFunc *free_funcs = NULL;
-
-#define GET_NEW_FUNC(n) \
-	if (free_funcs == NULL) {			\
-		n = g_new (GelEFunc, 1);		\
-	} else {					\
-		n = free_funcs;				\
-		free_funcs = free_funcs->data.next;	\
-	}
-
 /*return current context number (0 is global, -1 is uninitialized)*/
 int
 d_curcontext (void)
@@ -70,8 +59,7 @@ d_makebifunc (GelToken *id, GelBIFunction f, int nargs)
 {
 	GelEFunc *n;
 
-	GET_NEW_FUNC (n);
-	memset (n, 0, sizeof (GelEFunc));
+	n = g_slice_new0 (GelEFunc);
 	n->id = id;
 	n->data.func = f;
 	n->nargs = nargs;
@@ -81,6 +69,7 @@ d_makebifunc (GelToken *id, GelBIFunction f, int nargs)
 	n->vararg = 0;
 	n->on_subst_list = 0;
 	n->named_args = NULL;
+	n->local_idents = NULL;
 	n->extra_dict = NULL;
 	n->no_mod_all_args = FALSE;
 	n->propagate_mod = FALSE;
@@ -96,8 +85,7 @@ d_makeufunc (GelToken *id, GelETree *value, GSList *argnames, int nargs,
 {
 	GelEFunc *n;
 
-	GET_NEW_FUNC (n);
-	memset (n, 0, sizeof (GelEFunc));
+	n = g_slice_new0 (GelEFunc);
 
 	n->id = id;
 	n->data.user = value;
@@ -106,12 +94,14 @@ d_makeufunc (GelToken *id, GelETree *value, GSList *argnames, int nargs,
 	n->context = context.top;
 	n->type = GEL_USER_FUNC;
 
-	/* look at the memset
+	/* look at the new0
 	n->vararg = 0;
 	n->on_subst_list = 0;
 	n->no_mod_all_args = FALSE;
 	n->propagate_mod = FALSE;
 	n->extra_dict = NULL;
+	n->local_all = 0;
+	n->local_idents = NULL;
 	*/
 
 	if (extra_dict != NULL) {
@@ -130,15 +120,14 @@ d_makevfunc(GelToken *id, GelETree *value)
 {
 	GelEFunc *n;
 
-	GET_NEW_FUNC (n);
-	memset (n, 0, sizeof (GelEFunc));
+	n = g_slice_new0 (GelEFunc);
 
 	n->id = id;
 	n->data.user = value;
 	n->context = context.top;
 	n->type = GEL_VARIABLE_FUNC;
 
-	/* look at the memset
+	/* look at the new0
 	n->nargs = 0;
 	n->vararg = 0;
 	n->on_subst_list = 0;
@@ -146,6 +135,8 @@ d_makevfunc(GelToken *id, GelETree *value)
 	n->extra_dict = NULL;
 	n->no_mod_all_args = FALSE;
 	n->propagate_mod = FALSE;
+	n->local_all = 0;
+	n->local_idents = NULL;
 	*/
 
 	return n;
@@ -157,19 +148,19 @@ d_makereffunc(GelToken *id, GelEFunc *ref)
 {
 	GelEFunc *n;
 
-	GET_NEW_FUNC (n);
-	memset (n, 0, sizeof (GelEFunc));
+	n = g_slice_new0 (GelEFunc);
 
 	n->id = id;
 	n->data.ref = ref;
 	n->context = context.top;
 	n->type = GEL_REFERENCE_FUNC;
 
-	/* look at the memset
+	/* look at the new0
 	n->nargs = 0;
 	n->vararg = 0;
 	n->on_subst_list = 0;
 	n->named_args = NULL;
+	n->local_idents = NULL;
 	n->extra_dict = NULL;
 	n->no_mod_all_args = FALSE;
 	n->propagate_mod = FALSE;
@@ -185,8 +176,7 @@ d_copyfunc(GelEFunc *o)
 	GelEFunc *n;
 	GSList *li;
 
-	GET_NEW_FUNC (n);
-	memcpy (n, o, sizeof (GelEFunc));
+	n = g_slice_dup (GelEFunc, o);
 
 	if(n->type == GEL_USER_FUNC ||
 	   n->type == GEL_VARIABLE_FUNC) {
@@ -194,6 +184,7 @@ d_copyfunc(GelEFunc *o)
 		n->data.user = gel_copynode(o->data.user);
 	}
 	n->named_args = g_slist_copy (o->named_args);
+	n->local_idents = g_slist_copy (o->local_idents);
 
 	n->extra_dict = g_slist_copy (o->extra_dict);
 	for (li = n->extra_dict; li != NULL; li = li->next)
@@ -213,8 +204,8 @@ d_makerealfunc(GelEFunc *o,GelToken *id, gboolean use)
 {
 	GelEFunc *n;
 
-	GET_NEW_FUNC (n);
-	memcpy (n, o, sizeof (GelEFunc));
+	n = g_slice_dup (GelEFunc, o);
+
 	n->id = id;
 	if (o->symbolic_id == NULL)
 		n->symbolic_id = o->id;
@@ -232,18 +223,17 @@ d_makerealfunc(GelEFunc *o,GelToken *id, gboolean use)
 			n->data.user = gel_copynode(o->data.user);
 	}
 	if(use) {
-		o->named_args = NULL;
-		o->named_args = 0;
-	} else
-		n->named_args = g_slist_copy(o->named_args);
-
-	if (use) {
 		o->extra_dict = NULL;
+		o->named_args = NULL;
+		o->local_idents = NULL;
+		o->nargs = 0;
 	} else {
 		GSList *li;
 		n->extra_dict = g_slist_copy (o->extra_dict);
 		for (li = n->extra_dict; li != NULL; li = li->next)
 			li->data = d_copyfunc (li->data);
+		n->named_args = g_slist_copy (o->named_args);
+		n->local_idents = g_slist_copy (o->local_idents);
 	}
 
 	if (n->on_subst_list) {
@@ -280,11 +270,14 @@ d_setrealfunc(GelEFunc *n,GelEFunc *fake, gboolean use)
 
 	if(use) {
 		n->named_args = fake->named_args;
+		n->local_idents = fake->local_idents;
 		n->nargs = fake->nargs;
 		fake->named_args = NULL;
+		fake->local_idents = NULL;
 		fake->nargs = 0;
 	} else {
-		n->named_args = g_slist_copy(fake->named_args);
+		n->named_args = g_slist_copy (fake->named_args);
+		n->local_idents = g_slist_copy (fake->local_idents);
 		n->nargs = fake->nargs;
 	}
 
@@ -310,9 +303,8 @@ d_initcontext(void)
 
 	context.top = 0; /*0 means that element 0 exists!*/
 	/*add an empty dictionary*/
-	context.stack = g_slist_prepend (NULL,NULL);
-	context.subststack = g_slist_prepend (NULL,NULL);
-	context.stackname = g_slist_prepend (NULL,NULL);
+	context.stack = g_slice_new0 (GelContextFrame);
+	context.global_frame = context.stack;
 
 	dictionary = g_hash_table_new (g_str_hash, g_str_equal);
 
@@ -344,18 +336,24 @@ d_addfunc (GelEFunc *func)
 	GelEFunc *n;
 	
 	g_return_val_if_fail (func->context == context.top, func);
+
+	if (context.stack->local_all)
+		func->is_local = 1;
 	
 	/*we already found it (in current context)*/
 	n = d_lookup_local(func->id);
 	if(n) {
-		d_replacefunc(n,func);
+		int is_local = n->is_local;
+		d_replacefunc (n, func);
+		if (is_local)
+			n->is_local = 1;
 		return n;
 	}
 
-	context.stack->data = g_slist_prepend(context.stack->data,func);
+	context.stack->functions =
+		g_slist_prepend (context.stack->functions, func);
 	
 	func->id->refs = g_slist_prepend(func->id->refs,func);
-	func->id->curref = func;
 
 	return func;
 }
@@ -378,14 +376,10 @@ d_addfunc_global (GelEFunc *func)
 		return n;
 	}
 
-	last = g_slist_last (context.stack);
-	g_assert (last != NULL);
-
-	last->data = g_slist_prepend (last->data, func);
+	context.global_frame->functions =
+		g_slist_prepend (context.global_frame->functions, func);
 	
 	func->id->refs = g_slist_append (func->id->refs, func);
-	if (func->id->curref == NULL)
-		func->id->curref = func;
 
 	return func;
 }
@@ -411,16 +405,15 @@ GelEFunc *
 d_lookup_local(GelToken *id)
 {
 	GelEFunc *func;
-	
-	if(!id ||
-	   !id->refs)
+
+	if G_UNLIKELY (id == NULL || id->refs == NULL)
 		return NULL;
 	
 	/*the first one must be the lowest context*/
 	func = id->refs->data;
 	
 	/*not in currect context and we only want the currect context ones*/
-	if(func->context<context.top)
+	if (func->context < context.top)
 		return NULL;
 
 	return func;
@@ -431,20 +424,22 @@ GelEFunc *
 d_lookup_global_up1(GelToken *id)
 {
 	GelEFunc *func;
-	
-	if(!id ||
-	   !id->refs)
+	GSList *li;
+
+	if G_UNLIKELY (id == NULL || id->refs == NULL)
 		return NULL;
-	
+
 	/*the first one must be the lowest context*/
-	func = id->refs->data;
-	
-	if(func->context<context.top)
-		return func;
-	if(!id->refs->next)
-		return NULL;
-	
-	return id->refs->next->data;
+	li = id->refs;
+	do {
+		GelEFunc *f = li->data;
+		if ( ! f->is_local && f->context < context.top) {
+			return f;
+		}
+		li = li->next;
+	} while (li != NULL);
+
+	return NULL;
 }
 
 /*lookup a function in the dictionary but only in the toplevel context */
@@ -453,9 +448,8 @@ d_lookup_only_global (GelToken *id)
 {
 	GSList *li;
 	GelEFunc *func;
-	
-	if(!id ||
-	   !id->refs)
+
+	if G_UNLIKELY (id == NULL || id->refs == NULL)
 		return NULL;
 
 	li = id->refs;
@@ -471,12 +465,35 @@ d_lookup_only_global (GelToken *id)
 		return NULL;
 }
 
+/*lookup a function in the dictionary*/
+GelEFunc *
+d_lookup_global (GelToken *id)
+{
+	GelEFunc *func;
+	GSList *li;
+	
+	if G_UNLIKELY (id == NULL || id->refs == NULL)
+		return NULL;
+
+	/*the first one must be the lowest context*/
+	li = id->refs;
+	do {
+		GelEFunc *f = li->data;
+		if ( ! f->is_local || f->context == context.top) {
+			return f;
+		}
+		li = li->next;
+	} while (li != NULL);
+
+	return NULL;
+}
+
 GelToken *
 d_intern (const char *id)
 {
 	GelToken * tok;
 
-	if (id == NULL)
+	if G_UNLIKELY (id == NULL)
 		return NULL;
 
         tok = g_hash_table_lookup (dictionary, id);
@@ -495,9 +512,9 @@ d_intern (const char *id)
 static void
 whack_from_all_contexts (GelEFunc *func)
 {
-	GSList *li;
+	GelContextFrame *li;
 	for (li = context.stack; li != NULL; li = li->next) {
-		li->data = g_slist_remove (li->data, func);
+		li->functions = g_slist_remove (li->functions, func);
 	}
 }
 
@@ -510,7 +527,6 @@ d_delete(GelToken *id)
 	id->parameter = 0;
 	id->built_in_parameter = 0;
 
-	id->curref = NULL;
 	list = id->refs;
 	id->refs = NULL;
 	for (li = list; li != NULL; li = li->next) {
@@ -530,10 +546,10 @@ d_delete(GelToken *id)
 void
 d_singlecontext(void)
 {
-	if(context.stack==NULL)
+	if (context.stack == NULL)
 		d_initcontext();
 	else
-		while(context.top>0)
+		while (context.top > 0)
 			d_popcontext ();
 }
 
@@ -552,17 +568,17 @@ d_freedict (GSList *n)
 static void
 whack_from_subst_lists (GelEFunc *func)
 {
-	GSList *li;
-	for (li = context.subststack; li != NULL; li = li->next) {
-		GSList *fl = g_slist_find (li->data, func);
+	GelContextFrame *li;
+	for (li = context.stack; li != NULL; li = li->next) {
+		GSList *fl = g_slist_find (li->substlist, func);
 		if (fl != NULL) {
-			li->data = g_slist_delete_link (li->data, fl);
+			li->substlist = g_slist_delete_link (li->substlist, fl);
 			return;
 		}
 	}
 }
 
-/* Put on subst local var list for this current stack */
+/* Put on subst local var list for this current stack frame*/
 void
 d_put_on_subst_list (GelEFunc *func)
 {
@@ -572,8 +588,12 @@ d_put_on_subst_list (GelEFunc *func)
 		 * it will get to the lower one eventually */
 		whack_from_subst_lists (func);
 	}
-	context.subststack->data = 
-		g_slist_prepend (context.subststack->data, func);
+
+	if (func->context == -1)
+		func->context = context.top;
+
+	context.stack->substlist = 
+		g_slist_prepend (context.stack->substlist, func);
 	func->on_subst_list = 1;
 }
 
@@ -594,25 +614,23 @@ d_freefunc (GelEFunc *n)
 
 	/*if(n->id) {
 		n->id->refs = g_slist_remove(n->id->refs,n);
-		n->id->curref = n->id->refs?n->id->refs->data:NULL;
 	} */
 	if((n->type == GEL_USER_FUNC ||
 	    n->type == GEL_VARIABLE_FUNC) &&
 	   n->data.user)
 		gel_freetree(n->data.user);
-	g_slist_free(n->named_args);
+
 	for (li = n->extra_dict; li != NULL; li = li->next) {
 		d_freefunc (li->data);
 		li->data = NULL;
 	}
+
 	g_slist_free (n->extra_dict);
-#ifndef MEM_DEBUG_FRIENDLY
-	/*prepend to free list*/
-	n->data.next = free_funcs;
-	free_funcs = n;
-#else
-	g_free (n);
-#endif
+
+	g_slist_free (n->named_args);
+	g_slist_free (n->local_idents);
+
+	g_slice_free (GelEFunc, n);
 }
 
 /*replace old with stuff from new and free new,
@@ -642,7 +660,8 @@ d_replacefunc(GelEFunc *old,GelEFunc *_new)
 	   old->type == GEL_VARIABLE_FUNC)
 		gel_freetree(old->data.user);
 
-	g_slist_free(old->named_args);
+	g_slist_free (old->named_args);
+	g_slist_free (old->local_idents);
 
 	for (li = old->extra_dict; li != NULL; li = li->next) {
 		d_freefunc (li->data);
@@ -657,13 +676,7 @@ d_replacefunc(GelEFunc *old,GelEFunc *_new)
 		d_put_on_subst_list (old);
 	}
 
-#ifndef MEM_DEBUG_FRIENDLY
-	/*prepend to free list*/
-	_new->data.next = free_funcs;
-	free_funcs = _new;
-#else
-	g_free (_new);
-#endif
+	g_slice_free (GelEFunc, _new);
 }
 
 /*set_ref*/
@@ -676,9 +689,11 @@ d_set_ref(GelEFunc *n,GelEFunc *ref)
 	   n->type == GEL_VARIABLE_FUNC)
 		gel_freetree(n->data.user);
 	n->type = GEL_REFERENCE_FUNC;
-	g_slist_free(n->named_args);
+	g_slist_free (n->named_args);
+	g_slist_free (n->local_idents);
 	n->nargs = 0;
 	n->named_args = NULL;
+	n->local_idents = NULL;
 	
 	n->data.ref = ref;
 }
@@ -693,43 +708,42 @@ d_set_value(GelEFunc *n,GelETree *value)
 	   n->type == GEL_VARIABLE_FUNC)
 		gel_freetree(n->data.user);
 	n->type = GEL_VARIABLE_FUNC;
-	g_slist_free(n->named_args);
+	g_slist_free (n->named_args);
+	g_slist_free (n->local_idents);
 	n->nargs = 0;
 	n->named_args = NULL;
+	n->local_idents = NULL;
 	
 	n->data.user = value;
 }
 
-/*push a new dictionary onto the context stack*/
 gboolean
-d_addcontext(void)
+d_addcontext (GelEFunc *func)
 {
-	context.stack = g_slist_prepend (context.stack, NULL);
-	context.subststack = g_slist_prepend (context.subststack, NULL);
-	context.stackname = g_slist_prepend (context.stackname, NULL);
-	context.top++;
-	return TRUE;
-}
+	GelContextFrame *old = context.stack;
+	context.stack = g_slice_new0 (GelContextFrame);
+	context.stack->next = old;
+
+	if (func != NULL) {
+		context.stack->name = func->id;
+		context.stack->local_all = func->local_all;
+	}
 
-gboolean
-d_addcontext_named (GelToken *name)
-{
-	context.stack = g_slist_prepend (context.stack, NULL);
-	context.subststack = g_slist_prepend (context.subststack, NULL);
-	context.stackname = g_slist_prepend (context.stackname, name);
 	context.top++;
+
 	return TRUE;
 }
 
 /*pop the context stack*/
 void
-d_popcontext(void)
+d_popcontext (void)
 {
 	if (context.top != -1) {
 		GSList *li;
-		GSList *dict = context.stack->data;
-		GSList *subst = context.subststack->data;
+		GSList *dict = context.stack->functions;
+		GSList *subst = context.stack->substlist;
 		GSList *substlast = NULL;
+		GelContextFrame *of;
 
 		if (context.top != 0) {
 			for (li = subst; li != NULL; li = li->next) {
@@ -737,12 +751,24 @@ d_popcontext(void)
 				if (context.top == 1)
 					func->on_subst_list = 0;
 
-				if (func->type == GEL_USER_FUNC ||
-				    func->type == GEL_VARIABLE_FUNC) {
+				if ((func->type == GEL_USER_FUNC ||
+				     func->type == GEL_VARIABLE_FUNC) &&
+				    func->context >= context.top) {
 					D_ENSURE_USER_BODY (func);
+					if ( ! func->built_subst_dict) {
+						func->subst_dict = gel_get_ids_for_extradict (NULL,
+											      func->named_args,
+											      func->local_idents,
+											      func->data.user);
+						func->built_subst_dict = 1;
+					}
 					func->extra_dict =
-						gel_subst_local_vars (func->extra_dict,
-								      func->data.user);
+						gel_subst_local_vars (func->extra_dict, &(func->subst_dict));
+					/* With substitution, context of the function is
+					   lowered */
+					if (func->context >= context.top)
+						func->context = context.top - 1;
+
 				}
 
 				substlast = li;
@@ -752,19 +778,18 @@ d_popcontext(void)
 		for (li = dict; li != NULL; li = li->next) {
 			GelEFunc *func = li->data;
 			func->id->refs = g_slist_remove(func->id->refs,func);
-			func->id->curref =
-				func->id->refs?func->id->refs->data:NULL;
 		}
 		context.top--;
 
-		context.stack = g_slist_delete_link (context.stack, context.stack);
-		context.subststack = g_slist_delete_link (context.subststack, context.subststack);
-		context.stackname = g_slist_delete_link (context.stackname, context.stackname);
+		of = context.stack;
+		context.stack = of->next;
+
+		g_slice_free (GelContextFrame, of);
 
 		/* substitute lower variables unless we are on the toplevel */
 		if (substlast != NULL && context.top > 0) {
-			substlast->next = context.subststack->data;
-			context.subststack->data = subst;
+			substlast->next = context.stack->substlist;
+			context.stack->substlist = subst;
 			subst = NULL;
 		}
 
@@ -779,11 +804,13 @@ d_getcontext (void)
 {
 	if (context.top == -1)
 		return NULL;
-	else
-		return context.stack->data;
+	else {
+		g_assert (context.stack != NULL);
+		return context.stack->functions;
+	}
 }
 
-GSList *
+GelContextFrame *
 d_get_all_contexts (void)
 {
 	if (context.top == -1)
@@ -792,15 +819,6 @@ d_get_all_contexts (void)
 		return context.stack;
 }
 
-GSList *
-d_get_context_names (void)
-{
-	if (context.top == -1)
-		return NULL;
-	else
-		return context.stackname;
-}
-
 /*gimme the current global dictinary*/
 GSList *
 d_getcontext_global (void)
@@ -808,11 +826,8 @@ d_getcontext_global (void)
 	if (context.top == -1) {
 		return NULL;
 	} else {
-		GSList *last;
-		last = g_slist_last (context.stack);
-		g_assert (last != NULL);
-
-		return last->data;
+		g_assert (context.stack != NULL);
+		return context.global_frame->functions;
 	}
 }
 
diff --git a/src/dict.h b/src/dict.h
index c9a6c2b..758a61a 100644
--- a/src/dict.h
+++ b/src/dict.h
@@ -25,6 +25,18 @@
 /*declarations of structures*/
 #include "structs.h"
 
+typedef struct _GelContextFrame  GelContextFrame;
+struct _GelContextFrame  {
+	GelContextFrame *next;
+
+	GSList *functions;
+	GSList *substlist;
+	GelToken *name;
+
+	gboolean local_all;
+};
+
+
 /*return current context number (0 is global, -1 is uninitialized)*/
 int d_curcontext(void);
 
@@ -76,7 +88,7 @@ GelEFunc * d_lookup_global_up1(GelToken *id);
 GelEFunc * d_lookup_only_global (GelToken *id);
 /*lookup a function in the dictionary, if there are more return the one in the
   highest context*/
-#define d_lookup_global(id) ((id)->curref)
+GelEFunc * d_lookup_global (GelToken *id);
 
 GelToken * d_intern (const char *id);
 
@@ -96,8 +108,7 @@ void d_freefunc(GelEFunc *n);
 void d_replacefunc (GelEFunc *old, GelEFunc *_new);
 
 /*push a new dictionary onto the context stack*/
-gboolean d_addcontext(void);
-gboolean d_addcontext_named (GelToken *name);
+gboolean d_addcontext (GelEFunc *func);
 
 /*gimme the last dictinary and pop the context stack*/
 void d_popcontext(void);
@@ -105,9 +116,9 @@ void d_popcontext(void);
 /*gimme the current dictinary*/
 GSList * d_getcontext (void);
 
-/* this is a list of lists of the context stack */
-GSList * d_get_all_contexts (void);
-GSList * d_get_context_names (void);
+/* this is a list of lists of the context stack,
+ * Also it is a pointer to the current context frame */
+GelContextFrame * d_get_all_contexts (void);
 
 /*gimme the current global dictinary*/
 GSList * d_getcontext_global (void);
diff --git a/src/eval.c b/src/eval.c
index d62190b..9c36fee 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -570,6 +570,11 @@ freetree_full (GelETree *n, gboolean freeargs, gboolean kill)
 		if(freeargs && n->sp.arg)
 			gel_freetree(n->sp.arg);
 		break;
+	case GEL_LOCAL_NODE:
+		if(freeargs && n->loc.arg)
+			gel_freetree(n->loc.arg);
+		g_slist_free (n->loc.idents);
+		break;
 	default: break;
 	}
 	if(kill) {
@@ -758,6 +763,7 @@ copynode_to(GelETree *empty, GelETree *o)
 		else
 			empty->sp.arg = NULL;
 		break;
+	/* GEL_LOCAL_NODE: not needed */
 	default:
 		g_assert_not_reached();
 		break;
@@ -2594,7 +2600,8 @@ make_funccall (GelEFunc *a)
 	GEL_GET_NEW_NODE (nn);
 	nn->type = GEL_FUNCTION_NODE;
 	nn->func.func = d_copyfunc (a);
-	nn->func.func->context = -1;
+	if ( ! nn->func.func->on_subst_list)
+		nn->func.func->context = -1;
 
 	n->op.args = nn;
 
@@ -2787,7 +2794,8 @@ gel_function_from_function (GelEFunc *func, GelETree *l)
 	GEL_GET_NEW_NODE (n);
 	n->type = GEL_FUNCTION_NODE;
 	n->func.func = d_copyfunc (func);
-	n->func.func->context = -1;
+	if ( ! n->func.func->on_subst_list)
+		n->func.func->context = -1;
 
 	GEL_GET_NEW_NODE (nn);
 	nn->type = GEL_OPERATOR_NODE;
@@ -3315,7 +3323,8 @@ iter_do_var(GelCtx *ctx, GelETree *n, GelEFunc *f)
 			n->type = GEL_FUNCTION_NODE;
 			/* FIXME: are we ok with passing the token (f->id) as well? */
 			n->func.func = d_makerealfunc(f,f->id,FALSE);
-			n->func.func->context = -1;
+			if ( ! n->func.func->on_subst_list)
+				n->func.func->context = -1;
 			n->func.func->vararg = f->vararg;
 			/* FIXME: no need for extra_dict right? */
 			return TRUE;
@@ -3345,7 +3354,6 @@ iter_do_var(GelCtx *ctx, GelETree *n, GelEFunc *f)
 			/*make up a new fake id*/
 			GelToken *tok = g_new0(GelToken,1);
 			tok->refs = g_slist_append(NULL,f);
-			tok->curref = f;
 			i->id.id = tok;
 		}
 		i->any.next = NULL;
@@ -4532,7 +4540,7 @@ iter_funccallop(GelCtx *ctx, GelETree *n, gboolean *repushed)
 
 		EDEBUG("     USER FUNC PUSHING CONTEXT");
 
-		d_addcontext_named (f->id);
+		d_addcontext (f);
 
 		EDEBUG("     USER FUNC CONTEXT PUSHED TO ADD EXTRA DICT");
 
@@ -4550,13 +4558,14 @@ iter_funccallop(GelCtx *ctx, GelETree *n, gboolean *repushed)
 		for(ali = n->op.args->any.next;
 		    ali != NULL;
 		    ali = ali->any.next) {
+			GelEFunc *vf;
 			if (li->next == NULL) {
 				last_arg = li->data;
 				if (f->vararg)
 					break;
 			}
 			if (ali->type == GEL_FUNCTION_NODE) {
-				d_addfunc(d_makerealfunc(ali->func.func,li->data,FALSE));
+				vf = d_addfunc(d_makerealfunc(ali->func.func,li->data,FALSE));
 			} else if(ali->type == GEL_OPERATOR_NODE &&
 				  ali->op.oper == GEL_E_REFERENCE) {
 				GelETree *t = ali->op.args;
@@ -4566,10 +4575,12 @@ iter_funccallop(GelCtx *ctx, GelETree *n, gboolean *repushed)
 					gel_errorout (_("Referencing an undefined variable %s!"), t->id.id->token);
 					goto funccall_done_ok;
 				}
-				d_addfunc(d_makereffunc(li->data,rf));
+				vf = d_addfunc(d_makereffunc(li->data,rf));
 			} else {
-				d_addfunc(d_makevfunc(li->data,gel_copynode(ali)));
+				vf = d_addfunc(d_makevfunc(li->data,gel_copynode(ali)));
 			}
+			if (f->local_all)
+				vf->is_local = 1;
 			li = li->next;
 			if (li == NULL)
 				break;
@@ -4578,6 +4589,7 @@ iter_funccallop(GelCtx *ctx, GelETree *n, gboolean *repushed)
 		EDEBUG("     USER FUNC ABOUT TO HANDLE VARARG");
 
 		if (f->vararg) {
+			GelEFunc *vf;
 			if (last_arg == NULL) {
 				li = g_slist_last (f->named_args);
 				g_assert (li != NULL);
@@ -4585,7 +4597,7 @@ iter_funccallop(GelCtx *ctx, GelETree *n, gboolean *repushed)
 			}
 			/* no extra argument */
 			if (n->op.nargs == f->nargs) {
-				d_addfunc (d_makevfunc (last_arg, gel_makenum_null ()));
+				vf = d_addfunc (d_makevfunc (last_arg, gel_makenum_null ()));
 			} else {
 				GelETree *nn;
 				GelMatrix *m;
@@ -4605,8 +4617,24 @@ iter_funccallop(GelCtx *ctx, GelETree *n, gboolean *repushed)
 				nn->mat.quoted = FALSE;
 				nn->mat.matrix = gel_matrixw_new_with_matrix (m);
 
-				d_addfunc (d_makevfunc (last_arg, nn));
+				vf = d_addfunc (d_makevfunc (last_arg, nn));
+			}
+			if (f->local_all)
+				vf->is_local = 1;
+		}
+
+		EDEBUG("     CREATING LOCAL VARS");
+
+		for (li = f->local_idents;
+		     li != NULL;
+		     li = li->next) {
+			GelToken *tok = li->data;
+			GelEFunc *vf = d_lookup_local (tok);
+			if (vf == NULL) {
+				vf = d_addfunc (d_makevfunc
+					 (tok, gel_makenum_null ()));
 			}
+			vf->is_local = 1;
 		}
 
 		EDEBUG("     USER FUNC ABOUT TO ENSURE BODY");
@@ -5404,7 +5432,7 @@ iter_equalsop(GelETree *n)
 	GelETree *l,*r;
 
 	GEL_GET_LR(n,l,r);
-	
+
 	if G_UNLIKELY (l->type != GEL_IDENTIFIER_NODE &&
 		       !(l->type == GEL_OPERATOR_NODE && l->op.oper == GEL_E_GET_VELEMENT) &&
 		       !(l->type == GEL_OPERATOR_NODE && l->op.oper == GEL_E_GET_ELEMENT) &&
@@ -6607,7 +6635,7 @@ iter_operator_post (GelCtx *ctx, gboolean *repushed)
 }
 
 static gboolean
-function_id_on_list (GSList *funclist, GelToken *id)
+id_on_function_list (GSList *funclist, GelToken *id)
 {
 	GSList *li;
        
@@ -6620,33 +6648,30 @@ function_id_on_list (GSList *funclist, GelToken *id)
 }
 
 GSList *
-gel_subst_local_vars (GSList *funclist, GelETree *n)
+gel_get_ids_for_extradict (GSList *toklist, GSList *args, GSList *locals, GelETree *n)
 {
 	if (n == NULL)
-		return funclist;
+		return toklist;
 
 	if (n->type == GEL_IDENTIFIER_NODE) {
-		GelEFunc *func = d_lookup_local (n->id.id);
-		if (func != NULL &&
-		    ! function_id_on_list (funclist, n->id.id)) {
-			GelEFunc *f = d_copyfunc (func);
-			f->context = -1;
-			funclist = g_slist_prepend (funclist, f);
+		if (g_slist_find (args, n->id.id) == NULL &&
+		    g_slist_find (locals, n->id.id) == NULL &&
+		    g_slist_find (toklist, n->id.id) == NULL) {
+			toklist = g_slist_prepend (toklist, n->id.id);
 		}
 	} else if (n->type == GEL_SPACER_NODE) {
-		funclist = gel_subst_local_vars (funclist, n->sp.arg);
-	} else if(n->type == GEL_OPERATOR_NODE) {
-		/* special case to avoid more work
-		 * than needed */
-		if ((n->op.oper == GEL_E_EQUALS || n->op.oper == GEL_E_DEFEQUALS) &&
-		    n->op.args->type == GEL_IDENTIFIER_NODE) {
-			funclist = gel_subst_local_vars (funclist, n->op.args->any.next);
-		} else {
-			GelETree *args = n->op.args;
-			while (args != NULL) {
-				funclist = gel_subst_local_vars (funclist, args);
-				args = args->any.next;
-			}
+		toklist = gel_get_ids_for_extradict (toklist, args, locals, n->sp.arg);
+	} else if (n->type == GEL_OPERATOR_NODE) {
+		GelETree *al = n->op.args;
+		while (al != NULL) {
+			toklist = gel_get_ids_for_extradict (toklist, args, locals, al);
+			al = al->any.next;
+		}
+	} else if (n->type == GEL_COMPARISON_NODE) {
+		GelETree *al = n->comp.args;
+		while (al != NULL) {
+			toklist = gel_get_ids_for_extradict (toklist, args, locals, al);
+			al = al->any.next;
 		}
 	} else if (n->type == GEL_MATRIX_NODE &&
 		   n->mat.matrix != NULL &&
@@ -6655,24 +6680,57 @@ gel_subst_local_vars (GSList *funclist, GelETree *n)
 		int w,h;
 		w = gel_matrixw_width (n->mat.matrix);
 		h = gel_matrixw_height (n->mat.matrix);
-		gel_matrixw_make_private (n->mat.matrix, TRUE /* kill_type_caches */);
 		for (i = 0; i < w; i++) {
 			for(j = 0; j < h; j++) {
 				GelETree *t = gel_matrixw_get_index
 					(n->mat.matrix, i, j);
 				if (t != NULL)
-					funclist = gel_subst_local_vars (funclist, t);
+					toklist = gel_get_ids_for_extradict (toklist, args, locals, t);
 			}
 		}
 	} else if (n->type == GEL_SET_NODE) {
 		GelETree *ali;
 		for(ali = n->set.items; ali != NULL; ali = ali->any.next)
-			funclist = gel_subst_local_vars (funclist, ali);
+			toklist = gel_get_ids_for_extradict (toklist, args, locals, ali);
 	} else if (n->type == GEL_FUNCTION_NODE &&
 		   (n->func.func->type == GEL_USER_FUNC ||
 		    n->func.func->type == GEL_VARIABLE_FUNC)) {
 		D_ENSURE_USER_BODY (n->func.func);
-		funclist = gel_subst_local_vars (funclist, n->func.func->data.user);
+		toklist = gel_get_ids_for_extradict (toklist, args, locals, n->func.func->data.user);
+	}
+	return toklist;
+}
+
+GSList *
+gel_subst_local_vars (GSList *funclist, GSList **toklist)
+{
+	GSList *li;
+	GSList *prev;
+
+	li = *toklist;
+	prev = NULL;
+	while (li != NULL) {
+		GelToken *id = li->data;
+		GelEFunc *func = d_lookup_local (id);
+		if (func != NULL &&
+		    ! func->is_local) {
+			GSList *tmp;
+			GelEFunc *f = d_copyfunc (func);
+			if ( ! f->on_subst_list)
+				f->context = -1;
+			funclist = g_slist_prepend (funclist, f);
+			
+			tmp = li;
+			li = li->next;
+			if (prev != NULL) {
+				prev->next = g_slist_remove_link (prev->next, tmp);
+			} else {
+				*toklist = g_slist_remove_link (*toklist, tmp);
+			}
+		} else {
+			prev = li;
+			li = li->next;
+		}
 	}
 	return funclist;
 }
@@ -7064,6 +7122,89 @@ gather_comparisons_end:
 	return ret;
 }
 
+/* 0 not found
+   1 found OK
+   2 found not first */
+int
+gel_get_local_node (GelETree *n, gboolean first_arg,
+		    gboolean *local_all, GSList **local_idents)
+{
+	if (n == NULL) return 0;
+
+	if (n->type == GEL_LOCAL_NODE) {
+		if (first_arg) {
+			GelETree *arg = n->loc.arg;
+
+			*local_idents = n->loc.idents;
+			if (n->loc.idents == NULL)
+				*local_all = TRUE;
+
+			n->loc.idents = NULL;
+			n->loc.arg = NULL;
+
+			replacenode (n, arg);
+			if (gel_get_local_node (n, FALSE,
+						local_all, local_idents) == 2) {
+				return 2;
+			} else {
+				return 1;
+			}
+		} else {
+			return 2;
+		}
+	} else if (n->type == GEL_SPACER_NODE) {
+		return gel_get_local_node (n->sp.arg, first_arg, local_all, local_idents);
+	} else if (n->type == GEL_OPERATOR_NODE) {
+		GelETree *ali;
+		if (n->op.oper == GEL_E_SEPAR) {
+			int ret = gel_get_local_node (n->op.args, first_arg, local_all, local_idents);
+			if (ret == 2)
+				return 2;
+			for (ali = n->op.args->any.next; ali != NULL; ali = ali->any.next)
+				if (gel_get_local_node (ali, FALSE, local_all, local_idents))
+					return 2;
+			return ret;
+		} else {
+			for (ali = n->op.args; ali != NULL; ali = ali->any.next)
+				if (gel_get_local_node (ali, FALSE, local_all, local_idents))
+					return 2;
+		}
+		return FALSE;
+	} else if(n->type == GEL_MATRIX_NODE) {
+		int i, j;
+		int w, h;
+		if (n->mat.matrix == NULL ||
+		    gel_is_matrix_value_only (n->mat.matrix)) {
+			return 0;
+		}
+		w = gel_matrixw_width (n->mat.matrix);
+		h = gel_matrixw_height (n->mat.matrix);
+		gel_matrixw_make_private (n->mat.matrix, TRUE /* kill_type_caches */);
+		for (j = 0; j < h; j++) {
+			for (i = 0; i < w; i++) {
+				GelETree *t = gel_matrixw_get_index
+					(n->mat.matrix, i, j);
+				if (t != NULL) {
+					if (gel_get_local_node (t, FALSE, local_all,
+								local_idents))
+						return 2;
+				}
+			}
+		}
+		return FALSE;
+	} else if (n->type == GEL_SET_NODE) {
+		GelETree *ali;
+		for (ali = n->set.items; ali != NULL; ali = ali->any.next)
+			if (gel_get_local_node (ali, FALSE, local_all,
+						local_idents))
+				return 2;
+		return 0;
+	}
+	/* Note: Need not go into functions! */
+	/* Note: Need not go into comparison nodes as those do not exist yet! */
+	return 0;
+}
+
 void
 gel_replace_equals (GelETree *n, gboolean in_expression)
 {
@@ -7129,6 +7270,8 @@ gel_replace_equals (GelETree *n, gboolean in_expression)
 		/* function bodies are a completely new thing */
 		gel_replace_equals (n->func.func->data.user, FALSE);
 	}
+
+	/* Note: no need to handle comparison node, not yet created */
 }
 
 void
diff --git a/src/eval.h b/src/eval.h
index 94fd7c0..dc8d6e3 100644
--- a/src/eval.h
+++ b/src/eval.h
@@ -113,6 +113,13 @@ GelETree * gel_function_from_function (GelEFunc *func, GelETree *l);
 
 /* Functions to fixup the parsed tree */
 GelETree * gel_gather_comparisons(GelETree *n);
+
+/* 0 not found
+   1 found OK
+   2 found not first */
+gboolean gel_get_local_node (GelETree *n, gboolean first_arg,
+			     gboolean *local_all, GSList **local_idents);
+
 void gel_replace_equals (GelETree *n, gboolean in_expression);
 void gel_replace_exp (GelETree *n);
 void gel_fixup_num_neg (GelETree *n);
@@ -131,8 +138,11 @@ gboolean gel_eval_find_identifier (GelETree *n,
 char * gel_similar_possible_ids (const char *id);
 
 
-/* return a list of used local functions (copies of) */
-GSList * gel_subst_local_vars (GSList *, GelETree *n);
+GSList * gel_get_ids_for_extradict (GSList *toklist, GSList *args, GSList *locals, GelETree *n);
+
+/* return a list of used local functions (copies of).
+ * Modifies toklist to remove those already put on funclist */
+GSList * gel_subst_local_vars (GSList *funclist, GSList **toklist);
 
 void gel_mod_node (GelCtx *ctx, GelETree *n);
 gboolean gel_mod_integer_rational (mpw_t num, mpw_t mod);
diff --git a/src/geniustests.txt b/src/geniustests.txt
index 4e742d8..a37472b 100644
--- a/src/geniustests.txt
+++ b/src/geniustests.txt
@@ -933,3 +933,4 @@ CompositeSimpsonsRule(`(x)=x^2,3,3,100)				0
 load "nullspacetest.gel"					true
 load "longtest.gel"						true
 load "testprec.gel"						true
+load "testscope.gel"						true
diff --git a/src/gnome-genius.c b/src/gnome-genius.c
index 7703397..6f5b9ff 100644
--- a/src/gnome-genius.c
+++ b/src/gnome-genius.c
@@ -964,10 +964,9 @@ geniusbox (gboolean error,
 static void
 populate_var_box (GtkTextBuffer *buffer)
 {
-	GSList *all_contexts;
+	GelContextFrame *all_contexts, *lic;
 	GSList *funcs;
-	GSList *context_names;
-	GSList *li, *lic;
+	GSList *li;
 	GelOutput *out;
 	GtkTextIter iter;
 	GtkTextIter iter_end;
@@ -982,7 +981,6 @@ populate_var_box (GtkTextBuffer *buffer)
 	gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
 
 	all_contexts = d_get_all_contexts ();
-	context_names = d_get_context_names ();
 	funcs = d_getcontext_global ();
 
 	out = gel_output_new ();
@@ -1027,8 +1025,8 @@ populate_var_box (GtkTextBuffer *buffer)
 			(buffer, &iter, _("(depth of context in parentheses)\n\n"), -1, "note", NULL);
 
 		/* go over all local contexts (not the last one, that is global) */
-		for (lic = context_names; lic != NULL && lic->next != NULL; lic = lic->next) {
-			GelToken *tok = lic->data;
+		for (lic = all_contexts; lic != NULL && lic->next != NULL; lic = lic->next) {
+			GelToken *tok = lic->name;
 			char *s;
 
 			if (tok == NULL) {
@@ -1069,7 +1067,7 @@ populate_var_box (GtkTextBuffer *buffer)
 
 	/* go over all local contexts (not the last one, that is global) */
 	for (lic = all_contexts; lic != NULL && lic->next != NULL; lic = lic->next) {
-		for (li = lic->data; li != NULL; li = li->next) {
+		for (li = lic->functions; li != NULL; li = li->next) {
 			GelEFunc *f = li->data;
 			char *s;
 			if (f->type != GEL_VARIABLE_FUNC ||
diff --git a/src/lexer.l b/src/lexer.l
index 770c210..a1b6763 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -294,6 +294,8 @@ mod		{ NO_RET; return MOD; }
 
 null		{ DO_RET; return '.'; }
 
+local		{ DO_RET; return LOCAL; }
+
 "@("		{
 			gel_parenth_depth++;
 			if (matrix_entry_stack != NULL)
diff --git a/src/mpwrap.c b/src/mpwrap.c
index 54a3c60..72758ac 100644
--- a/src/mpwrap.c
+++ b/src/mpwrap.c
@@ -54,9 +54,6 @@ struct _MpwCtx {
 };
 #endif
 
-static MpwRealNum *free_reals = NULL;
-static int free_reals_n = 0;
-
 MpwRealNum *gel_zero = NULL;
 MpwRealNum *gel_one = NULL;
 
@@ -137,16 +134,42 @@ static __mpfr_struct *free_mpfr_top = free_mpfr;
 	}						\
 }
 
+#ifdef MEM_DEBUG_FRIENDLY
+# define GET_NEW_REAL(n) (n = g_new0 (MpwRealNum, 1));
+#else
+
+/* In tests it seems that this achieves better then 4096 */
+#define GEL_CHUNK_SIZE 4048
+#define ALIGNED_SIZE(t) (sizeof(t) + sizeof (t) % G_MEM_ALIGN)
+
+static MpwRealNum *free_reals = NULL;
+
+static void
+_gel_make_free_reals (void)
+{
+	int i;
+	char *p;
 
+	p = g_malloc ((GEL_CHUNK_SIZE / ALIGNED_SIZE (MpwRealNum)) *
+		      ALIGNED_SIZE (MpwRealNum));
+	for (i = 0; i < (GEL_CHUNK_SIZE / ALIGNED_SIZE (MpwRealNum)); i++) {
+		MpwRealNum *t = (MpwRealNum *)p;
+		/*put onto the free list*/
+		t->alloc.next = free_reals;
+		free_reals = t;
+		p += ALIGNED_SIZE (MpwRealNum);
+	}
+}
 #define GET_NEW_REAL(n) {				\
-	if(!free_reals) {				\
-		n = g_new0(MpwRealNum,1);		\
-	} else {					\
-		n = free_reals;				\
-		free_reals = free_reals->alloc.next;	\
-		free_reals_n--;				\
+	if G_UNLIKELY (free_reals == NULL) {		\
+		_gel_make_free_reals ();		\
 	}						\
+	(n) = free_reals;				\
+    	free_reals = free_reals->alloc.next;		\
 }
+
+#endif
+
 #define MAKE_COPY(n) {					\
 	if((n)->alloc.usage>1) {			\
 		MpwRealNum *m;				\
@@ -643,18 +666,12 @@ mpwl_free(MpwRealNum *op)
 
 	mpwl_clear(op);
 
-	/*FIXME: the 2000 should be settable*/
-	/*if we want to store this so that we don't allocate new one
-	  each time, up to a limit of 2000, unless it was some local
-	  var in which case it can't be freed nor put on the free
-	  stack*/
-	if(free_reals_n>2000) {
-		g_free(op);
-	} else {
-		op->alloc.next = free_reals;
-		free_reals = op;
-		free_reals_n++;
-	}
+#ifdef MEM_DEBUG_FRIENDLY
+	g_free (op);
+#else
+	op->alloc.next = free_reals;
+	free_reals = op;
+#endif
 }
 
 static inline int
diff --git a/src/parse.y b/src/parse.y
index 8b982dd..dfe26a9 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -59,7 +59,7 @@ void yyerror(char *);
 
 %token FUNCTION CALL THREEDOTS PARAMETER
 
-%token RETURNTOK BAILOUT EXCEPTION CONTINUE BREAK
+%token RETURNTOK BAILOUT EXCEPTION CONTINUE BREAK LOCAL
 
 %token WHILE UNTIL FOR SUM PROD DO IF THEN ELSE TO BY IN
 
@@ -75,15 +75,15 @@ void yyerror(char *);
 
 %token LOGICAL_XOR LOGICAL_OR LOGICAL_AND LOGICAL_NOT
 
-
 %left NEXTROW
 
 %left SEPAR
 
+
 %nonassoc FUNCTION PARAMETER
 
-%nonassoc LOWER_THEN_ELSE
-%nonassoc WHILE UNTIL DO IF FOR SUM PROD TO BY IN THEN ELSE RETURNTOK
+%nonassoc LOWER_THAN_ELSE
+%nonassoc WHILE UNTIL DO IF FOR SUM PROD TO BY IN THEN ELSE RETURNTOK LOCAL
 
 %left LOGICAL_XOR LOGICAL_OR
 %left LOGICAL_AND
@@ -130,6 +130,14 @@ fullexpr:	STARTTOK expr '\n' { YYACCEPT; }
 	;
 
 expr:		expr SEPAR expr		{ PUSH_ACT(GEL_E_SEPAR); }
+	|	LOCAL '*' SEPAR expr	{ if ( ! gp_push_local_all ()) {
+						SYNTAX_ERROR;
+					  }
+       					}
+	|	LOCAL identlist SEPAR expr { if ( ! gp_push_local_idents ()) {
+						SYNTAX_ERROR;
+					  }
+					}
 	|	expr MOD expr		{ PUSH_ACT(GEL_E_MOD_CALC); }
 	|	'(' expr SEPAR ')'	{ gp_push_null(); PUSH_ACT(GEL_E_SEPAR);
 					  gp_push_spacer(); }
@@ -226,7 +234,7 @@ expr:		expr SEPAR expr		{ PUSH_ACT(GEL_E_SEPAR); }
 	|	PROD ident anyequals expr TO expr DO expr { PUSH_ACT(GEL_E_PROD_CONS); }
 	|	PROD ident anyequals expr TO expr BY expr DO expr { PUSH_ACT(GEL_E_PRODBY_CONS); }
 	|	PROD ident IN expr DO expr { PUSH_ACT(GEL_E_PRODIN_CONS); }
-	|	IF expr THEN expr %prec LOWER_THEN_ELSE	{ PUSH_ACT(GEL_E_IF_CONS); }
+	|	IF expr THEN expr %prec LOWER_THAN_ELSE	{ PUSH_ACT(GEL_E_IF_CONS); }
 	|	IF expr THEN expr ELSE expr { PUSH_ACT(GEL_E_IFELSE_CONS); }
 	|	ident			{ gp_convert_identifier_to_bool ();
 					  /* convert true/false to bool */}
@@ -276,7 +284,7 @@ paramdef: 	ident anyequals expr %prec EQUALS {
 anyequals:	EQUALS
 	|	DEFEQUALS
 	;
-	
+
 funcdef:	'(' identlist ')' anyequals expr %prec FUNCTION {
 			if ( ! gp_push_func (FALSE /* vararg */)) {
 				SYNTAX_ERROR;
diff --git a/src/parseutil.c b/src/parseutil.c
index de51057..5d2ad7f 100644
--- a/src/parseutil.c
+++ b/src/parseutil.c
@@ -44,11 +44,20 @@ gp_push_func (gboolean vararg)
 	GelETree * val;
 	GSList * list = NULL;
 	int i = 0;
+	gboolean local_all = FALSE;
+	GSList *local_idents = NULL;
 	
-	val = gel_stack_pop(&gel_parsestack);
-	if(!val)
+	val = gel_stack_pop (&gel_parsestack);
+	if G_UNLIKELY (val == NULL)
 		return FALSE;
 
+	if (gel_get_local_node (val, TRUE /*first_arg*/,
+				&local_all, &local_idents) == 2) {
+		gel_errorout ("%s", _("ERROR: local statement not the first statement in function definition"));
+		gel_freetree (val);
+		g_slist_free (local_idents);
+		return FALSE;
+	}
 
 	for(;;) {
 		tree = gel_stack_pop(&gel_parsestack);
@@ -58,10 +67,11 @@ gp_push_func (gboolean vararg)
 		}
 		/*we have gone all the way to the top and haven't found a
 		  marker or tree is not an ident node*/
-		if(!tree || tree->type != GEL_IDENTIFIER_NODE) {
+		if G_UNLIKELY (tree == NULL ||
+			       tree->type != GEL_IDENTIFIER_NODE) {
 			if(tree) gel_freetree(tree);
-			g_slist_foreach(list,(GFunc)gel_freetree,NULL);
 			g_slist_free(list); 
+			g_slist_free (local_idents);
 			return FALSE;
 		}
 		list = g_slist_prepend(list,tree->id.id);
@@ -75,6 +85,8 @@ gp_push_func (gboolean vararg)
 	tree->func.func = d_makeufunc(NULL,val,list,i, NULL);
 	tree->func.func->context = -1;
 	tree->func.func->vararg = vararg;
+	tree->func.func->local_all = local_all ? 1 : 0;
+	tree->func.func->local_idents = local_idents;
 
 	gel_stack_push(&gel_parsestack,tree);
 
@@ -166,6 +178,8 @@ gp_push_marker_simple(GelETreeType markertype)
 	gel_stack_push(&gel_parsestack,tree);
 }
 
+
+
 /*puts a spacer into the tree, spacers are just useless nodes to be removed
   before evaluation, they just signify where there were parenthesis*/
 gboolean
@@ -173,7 +187,7 @@ gp_push_spacer(void)
 {
 	GelETree * last_expr = gel_stack_pop(&gel_parsestack);
 	
-	if(!last_expr)
+	if G_UNLIKELY (last_expr == NULL)
 		return FALSE;
 	else if(last_expr->type == GEL_SPACER_NODE)
 		gel_stack_push(&gel_parsestack,last_expr);
@@ -186,6 +200,68 @@ gp_push_spacer(void)
 	}
 	return TRUE;
 }
+
+/*puts a local node into the tree, locals are just useless nodes to be removed
+  right after parsing */
+gboolean
+gp_push_local_all (void)
+{
+	GelETree * tree;
+	GelETree * last_expr = gel_stack_pop (&gel_parsestack);
+	
+	if G_UNLIKELY (last_expr == NULL)
+		return FALSE;
+
+	GEL_GET_NEW_NODE (tree);
+	tree->type = GEL_LOCAL_NODE;
+	tree->loc.arg = last_expr;
+	tree->loc.idents = NULL; /* all */
+	gel_stack_push (&gel_parsestack, tree);
+
+	return TRUE;
+}
+
+/*puts a local node into the tree, locals are just useless nodes to be removed
+  right after parsing */
+gboolean
+gp_push_local_idents (void)
+{
+	GelETree * tree;
+	GSList * list = NULL;
+	int i = 0;
+	GelETree * last_expr = gel_stack_pop (&gel_parsestack);
+	
+	if G_UNLIKELY (last_expr == NULL)
+		return FALSE;
+
+	for (;;) {
+		tree = gel_stack_pop (&gel_parsestack);
+		if (tree && tree->type == GEL_EXPRLIST_START_NODE) {
+			gel_freetree (tree);
+			break;
+		}
+		/*we have gone all the way to the top and haven't found a
+		  marker or tree is not an ident node*/
+		if G_UNLIKELY (tree == NULL ||
+			       tree->type != GEL_IDENTIFIER_NODE) {
+			if (tree != NULL)
+				gel_freetree(tree);
+			g_slist_free (list); 
+			return FALSE;
+		}
+		list = g_slist_prepend (list, tree->id.id);
+		gel_freetree (tree);
+		i++;
+	}
+
+	GEL_GET_NEW_NODE (tree);
+	tree->type = GEL_LOCAL_NODE;
+	tree->loc.arg = last_expr;
+	tree->loc.idents = list;
+	gel_stack_push (&gel_parsestack, tree);
+
+	return TRUE;
+}
 	
 /*gather all expressions up until a row start marker and push the
   result as a GEL_MATRIX_ROW_NODE*/
diff --git a/src/parseutil.h b/src/parseutil.h
index 0b56443..f753790 100644
--- a/src/parseutil.h
+++ b/src/parseutil.h
@@ -27,6 +27,9 @@ gboolean gp_push_func (gboolean vararg) GEL_WEAK_FUNC;
 gboolean gp_prepare_push_param (gboolean setfunc) GEL_WEAK_FUNC;
 gboolean gp_prepare_push_region_sep (void) GEL_WEAK_FUNC;
 
+gboolean gp_push_local_all (void) GEL_WEAK_FUNC;
+gboolean gp_push_local_idents (void) GEL_WEAK_FUNC;
+
 void gp_convert_identifier_to_bool (void) GEL_WEAK_FUNC;
 
 /*pops the last expression, pushes a marker
diff --git a/src/structs.h b/src/structs.h
index 3d34950..2ef214b 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -53,6 +53,7 @@ typedef struct _GelETreeMatrixRow GelETreeMatrixRow;
 /*typedef struct _GelETreeMatrixStart GelETreeMatrixStart;*/
 /*typedef struct _GelETreeExprlistStart GelETreeExprlistStart;*/
 typedef struct _GelETreeSpacer GelETreeSpacer;
+typedef struct _GelETreeLocal GelETreeLocal;
 typedef struct _GelToken GelToken;
 
 typedef struct _GelEvalStack GelEvalStack;
@@ -73,11 +74,11 @@ typedef GelETree *(* ParameterGetFunc) (void);
 
 typedef	GelETree *(* GelBIFunction) (GelCtx *ctx, GelETree * *, gboolean *); /*the gboolean is exception*/
 
+
 /* tokens point to this structure globaly, there is
    one such structure for each token.  */
 struct _GelToken {
 	char *token;
-	GelEFunc *curref;
 	GSList *refs;
 
 	/* For built-in parameters this is the get and set function
@@ -102,6 +103,9 @@ struct _GelEFunc {
 
 	GSList *extra_dict;
 
+	GSList *local_idents;
+	GSList *subst_dict;
+
 	union {
 		GelETree *user;
 		GelBIFunction func;
@@ -109,17 +113,27 @@ struct _GelEFunc {
 		GelEFunc *next; /*this is for keeping a free list*/
 	} data;
 
-	guint16 nargs; /*number of arguments*/
+	guint32 nargs:16; /*number of arguments*/
 
 	/* GelEFuncType type; */
-	guint8 type:3;
+	guint32 type:3;
 
 	/* if true, we must take this off the subst list for a context pop,
 	 * before we free the function */
-	guint8 on_subst_list:1;
-	guint8 vararg:1;
-	guint8 propagate_mod:1;
-	guint8 no_mod_all_args:1;
+	guint32 on_subst_list:1;
+	guint32 vararg:1;
+	guint32 propagate_mod:1;
+	guint32 no_mod_all_args:1;
+
+	/* this is true if all local vars of this function
+	   will be local-scoped */
+	guint32 local_all:1;
+
+	/* is this variable local */
+	guint32 is_local:1;
+
+	/* did we already build the subst_list */
+	guint32 built_subst_dict:1;
 };
 
 typedef enum {
@@ -140,7 +154,8 @@ typedef enum {
 	GEL_MATRIX_ROW_NODE=1000,
 	GEL_MATRIX_START_NODE,
 	GEL_EXPRLIST_START_NODE,
-	GEL_SPACER_NODE
+	GEL_SPACER_NODE,
+	GEL_LOCAL_NODE
 } GelETreeType;
 
 struct _GelETreeAny {
@@ -286,6 +301,13 @@ struct _GelETreeSpacer {
 	GelETree *arg;
 };
 
+struct _GelETreeLocal {
+	GelETreeType type;
+	GelETree *next;
+	GSList *idents; /* NULL means all */
+	GelETree *arg;
+};
+
 union _GelETree {
 	GelETreeType type;
 	GelETreeAny any; /*for allocation purposes only*/
@@ -305,6 +327,7 @@ union _GelETree {
 	/*GelETreeMatrixStart mats;*/
 	/*GelETreeExprlistStart exps;*/
 	GelETreeSpacer sp;
+	GelETreeLocal loc;
 };
 
 /* builtin primitives (operator node type) */
diff --git a/src/testscope.gel b/src/testscope.gel
new file mode 100644
index 0000000..b11e2ba
--- /dev/null
+++ b/src/testscope.gel
@@ -0,0 +1,50 @@
+A = 1;
+function f(x) = (
+	A=2;
+	A
+);
+if f(0) != 2 then (error("simple local lookup failed");exit());
+
+A = 1;
+function f(x) = (
+	A
+);
+if f(0) != 1 then (error("simple global lookup failed");exit());
+
+A = 1;
+function f(x) = (
+	A = 8;
+	function g(y) = A+5;
+	g(x)
+);
+if f(0) != 8+5 then (error("intermediate global lookup failed");exit());
+
+A = 1;
+function f(x) = (
+	A = 8;
+	function g(y) = A+5;
+	g
+);
+h = f(0);
+if h(0) != 8+5 then (error("single subst lookup failed");exit());
+
+A = 1;
+function f(x) = (
+	local A;
+	A = 8;
+	function g(y) = A+5;
+	g(x)
+);
+if f(0) != 1+5 then (error("global lookup over local failed");exit());
+
+A = 1;
+function f(x) = (
+	local *;
+	A = 8;
+	function g(y) = A+5;
+	g(x)
+);
+if f(0) != 1+5 then (error("global lookup over all local failed");exit());
+
+
+print("true");



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]