/*
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 *
 * Author: Ceriel J.H. Jacobs
 */

/* L O O K U P   R O U T I N E S */

/* $Id$ */

#include 	"parameters.h"
#include	"debug.h"

#include	<em_arith.h>
#include	<em_label.h>
#include	<assert.h>
#include	<stdlib.h>

#include	"lookup.h"
#include	"LLlex.h"
#include	"def.h"
#include	"idf.h"
#include	"scope.h"
#include	"node.h"
#include	"type.h"
#include	"misc.h"

extern int	pass_1;
#ifdef DEBUG
extern char	options[];
#endif

struct def *lookup(register struct idf *id, struct scope *scope, int import, int flags)
{
	/*	Look up a definition of an identifier in scope "scope".
		Make the "def" list self-organizing.
		Return a pointer to its "def" structure if it exists,
		otherwise return 0.
	*/
	register struct def *df, *df1;

	/* Look in the chain of definitions of this "id" for one with scope
	   "scope".
	*/
	for (df = id->id_def, df1 = 0;
	     df && df->df_scope != scope;
	     df1 = df, df = df->df_next) { /* nothing */ }

	if (! df && import && scopeclosed(scope)) {
		for (df = id->id_def, df1 = 0;
		     df && df->df_scope != PervasiveScope;
		     df1 = df, df = df->df_next) { /* nothing */ }
	}

	if (df) {
		/* Found it
		*/
		if (df1) {
			/* Put the definition in front
			*/
			df1->df_next = df->df_next;
			df->df_next = id->id_def;
			id->id_def = df;
		}
		df->df_flags |= flags;
		while (df->df_kind & import) {
			assert(df->imp_def != 0);
			df = df->imp_def;
		}
		DO_DEBUG(options['S'], print("lookup %s, %x\n", id->id_text, df->df_kind));
	}
	return df;
}

struct def *lookfor(register struct node *id, register struct scopelist *vis, int message, int flags)
{
	/*	Look for an identifier in the visibility range started by "vis".
		If it is not defined create a dummy definition and,
		if message is set, give an error message
	*/
	register struct scopelist *sc;
	struct scopelist *sc1 = 0;
	struct def *df;

	for (sc = vis; sc; sc = nextvisible(sc)) {
		df = lookup(id->nd_IDF, sc->sc_scope, D_IMPORTED, flags);
		if (df) {
			if (message && df->df_kind == D_FORWARD) {
				if (! sc1) sc1 = sc;
				while (sc && sc->sc_scope != df->df_scope) {
					sc = enclosing(sc);
				}
				if (sc) continue;
				break;
			}
			if (pass_1 && message) {
				if (sc1) sc = sc1;
				while (vis->sc_scope->sc_level >
				       sc->sc_scope->sc_level ||
				       (sc1 &&
					vis->sc_scope->sc_level >=
					sc->sc_scope->sc_level)) {
					define( id->nd_IDF,
						vis->sc_scope,
						D_INUSE)-> imp_def = df;
					vis = enclosing(vis);
				}
			}
			return df;
		}
	}

	if (message) id_not_declared(id);

	return MkDef(id->nd_IDF, vis->sc_scope, D_ERROR);
}
