[anjuta] am-project: Take into account variable dependencies in evaluation



commit d2aa0eed1fbc2965af7a47c735ae5dd81566af28
Author: Sébastien Granjoux <seb sfo free fr>
Date:   Sat May 28 21:26:37 2011 +0200

    am-project: Take into account variable dependencies in evaluation

 libanjuta/anjuta-token.c             |   15 ++
 libanjuta/anjuta-token.h             |    1 +
 plugins/am-project/am-scanner.l      |  258 ++++++++++++++++++++++++++++++---
 plugins/am-project/tests/variable.at |   21 +++
 4 files changed, 271 insertions(+), 24 deletions(-)
---
diff --git a/libanjuta/anjuta-token.c b/libanjuta/anjuta-token.c
index 04c9737..0ee8122 100644
--- a/libanjuta/anjuta-token.c
+++ b/libanjuta/anjuta-token.c
@@ -1482,6 +1482,21 @@ anjuta_token_evaluate (AnjutaToken *token)
 	return g_string_free (value, *(value->str) == '\0');
 }
 
+/* Does not evaluate content if token is a variable */
+gchar *
+anjuta_token_evaluate_name (AnjutaToken *token)
+{
+	GString *value = g_string_new (NULL);
+	AnjutaToken *children = token->children;
+
+	token->children = NULL;
+	anjuta_token_foreach_content (token, evaluate_token, value);
+	token->children = children;
+	
+	/* Return NULL and free data for an empty string */
+	return g_string_free (value, *(value->str) == '\0');
+}
+
 gboolean
 anjuta_token_is_empty (AnjutaToken *token)
 {
diff --git a/libanjuta/anjuta-token.h b/libanjuta/anjuta-token.h
index d20efdc..7bd560c 100644
--- a/libanjuta/anjuta-token.h
+++ b/libanjuta/anjuta-token.h
@@ -139,6 +139,7 @@ AnjutaToken *anjuta_token_cut (AnjutaToken *token, guint pos, guint size);
 AnjutaToken *anjuta_token_concat(AnjutaToken *token);
 
 gchar *anjuta_token_evaluate (AnjutaToken *token);
+gchar *anjuta_token_evaluate_name (AnjutaToken *token);
 gboolean anjuta_token_is_empty (AnjutaToken *token);
 
 void anjuta_token_dump (AnjutaToken *token);
diff --git a/plugins/am-project/am-scanner.l b/plugins/am-project/am-scanner.l
index de2130e..5922f84 100644
--- a/plugins/am-project/am-scanner.l
+++ b/plugins/am-project/am-scanner.l
@@ -54,10 +54,22 @@ struct _AmpAmScanner
 	AmpGroupNode *group;
 	GHashTable *orphan_properties;
 	GList *am_variables;
+	GList *variables;
 	gboolean eof;		/* TRUE to emit EOF at the end */
 	gboolean expansion;		/* Expand variables */
 };
 
+struct _AmpVariableDepend
+{
+	GList *token;
+	GList *depend;
+	const gchar *name;
+	gboolean evaluated;
+};
+
+typedef struct _AmpVariableDepend AmpVariableDepend;
+
+
 %}
 
 %option reentrant noyywrap yylineno
@@ -230,6 +242,149 @@ amp_am_scanner_reparse_token (AmpAmScanner *scanner, AnjutaToken *token, GFile *
 	anjuta_token_free (token);
 }
 
+/* Private functions, variable dependencies
+ *---------------------------------------------------------------------------*/
+
+static AmpVariableDepend *
+amp_variable_depend_new (void)
+{
+	AmpVariableDepend *dep;
+
+	dep = g_new0 (AmpVariableDepend, 1);
+
+	return dep;
+}
+
+static void
+amp_variable_depend_free (AmpVariableDepend *depend)
+{
+	g_list_free (depend->token);
+	g_list_free (depend->depend);
+}
+
+static void
+list_depend (AnjutaToken *token, gpointer user_data)
+{
+	GList **depend = (GList **)user_data;
+
+	if (anjuta_token_get_type (token) == ANJUTA_TOKEN_VARIABLE)
+	{
+		gchar *string;
+		gchar *name;
+		guint length;		
+		
+		string = anjuta_token_evaluate_name(token);
+		length = strlen (string);
+		if (length > 1)
+		{
+			if (string[1] == '(')
+			{
+				string[length - 1] = '\0';
+				name = string + 2;
+			}
+			else
+			{
+				string[2] = '\0';
+				name = string + 1;
+			}
+			name = g_strdup (name);
+			*depend = g_list_prepend (*depend, name);
+		}
+	}
+}
+
+static void
+convert_dependencies (gchar *variable_name, AmpVariableDepend *variable, gpointer user_data)
+{
+	GList *list;
+	GHashTable *dependencies = (GHashTable *)user_data;
+	
+	variable->token = g_list_reverse (variable->token);
+
+	list = g_list_first (variable->depend);
+	if (list == NULL) variable->evaluated = TRUE;
+	for (; list != NULL;)
+	{
+		gchar *name = (gchar *)list->data;
+		AmpVariableDepend *depend;
+		GList *next;
+
+		depend =g_hash_table_lookup (dependencies, name);
+		g_free (name);
+		next = g_list_next (list);
+		
+		if (depend == NULL)
+		{
+			/* Unexisting variable, remove it from dependencies */
+			variable->depend = g_list_delete_link (variable->depend, list);
+		}
+		else
+		{
+			GList *dup;
+			
+			/* Look for duplicate */
+			for (dup = g_list_first (variable->depend); dup != list; dup = g_list_next (dup))
+			{
+				if (dup->data == depend) break;
+			}
+
+			if (dup == list)
+			{
+				dup->data = depend;
+			}
+			else
+			{
+				/* Find a duplicate */
+				variable->depend = g_list_delete_link (variable->depend, list);
+			}
+		}
+		list = next;
+	}
+	
+}
+
+static GHashTable *
+amp_am_scanner_compute_dependencies (AmpAmScanner *scanner)
+{
+	GHashTable *variable_dependencies;
+	GList *variable;
+			
+	/* Compute variables dependencies */
+	variable_dependencies = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, (GDestroyNotify)amp_variable_depend_free);
+	for (variable = g_list_first (scanner->variables); variable != NULL; variable = g_list_next (variable))
+	{
+		AnjutaToken *arg;
+		AnjutaToken *value;
+		gchar *name;
+		GList *list = NULL;
+		AmpVariableDepend *depend;
+			
+		arg = anjuta_token_first_item ((AnjutaToken *)variable->data);
+		name = g_strstrip (anjuta_token_evaluate (arg));
+
+		/* Find variable dependencies data */
+		depend =(AmpVariableDepend *)g_hash_table_lookup (variable_dependencies, name);
+		if (depend == NULL)
+		{
+			depend = amp_variable_depend_new ();
+			depend->name = name;
+			g_hash_table_insert (variable_dependencies, name, depend);
+		}
+
+		depend->token = g_list_prepend (depend->token, variable->data);
+		
+		/* Find dependencies */
+		value = anjuta_token_last_item ((AnjutaToken *)variable->data);
+		anjuta_token_foreach_token (value, list_depend, &list);
+		depend->depend = g_list_concat (list, depend->depend);
+	}
+
+	/* Replace name in dependencies by pointer */
+	g_hash_table_foreach (variable_dependencies, (GHFunc)convert_dependencies, variable_dependencies);
+
+	return variable_dependencies;
+}
+
 static gint
 amp_am_scanner_parse_end (AmpAmScanner *scanner)
 {
@@ -263,26 +418,6 @@ amp_am_scanner_parse_end (AmpAmScanner *scanner)
 	}
 }
 
-static GList *
-list_used_variable (AnjutaToken *token)
-{
-	AnjutaToken *last = anjuta_token_last (token);
-	GList *list = NULL;
-
-	for (;;)
-	{
-		if (anjuta_token_get_type (token) == ANJUTA_TOKEN_VARIABLE)
-		{
-			list = g_list_prepend (list, token);
-		}
-		if (token == last) break;
-		token = anjuta_token_next (token);
-	}
-	list = g_list_reverse (list);
-	
-	return list;
-}
-
 
 /* Parser functions
  *---------------------------------------------------------------------------*/
@@ -341,6 +476,7 @@ amp_am_scanner_include (AmpAmScanner *scanner, AnjutaToken *list)
 void
 amp_am_scanner_update_variable (AmpAmScanner *scanner, AnjutaToken *variable)
 {
+	if (scanner->expansion == FALSE) scanner->variables = g_list_prepend (scanner->variables, variable);
     amp_group_node_update_variable (scanner->group, variable);
 }
 
@@ -368,7 +504,6 @@ amp_am_scanner_parse_token (AmpAmScanner *scanner, AnjutaToken *root, AnjutaToke
 {
     AnjutaToken *first;
     AnjutaTokenStream *stream;
-	GList *variable;
 
     stream = anjuta_token_stream_push (scanner->stream, root, content, filename);
     first = anjuta_token_stream_get_root (stream);
@@ -401,14 +536,83 @@ amp_am_scanner_parse_token (AmpAmScanner *scanner, AnjutaToken *root, AnjutaToke
         } while (status == YYPUSH_MORE);
         amp_am_yypstate_delete (ps);
 
-		/* Evaluate autotools variable at the end */
+		/* Evaluate autotools variable and needed variables at the end */
 		if (scanner->expansion == FALSE)
 		{
+			GHashTable *variable_dependencies;
+			GList *variables;
+			GList *var;
+			guint evaluated;
+
+			variable_dependencies =amp_am_scanner_compute_dependencies (scanner);			
+			variables = g_hash_table_get_values (variable_dependencies);
+
+			/* Reevaluate variable having dependencies */
 			scanner->expansion = TRUE;
+			do
+			{
+				evaluated = 0;
+				for (var =variables; var != NULL;)
+				{
+					AmpVariableDepend *depend = (AmpVariableDepend *)var->data;
+					GList *next;
+
+					next = g_list_next (var);
+					if (depend->depend == NULL)
+					{
+						/* No need to reevaluate */
+						variables = g_list_delete_link (variables, var);
+					}
+					else
+					{
+						/* Check that all dependencies are evaluated */
+						GList*list;
+						gboolean missing = FALSE;
+
+						for (list = g_list_first (depend->depend); list != NULL; list = g_list_next (list))
+						{
+							if (((AmpVariableDepend *)list->data)->evaluated == FALSE)
+							{
+								missing = TRUE;
+								break;
+							}
+						}
+						if (missing == FALSE)
+						{
+							for (list = g_list_first (depend->token); list != NULL; list = g_list_next (list))
+							{
+								amp_am_scanner_reparse_token (scanner, (AnjutaToken *)list->data, filename);
+							}
+							variables = g_list_delete_link (variables, var);
+							depend->evaluated = TRUE;
+							evaluated++;
+						}
+					}
+					var = next;
+				}
+			}
+			while (evaluated);
+
+			/* The remaining variables have dependencies loop, evaluate them in order */
+			if (variables != NULL) g_warning ("Dependencies loop in variables");
+			for (var =variables; var != NULL; var = g_list_next (var))
+			{
+				AmpVariableDepend *depend = (AmpVariableDepend *)var->data;
+				GList *list;
+
+				for (list = g_list_first (depend->token); list != NULL; list = g_list_next (list))
+				{
+					amp_am_scanner_reparse_token (scanner, (AnjutaToken *)list->data, filename);
+				}
+			}
+			g_list_free (variables);
+			g_hash_table_destroy (variable_dependencies);
+
+			/* Evaluate autotools variables */
 			scanner->am_variables = g_list_reverse (scanner->am_variables);
-			for (variable = g_list_first (scanner->am_variables); variable != NULL; variable = g_list_next (variable))
+			for (var = g_list_first (scanner->am_variables); var != NULL; var = g_list_next (var))
 			{
-				AnjutaToken *token = (AnjutaToken *)variable->data;
+				AnjutaToken *token = (AnjutaToken *)var->data;
 
 				amp_am_scanner_reparse_token (scanner, token, filename);				
 			}
@@ -439,6 +643,9 @@ amp_am_scanner_new (AmpProject *project, AmpGroupNode *group)
 	scanner->am_variables = NULL;
 	scanner->expansion = FALSE;
 
+	/* Create list of variable */
+	scanner->variables = NULL;
+	
     yylex_init(&scanner->scanner);
     yyset_extra (scanner, scanner->scanner);
 
@@ -454,7 +661,10 @@ amp_am_scanner_free (AmpAmScanner *scanner)
 
 	/* Free unused sources files */
 	g_hash_table_destroy (scanner->orphan_properties);
+	
 	g_list_free (scanner->am_variables);
 
+	g_list_free (scanner->variables); 
+	
 	g_free (scanner);
 }
diff --git a/plugins/am-project/tests/variable.at b/plugins/am-project/tests/variable.at
index 2c27076..d4dba6c 100644
--- a/plugins/am-project/tests/variable.at
+++ b/plugins/am-project/tests/variable.at
@@ -63,4 +63,25 @@ AT_CHECK([diff -b output expect])
 
 
 
+AS_MKDIR_P([variable4])
+AT_DATA([variable4/configure.ac],
+[[AC_CONFIG_FILES(Makefile)
+]])
+AT_DATA([variable4/Makefile.am],
+[[
+bin_PROGRAMS = $(TARGETS)
+TARGETS = $(TARGETS1)
+TARGETS1 = target1
+]])
+AT_DATA([expect],
+[[    GROUP (): variable4
+        TARGET (): target1
+            PROPERTY (Installation directory): bindir
+]])
+AT_PARSER_CHECK([load variable4 \
+		 list])
+AT_CHECK([diff -b output expect])
+
+
+
 AT_CLEANUP



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