Blame ns.c

Packit 4a5d52
/***************************************************************************
Packit 4a5d52
Packit 4a5d52
    ns.c (libIDL namespace functions)
Packit 4a5d52
Packit 4a5d52
    Copyright (C) 1998, 1999 Andrew T. Veliath
Packit 4a5d52
Packit 4a5d52
    This library is free software; you can redistribute it and/or
Packit 4a5d52
    modify it under the terms of the GNU Library General Public
Packit 4a5d52
    License as published by the Free Software Foundation; either
Packit 4a5d52
    version 2 of the License, or (at your option) any later version.
Packit 4a5d52
Packit 4a5d52
    This library is distributed in the hope that it will be useful,
Packit 4a5d52
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4a5d52
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 4a5d52
    Library General Public License for more details.
Packit 4a5d52
Packit 4a5d52
    You should have received a copy of the GNU Library General Public
Packit 4a5d52
    License along with this library; if not, write to the Free
Packit 4a5d52
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Packit 4a5d52
Packit 4a5d52
    $Id$
Packit 4a5d52
Packit 4a5d52
***************************************************************************/
Packit 4a5d52
#include <assert.h>
Packit 4a5d52
#include <stdarg.h>
Packit 4a5d52
#include <stdio.h>
Packit 4a5d52
#include <stdlib.h>
Packit 4a5d52
#include <ctype.h>
Packit 4a5d52
#include <string.h>
Packit 4a5d52
#include <errno.h>
Packit 4a5d52
#include "rename.h"
Packit 4a5d52
#include "util.h"
Packit 4a5d52
Packit 4a5d52
static int is_inheritance_conflict (IDL_tree p);
Packit 4a5d52
Packit 4a5d52
IDL_ns IDL_ns_new (void)
Packit 4a5d52
{
Packit 4a5d52
	IDL_ns ns;
Packit 4a5d52
Packit 4a5d52
	ns = g_new0 (struct _IDL_ns, 1);
Packit 4a5d52
	if (ns == NULL) {
Packit 4a5d52
		yyerror ("IDL_ns_new: memory exhausted");
Packit 4a5d52
		return NULL;
Packit 4a5d52
	}
Packit 4a5d52
Packit 4a5d52
	IDL_NS (ns).global = IDL_gentree_new (IDL_ident_hash,
Packit 4a5d52
					      IDL_ident_equal,
Packit 4a5d52
					      IDL_ident_new (""));
Packit 4a5d52
	IDL_NS (ns).file =  IDL_NS (ns).current = IDL_NS (ns).global;
Packit 4a5d52
	IDL_NS (ns).inhibits = g_hash_table_new (g_direct_hash, g_direct_equal);
Packit 4a5d52
	IDL_NS (ns).filename_hash = g_hash_table_new (g_str_hash, g_str_equal);
Packit 4a5d52
Packit 4a5d52
	return ns;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
static void filename_hash_free (char *filename, IDL_fileinfo *fi)
Packit 4a5d52
{
Packit 4a5d52
	g_free (fi->name);
Packit 4a5d52
	g_free (fi);
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
void IDL_ns_free (IDL_ns ns)
Packit 4a5d52
{
Packit 4a5d52
	assert (ns != NULL);
Packit 4a5d52
Packit 4a5d52
	g_hash_table_foreach (IDL_NS (ns).inhibits, (GHFunc)IDL_tree_free, NULL);
Packit 4a5d52
	g_hash_table_destroy (IDL_NS (ns).inhibits);
Packit 4a5d52
	g_hash_table_foreach (IDL_NS (ns).filename_hash, (GHFunc) filename_hash_free, NULL);
Packit 4a5d52
	g_hash_table_destroy (IDL_NS (ns).filename_hash);
Packit 4a5d52
	IDL_tree_free (IDL_NS (ns).global);
Packit 4a5d52
Packit 4a5d52
	g_free (ns);
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
#define IDL_NS_ASSERTS		do {						\
Packit 4a5d52
	assert (ns != NULL);							\
Packit 4a5d52
	if (__IDL_is_parsing) {							\
Packit 4a5d52
		assert (IDL_NS (ns).global != NULL);				\
Packit 4a5d52
		assert (IDL_NS (ns).file != NULL);				\
Packit 4a5d52
		assert (IDL_NS (ns).current != NULL);				\
Packit 4a5d52
		assert (IDL_NODE_TYPE (IDL_NS (ns).global) == IDLN_GENTREE);	\
Packit 4a5d52
		assert (IDL_NODE_TYPE (IDL_NS (ns).file) == IDLN_GENTREE);	\
Packit 4a5d52
		assert (IDL_NODE_TYPE (IDL_NS (ns).current) == IDLN_GENTREE);	\
Packit 4a5d52
	}									\
Packit 4a5d52
} while (0)
Packit 4a5d52
Packit 4a5d52
int IDL_ns_prefix (IDL_ns ns, const char *s)
Packit 4a5d52
{
Packit 4a5d52
	char *r;
Packit 4a5d52
	int l;
Packit 4a5d52
Packit 4a5d52
	IDL_NS_ASSERTS;
Packit 4a5d52
Packit 4a5d52
	if (s == NULL)
Packit 4a5d52
		return FALSE;
Packit 4a5d52
Packit 4a5d52
	if (*s == '"')
Packit 4a5d52
		r = g_strdup (s + 1);
Packit 4a5d52
	else
Packit 4a5d52
		r = g_strdup (s);
Packit 4a5d52
Packit 4a5d52
	l = strlen (r);
Packit 4a5d52
	if (l && r[l - 1] == '"')
Packit 4a5d52
		r[l - 1] = 0;
Packit 4a5d52
Packit 4a5d52
	if (IDL_GENTREE (IDL_NS (ns).current)._cur_prefix)
Packit 4a5d52
		g_free (IDL_GENTREE (IDL_NS (ns).current)._cur_prefix);
Packit 4a5d52
Packit 4a5d52
	IDL_GENTREE (IDL_NS (ns).current)._cur_prefix = r;
Packit 4a5d52
Packit 4a5d52
	return TRUE;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
IDL_tree IDL_ns_resolve_this_scope_ident (IDL_ns ns, IDL_tree scope, IDL_tree ident)
Packit 4a5d52
{
Packit 4a5d52
	IDL_tree p, q;
Packit 4a5d52
Packit 4a5d52
	IDL_NS_ASSERTS;
Packit 4a5d52
Packit 4a5d52
	p = scope;
Packit 4a5d52
Packit 4a5d52
	while (p != NULL) {
Packit 4a5d52
		q = IDL_ns_lookup_this_scope (ns, p, ident, NULL);
Packit 4a5d52
		if (q != NULL)
Packit 4a5d52
			return q;
Packit 4a5d52
		p = IDL_NODE_UP (p);
Packit 4a5d52
	}
Packit 4a5d52
Packit 4a5d52
	return p;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
IDL_tree IDL_ns_resolve_ident (IDL_ns ns, IDL_tree ident)
Packit 4a5d52
{
Packit 4a5d52
	return IDL_ns_resolve_this_scope_ident (ns, IDL_NS (ns).current, ident);
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
IDL_tree IDL_ns_lookup_this_scope (IDL_ns ns, IDL_tree scope, IDL_tree ident, gboolean *conflict)
Packit 4a5d52
{
Packit 4a5d52
	IDL_tree p, q;
Packit 4a5d52
Packit 4a5d52
	IDL_NS_ASSERTS;
Packit 4a5d52
Packit 4a5d52
	if (conflict)
Packit 4a5d52
		*conflict = TRUE;
Packit 4a5d52
Packit 4a5d52
	if (scope == NULL)
Packit 4a5d52
		return NULL;
Packit 4a5d52
Packit 4a5d52
	assert (IDL_NODE_TYPE (scope) == IDLN_GENTREE);
Packit 4a5d52
Packit 4a5d52
	/* Search this namespace */
Packit 4a5d52
	if (g_hash_table_lookup_extended (
Packit 4a5d52
		IDL_GENTREE (scope).children, ident, NULL, (gpointer)&p)) {
Packit 4a5d52
		assert (IDL_GENTREE (p).data != NULL);
Packit 4a5d52
		assert (IDL_NODE_TYPE (IDL_GENTREE (p).data) == IDLN_IDENT);
Packit 4a5d52
		return p;
Packit 4a5d52
	}
Packit 4a5d52
Packit 4a5d52
	/* If there are inherited namespaces, look in those before giving up */
Packit 4a5d52
	q = IDL_GENTREE (scope)._import;
Packit 4a5d52
	if (!q)
Packit 4a5d52
		return NULL;
Packit 4a5d52
Packit 4a5d52
	assert (IDL_NODE_TYPE (q) == IDLN_LIST);
Packit 4a5d52
	for (; q != NULL; q = IDL_LIST (q).next) {
Packit 4a5d52
		IDL_tree r;
Packit 4a5d52
Packit 4a5d52
		assert (IDL_LIST (q).data != NULL);
Packit 4a5d52
		assert (IDL_NODE_TYPE (IDL_LIST (q).data) == IDLN_IDENT);
Packit 4a5d52
		assert (IDL_IDENT_TO_NS (IDL_LIST (q).data) != NULL);
Packit 4a5d52
		assert (IDL_NODE_TYPE (IDL_IDENT_TO_NS (IDL_LIST (q).data)) == IDLN_GENTREE);
Packit 4a5d52
Packit 4a5d52
		/* Search imported namespace scope q */
Packit 4a5d52
		if (g_hash_table_lookup_extended (
Packit 4a5d52
			IDL_GENTREE (IDL_IDENT_TO_NS (IDL_LIST (q).data)).children,
Packit 4a5d52
			ident, NULL, (gpointer)&p)) {
Packit 4a5d52
			assert (IDL_GENTREE (p).data != NULL);
Packit 4a5d52
			assert (IDL_NODE_TYPE (IDL_GENTREE (p).data) == IDLN_IDENT);
Packit 4a5d52
Packit 4a5d52
			/* This needs more work, it won't do full ambiguity detection */
Packit 4a5d52
			if (conflict && !is_inheritance_conflict (p))
Packit 4a5d52
				*conflict = FALSE;
Packit 4a5d52
Packit 4a5d52
			return p;
Packit 4a5d52
		}
Packit 4a5d52
Packit 4a5d52
		/* Search up one level */
Packit 4a5d52
		if (IDL_NODE_TYPE (IDL_NODE_UP (IDL_LIST (q).data)) == IDLN_INTERFACE &&
Packit 4a5d52
		    (r = IDL_ns_lookup_this_scope (
Packit 4a5d52
			    ns, IDL_IDENT_TO_NS (IDL_LIST (q).data), ident, conflict)))
Packit 4a5d52
			return r;
Packit 4a5d52
	}
Packit 4a5d52
Packit 4a5d52
	return NULL;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
IDL_tree IDL_ns_lookup_cur_scope (IDL_ns ns, IDL_tree ident, gboolean *conflict)
Packit 4a5d52
{
Packit 4a5d52
	return IDL_ns_lookup_this_scope (ns, IDL_NS (ns).current, ident, conflict);
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
IDL_tree IDL_ns_place_new (IDL_ns ns, IDL_tree ident)
Packit 4a5d52
{
Packit 4a5d52
	IDL_tree p, up_save;
Packit 4a5d52
	gboolean does_conflict;
Packit 4a5d52
Packit 4a5d52
	IDL_NS_ASSERTS;
Packit 4a5d52
Packit 4a5d52
	p = IDL_ns_lookup_cur_scope (ns, ident, &does_conflict);
Packit 4a5d52
	if (p != NULL && does_conflict)
Packit 4a5d52
		return NULL;
Packit 4a5d52
Packit 4a5d52
	/* The namespace tree is separate from the primary parse tree,
Packit 4a5d52
	   so keep the primary tree node's parent the same */
Packit 4a5d52
	up_save = IDL_NODE_UP (ident);
Packit 4a5d52
	p = IDL_gentree_chain_child (IDL_NS (ns).current, ident);
Packit 4a5d52
	IDL_NODE_UP (ident) = up_save;
Packit 4a5d52
Packit 4a5d52
	if (p == NULL)
Packit 4a5d52
		return NULL;
Packit 4a5d52
Packit 4a5d52
	assert (IDL_NODE_TYPE (p) == IDLN_GENTREE);
Packit 4a5d52
Packit 4a5d52
	IDL_IDENT_TO_NS (ident) = p;
Packit 4a5d52
Packit 4a5d52
	assert (IDL_NODE_UP (IDL_IDENT_TO_NS (ident)) == IDL_NS (ns).current);
Packit 4a5d52
Packit 4a5d52
	/* Generate default repository ID */
Packit 4a5d52
	IDL_IDENT_REPO_ID (ident) =
Packit 4a5d52
		IDL_ns_ident_make_repo_id (__IDL_root_ns, p, NULL, NULL, NULL);
Packit 4a5d52
Packit 4a5d52
	return p;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
void IDL_ns_push_scope (IDL_ns ns, IDL_tree ns_ident)
Packit 4a5d52
{
Packit 4a5d52
	IDL_NS_ASSERTS;
Packit 4a5d52
Packit 4a5d52
	assert (IDL_NODE_TYPE (ns_ident) == IDLN_GENTREE);
Packit 4a5d52
	assert (IDL_NODE_TYPE (IDL_GENTREE (ns_ident).data) == IDLN_IDENT);
Packit 4a5d52
	assert (IDL_NS (ns).current == IDL_NODE_UP (ns_ident));
Packit 4a5d52
Packit 4a5d52
	IDL_NS (ns).current = ns_ident;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
void IDL_ns_pop_scope (IDL_ns ns)
Packit 4a5d52
{
Packit 4a5d52
	IDL_NS_ASSERTS;
Packit 4a5d52
Packit 4a5d52
	if (IDL_NODE_UP (IDL_NS (ns).current) != NULL)
Packit 4a5d52
		IDL_NS (ns).current = IDL_NODE_UP (IDL_NS (ns).current);
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
IDL_tree IDL_ns_qualified_ident_new (IDL_tree nsid)
Packit 4a5d52
{
Packit 4a5d52
	IDL_tree l = NULL, item;
Packit 4a5d52
Packit 4a5d52
	while (nsid != NULL) {
Packit 4a5d52
		if (IDL_GENTREE (nsid).data == NULL) {
Packit 4a5d52
			nsid = IDL_NODE_UP (nsid);
Packit 4a5d52
			continue;
Packit 4a5d52
		}
Packit 4a5d52
		assert (IDL_GENTREE (nsid).data != NULL);
Packit 4a5d52
		assert (IDL_NODE_TYPE (IDL_GENTREE (nsid).data) == IDLN_IDENT);
Packit 4a5d52
		item = IDL_list_new (IDL_ident_new (
Packit 4a5d52
			g_strdup (IDL_IDENT (IDL_GENTREE (nsid).data).str)));
Packit 4a5d52
		l = IDL_list_concat (item, l);
Packit 4a5d52
		nsid = IDL_NODE_UP (nsid);
Packit 4a5d52
	}
Packit 4a5d52
Packit 4a5d52
	return l;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
gchar *IDL_ns_ident_to_qstring (IDL_tree ns_ident, const char *join, int levels)
Packit 4a5d52
{
Packit 4a5d52
	IDL_tree l, q;
Packit 4a5d52
	int len, joinlen;
Packit 4a5d52
	char *s;
Packit 4a5d52
	int count = 0, start_level;
Packit 4a5d52
Packit 4a5d52
	if (levels < 0 || levels > 64)
Packit 4a5d52
		return NULL;
Packit 4a5d52
Packit 4a5d52
	if (ns_ident == NULL)
Packit 4a5d52
		return NULL;
Packit 4a5d52
Packit 4a5d52
	if (IDL_NODE_TYPE (ns_ident) == IDLN_IDENT)
Packit 4a5d52
		ns_ident = IDL_IDENT_TO_NS (ns_ident);
Packit 4a5d52
Packit 4a5d52
	assert (IDL_NODE_TYPE (ns_ident) == IDLN_GENTREE);
Packit 4a5d52
Packit 4a5d52
	l = IDL_ns_qualified_ident_new (ns_ident);
Packit 4a5d52
Packit 4a5d52
	if (l == NULL)
Packit 4a5d52
		return NULL;
Packit 4a5d52
Packit 4a5d52
	if (join == NULL)
Packit 4a5d52
		join = "";
Packit 4a5d52
Packit 4a5d52
	joinlen = strlen (join);
Packit 4a5d52
	for (len = 0, q = l; q != NULL; q = IDL_LIST (q).next) {
Packit 4a5d52
		IDL_tree i = IDL_LIST (q).data;
Packit 4a5d52
		assert (IDL_NODE_TYPE (q) == IDLN_LIST);
Packit 4a5d52
		assert (IDL_NODE_TYPE (i) == IDLN_IDENT);
Packit 4a5d52
		if (IDL_IDENT (i).str != NULL)
Packit 4a5d52
			len += strlen (IDL_IDENT (i).str) + joinlen;
Packit 4a5d52
		++count;
Packit 4a5d52
	}
Packit 4a5d52
Packit 4a5d52
	if (levels == 0)
Packit 4a5d52
		start_level = 0;
Packit 4a5d52
	else
Packit 4a5d52
		start_level = count - levels;
Packit 4a5d52
Packit 4a5d52
	assert (start_level >= 0 && start_level < count);
Packit 4a5d52
Packit 4a5d52
	s = g_malloc (len + 1);
Packit 4a5d52
	if (s == NULL) {
Packit 4a5d52
		IDL_tree_free (l);
Packit 4a5d52
		return NULL;
Packit 4a5d52
	}
Packit 4a5d52
	s[0] = '\0';
Packit 4a5d52
	for (q = l; q != NULL; q = IDL_LIST (q).next) {
Packit 4a5d52
		IDL_tree i = IDL_LIST (q).data;
Packit 4a5d52
		if (start_level > 0) {
Packit 4a5d52
			--start_level;
Packit 4a5d52
			continue;
Packit 4a5d52
		}
Packit 4a5d52
		if (s[0] != '\0')
Packit 4a5d52
			strcat (s, join);
Packit 4a5d52
		strcat (s, IDL_IDENT (i).str);
Packit 4a5d52
	}
Packit 4a5d52
Packit 4a5d52
	IDL_tree_free (l);
Packit 4a5d52
Packit 4a5d52
	return s;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
int IDL_ns_scope_levels_from_here (IDL_ns ns, IDL_tree ident, IDL_tree parent)
Packit 4a5d52
{
Packit 4a5d52
	IDL_tree p, scope_here, scope_ident;
Packit 4a5d52
	int levels;
Packit 4a5d52
Packit 4a5d52
	g_return_val_if_fail (ns != NULL, 1);
Packit 4a5d52
	g_return_val_if_fail (ident != NULL, 1);
Packit 4a5d52
Packit 4a5d52
	while (parent && !IDL_NODE_IS_SCOPED (parent))
Packit 4a5d52
		parent = IDL_NODE_UP (parent);
Packit 4a5d52
Packit 4a5d52
	if (parent == NULL)
Packit 4a5d52
		return 1;
Packit 4a5d52
Packit 4a5d52
	if ((scope_here = IDL_tree_get_scope (parent)) == NULL ||
Packit 4a5d52
	    (scope_ident = IDL_tree_get_scope (ident)) == NULL)
Packit 4a5d52
		return 1;
Packit 4a5d52
Packit 4a5d52
	assert (IDL_NODE_TYPE (scope_here) == IDLN_GENTREE);
Packit 4a5d52
	assert (IDL_NODE_TYPE (scope_ident) == IDLN_GENTREE);
Packit 4a5d52
Packit 4a5d52
	for (levels = 1; scope_ident;
Packit 4a5d52
	     ++levels, scope_ident = IDL_NODE_UP (scope_ident)) {
Packit 4a5d52
		p = IDL_ns_resolve_this_scope_ident (
Packit 4a5d52
			ns, scope_here, IDL_GENTREE (scope_ident).data);
Packit 4a5d52
		if (p == scope_ident)
Packit 4a5d52
			return levels;
Packit 4a5d52
	}
Packit 4a5d52
Packit 4a5d52
	return 1;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
/* If insertion was made, return true, else there was a collision */
Packit 4a5d52
static gboolean heap_insert_ident (IDL_tree interface_ident, GTree *heap, IDL_tree any)
Packit 4a5d52
{
Packit 4a5d52
	IDL_tree p;
Packit 4a5d52
Packit 4a5d52
	assert (any != NULL);
Packit 4a5d52
	assert (heap != NULL);
Packit 4a5d52
Packit 4a5d52
	if ((p = g_tree_lookup (heap, any))) {
Packit 4a5d52
		char *newi;
Packit 4a5d52
		char *i1, *i2;
Packit 4a5d52
		char *what1 = "identifier", *what2 = what1;
Packit 4a5d52
		char *who1, *who2;
Packit 4a5d52
		IDL_tree q;
Packit 4a5d52
Packit 4a5d52
		assert (IDL_NODE_TYPE (p) == IDLN_IDENT);
Packit 4a5d52
Packit 4a5d52
		newi = IDL_ns_ident_to_qstring (IDL_IDENT_TO_NS (interface_ident), "::", 0);
Packit 4a5d52
		i1 = IDL_ns_ident_to_qstring (IDL_IDENT_TO_NS (p), "::", 0);
Packit 4a5d52
		i2 = IDL_ns_ident_to_qstring (IDL_IDENT_TO_NS (any), "::", 0);
Packit 4a5d52
Packit 4a5d52
		q = p;
Packit 4a5d52
		while (q && (IDL_NODE_TYPE (q) == IDLN_IDENT || IDL_NODE_TYPE (q) == IDLN_LIST))
Packit 4a5d52
			q = IDL_NODE_UP (q);
Packit 4a5d52
		assert (q != NULL);
Packit 4a5d52
		IDL_tree_get_node_info (q, &what1, &who1);
Packit 4a5d52
Packit 4a5d52
		q = any;
Packit 4a5d52
		while (q && (IDL_NODE_TYPE (q) == IDLN_IDENT || IDL_NODE_TYPE (q) == IDLN_LIST))
Packit 4a5d52
			q = IDL_NODE_UP (q);
Packit 4a5d52
		assert (q != NULL);
Packit 4a5d52
		IDL_tree_get_node_info (q, &what2, &who2);
Packit 4a5d52
Packit 4a5d52
		yyerrorv ("Ambiguous inheritance in interface `%s' from %s `%s' and %s `%s'",
Packit 4a5d52
			  newi, what1, i1, what2, i2);
Packit 4a5d52
		IDL_tree_error (p, "%s `%s' conflicts with", what1, i1);
Packit 4a5d52
		IDL_tree_error (any, "%s `%s'", what2, i2);
Packit 4a5d52
Packit 4a5d52
		g_free (newi); g_free (i1); g_free (i2);
Packit 4a5d52
Packit 4a5d52
		return FALSE;
Packit 4a5d52
	}
Packit 4a5d52
Packit 4a5d52
	g_tree_insert (heap, any, any);
Packit 4a5d52
Packit 4a5d52
	return TRUE;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
static int is_visited_interface (GHashTable *visited_interfaces, IDL_tree scope)
Packit 4a5d52
{
Packit 4a5d52
	assert (scope != NULL);
Packit 4a5d52
	assert (IDL_NODE_TYPE (scope) == IDLN_GENTREE);
Packit 4a5d52
	/* If already visited, do not visit again */
Packit 4a5d52
	return g_hash_table_lookup_extended (visited_interfaces, scope, NULL, NULL);
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
static void mark_visited_interface (GHashTable *visited_interfaces, IDL_tree scope)
Packit 4a5d52
{
Packit 4a5d52
	assert (scope != NULL);
Packit 4a5d52
	assert (IDL_NODE_TYPE (scope) == IDLN_GENTREE);
Packit 4a5d52
	g_hash_table_insert (visited_interfaces, scope, scope);
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
static int is_inheritance_conflict (IDL_tree p)
Packit 4a5d52
{
Packit 4a5d52
	if (IDL_GENTREE (p).data == NULL)
Packit 4a5d52
		return FALSE;
Packit 4a5d52
Packit 4a5d52
	assert (IDL_NODE_TYPE (IDL_GENTREE (p).data) == IDLN_IDENT);
Packit 4a5d52
Packit 4a5d52
	if (IDL_NODE_UP (IDL_GENTREE (p).data) == NULL)
Packit 4a5d52
		return FALSE;
Packit 4a5d52
Packit 4a5d52
	if (!(IDL_NODE_TYPE (IDL_NODE_UP (IDL_GENTREE (p).data)) == IDLN_OP_DCL ||
Packit 4a5d52
	      (IDL_NODE_UP (IDL_GENTREE (p).data) &&
Packit 4a5d52
	       IDL_NODE_TYPE (IDL_NODE_UP (IDL_NODE_UP (IDL_GENTREE (p).data))) == IDLN_ATTR_DCL)))
Packit 4a5d52
		return FALSE;
Packit 4a5d52
Packit 4a5d52
	return TRUE;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
typedef struct {
Packit 4a5d52
	IDL_tree interface_ident;
Packit 4a5d52
	GTree *ident_heap;
Packit 4a5d52
	int insert_conflict;
Packit 4a5d52
} InsertHeapData;
Packit 4a5d52
Packit 4a5d52
static void insert_heap_cb (IDL_tree ident, IDL_tree p, InsertHeapData *data)
Packit 4a5d52
{
Packit 4a5d52
	if (!is_inheritance_conflict (p))
Packit 4a5d52
		return;
Packit 4a5d52
Packit 4a5d52
	if (!heap_insert_ident (
Packit 4a5d52
		data->interface_ident, data->ident_heap, IDL_GENTREE (p).data))
Packit 4a5d52
		data->insert_conflict = 1;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
/* Return true if adds went okay */
Packit 4a5d52
static int IDL_ns_load_idents_to_tables (IDL_tree interface_ident, IDL_tree ident_scope,
Packit 4a5d52
					 GTree *ident_heap, GHashTable *visited_interfaces)
Packit 4a5d52
{
Packit 4a5d52
	IDL_tree q, scope;
Packit 4a5d52
	InsertHeapData data;
Packit 4a5d52
Packit 4a5d52
	assert (ident_scope != NULL);
Packit 4a5d52
	assert (IDL_NODE_TYPE (ident_scope) == IDLN_IDENT);
Packit 4a5d52
Packit 4a5d52
	scope = IDL_IDENT_TO_NS (ident_scope);
Packit 4a5d52
Packit 4a5d52
	if (!scope)
Packit 4a5d52
		return TRUE;
Packit 4a5d52
Packit 4a5d52
	assert (IDL_NODE_TYPE (scope) == IDLN_GENTREE);
Packit 4a5d52
	assert (IDL_GENTREE (scope).data != NULL);
Packit 4a5d52
	assert (IDL_NODE_TYPE (IDL_GENTREE (scope).data) == IDLN_IDENT);
Packit 4a5d52
	assert (IDL_NODE_UP (IDL_GENTREE (scope).data) != NULL);
Packit 4a5d52
	assert (IDL_NODE_TYPE (IDL_NODE_UP (IDL_GENTREE (scope).data)) == IDLN_INTERFACE);
Packit 4a5d52
Packit 4a5d52
	if (is_visited_interface (visited_interfaces, scope))
Packit 4a5d52
		return TRUE;
Packit 4a5d52
Packit 4a5d52
	/* Search this namespace */
Packit 4a5d52
	data.interface_ident = interface_ident;
Packit 4a5d52
	data.ident_heap = ident_heap;
Packit 4a5d52
	data.insert_conflict = 0;
Packit 4a5d52
	g_hash_table_foreach (IDL_GENTREE (scope).children, (GHFunc)insert_heap_cb, &data);
Packit 4a5d52
Packit 4a5d52
	/* If there are inherited namespaces, look in those before giving up */
Packit 4a5d52
	q = IDL_GENTREE (scope)._import;
Packit 4a5d52
	if (!q)
Packit 4a5d52
		data.insert_conflict = 0;
Packit 4a5d52
	else
Packit 4a5d52
		assert (IDL_NODE_TYPE (q) == IDLN_LIST);
Packit 4a5d52
Packit 4a5d52
	/* Add inherited namespace identifiers into heap */
Packit 4a5d52
	for (; q != NULL; q = IDL_LIST (q).next) {
Packit 4a5d52
		int r;
Packit 4a5d52
Packit 4a5d52
		assert (IDL_LIST (q).data != NULL);
Packit 4a5d52
		assert (IDL_NODE_TYPE (IDL_LIST (q).data) == IDLN_IDENT);
Packit 4a5d52
		assert (IDL_IDENT_TO_NS (IDL_LIST (q).data) != NULL);
Packit 4a5d52
		assert (IDL_NODE_TYPE (IDL_IDENT_TO_NS (IDL_LIST (q).data)) == IDLN_GENTREE);
Packit 4a5d52
		assert (IDL_NODE_TYPE (IDL_NODE_UP (IDL_LIST (q).data)) == IDLN_INTERFACE);
Packit 4a5d52
Packit 4a5d52
		if (!(r = IDL_ns_load_idents_to_tables (interface_ident, IDL_LIST (q).data,
Packit 4a5d52
							ident_heap, visited_interfaces)))
Packit 4a5d52
			data.insert_conflict = 1;
Packit 4a5d52
	}
Packit 4a5d52
Packit 4a5d52
	mark_visited_interface (visited_interfaces, scope);
Packit 4a5d52
Packit 4a5d52
	return data.insert_conflict == 0;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
int IDL_ns_check_for_ambiguous_inheritance (IDL_tree interface_ident, IDL_tree p)
Packit 4a5d52
{
Packit 4a5d52
	/* We use a sorted heap to check for namespace collisions,
Packit 4a5d52
	   since we must do case-insensitive collision checks.
Packit 4a5d52
	   visited_interfaces is a hash of visited interface nodes, so
Packit 4a5d52
	   we only visit common ancestors once. */
Packit 4a5d52
	GTree *ident_heap;
Packit 4a5d52
	GHashTable *visited_interfaces;
Packit 4a5d52
	int is_ambiguous = 0;
Packit 4a5d52
Packit 4a5d52
	if (!p)
Packit 4a5d52
		return 0;
Packit 4a5d52
Packit 4a5d52
	ident_heap = g_tree_new (IDL_ident_cmp);
Packit 4a5d52
	visited_interfaces = g_hash_table_new (g_direct_hash, g_direct_equal);
Packit 4a5d52
Packit 4a5d52
	assert (IDL_NODE_TYPE (p) == IDLN_LIST);
Packit 4a5d52
	for (; p;  p = IDL_LIST (p).next) {
Packit 4a5d52
		if (!IDL_ns_load_idents_to_tables (interface_ident, IDL_LIST (p).data,
Packit 4a5d52
						   ident_heap, visited_interfaces))
Packit 4a5d52
			is_ambiguous = 1;
Packit 4a5d52
	}
Packit 4a5d52
Packit 4a5d52
	g_tree_destroy (ident_heap);
Packit 4a5d52
	g_hash_table_destroy (visited_interfaces);
Packit 4a5d52
Packit 4a5d52
	return is_ambiguous;
Packit 4a5d52
}
Packit 4a5d52
Packit 4a5d52
/*
Packit 4a5d52
 * Local variables:
Packit 4a5d52
 * mode: C
Packit 4a5d52
 * c-basic-offset: 8
Packit 4a5d52
 * tab-width: 8
Packit 4a5d52
 * indent-tabs-mode: t
Packit 4a5d52
 * End:
Packit 4a5d52
 */