;;; -*- mode:lisp;package:user;base:10.;fonts: cptfontb -*- 
;;; $Header: /ct/interp/visible.l,v 1.32 84/12/14 19:24:38 penny Exp $
;;;
;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                            visible.l                             ;;;
;;; Paul Robertson                                  October 18, 1983 ;;;
;;;                                                                  ;;;
;;;       The C*T Ada Interpreters Static Semantic support           ;;;
;;;                                                                  ;;;
;;; This file is part of a proprietary software project.  Source     ;;;
;;; code and documentation describing implementation details are     ;;;
;;; available on a confidential, non-disclosure basis only.  These   ;;;
;;; materials, including this file in particular, are trade secrets  ;;;
;;; of Computer * Thought Corporation.                               ;;;
;;;                                                                  ;;;
;;; (c) Copyright 1982 and 1983,  Computer * Thought Corporation.    ;;;
;;;     All Rights Reserved.                                         ;;;
;;;                                                                  ;;;
;;; Reference materials:                                             ;;;
;;;   Miller, 1982.  The C*T Ada Tutor: Guide to the Implementation. ;;;
;;;   Charniak et al., 198?.  Artificial Intelligence Programming.   ;;;
;;;                                                                  ;;;
;;; The following code assumes familiarity with the above.           ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Ensure presence of needed files. 


(eval-when (compile load eval) (ct_load 'aip))	      ;AIP macros pkg. 

(eval-when (compile load eval) (ct_load 'compat))     ;Franz/LM compat pkg. 

(eval-when (compile load eval) (ct_load 'charmac))

(eval-when (compile load eval) (ct_load 'time))       ;Timing functions. 

(eval-when (compile load eval) (ct_load 'diana))      ; Diana tools.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Compiler Declarations and Global Variables -- 

#+franz (declare (macros t))
(declare (ct_includef 'intrpdcl))		; get the specials
(eval-when (compile load eval) (ct_load 'ferec))	; get the macros etc.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Externally Call-able Functions/Macros -- 

;;; Static semantic code schemas are structured as follows.
;;; Body contains lisp code that returns a piece of diana tree or nil.
;;; The main way of building a diana tree is with the sc_diana functon.
;;; Simple node will consist only of these nodes. sc_diana looks like this...
;;; (sc_diana dn_foo slotname code slotname code slotname code .. .. .. ..)
;;; The above example creates a diana node with the names slots, and calls the
;;; appropriate code to fill the slots. One reason why this function should be
;;; used is that it hides the internal representation of a diana node making
;;; future modifications easy (which would be necessary for say a production
;;; compiler.
;;; The abstract syntax is available for inclusion in  the diana tree or
;;; other in a free variable called *abstract_syntax*. This variable may be
;;; altered by the code for effeciency reasons without intefering with the
;;; parsing process. Syntax nodes that do not have ssemantics code will
;;; produce abstract syntax subtree's. To return a null node have a ssemantic
;;; property that returns nil.
	     
;;; pr_in_block
;;; Parse the syntactic unit as a textually inferior 'block' of the
;;; current block. Block here refers to a block for identifier 
;;; resolution rather than an Ada BLOCK as a syntactic unit.
;;; Two special variables are handled here *bnl* and **current_block**
       ;;;;;;;;;;;
(defun pr_in_block fexpr (syn)
       ;;;;;;;;;;;

   (prog2
     (pushcontext)
     (parserd (first syn))
     (popcontext))
)

       ;;;;;;;;;;;
(defun savecontext()	
       ;;;;;;;;;;;

    (ct_push `(,*bnl* ,*pnl* ,**current_block**) *contextstack*))

       ;;;;;;;;;;
(defun popcontext()		; pop to mother block (must match
       ;;;;;;;;;;

				; pushcontext).
    (let ((b (first (first *contextstack*)))
	  (p (second (first *contextstack*)))
	  (c (third (first *contextstack*))))
      (setq *bnl* b *pnl* p **current_block** c))
    (ct_pop *contextstack*))

 #| This is the good version!
       ;;;;;;;;;;;
(defun pushcontext()		; make a nested block.
       ;;;;;;;;;;;

    (ct_push `(,*bnl* ,*pnl* ,**current_block**) *contextstack*)
    (%= *bnl* (1+ *_*))
    (%= **current_block** (new_block)))

       ;;;;;;;;;;;;;;;
(defun pushproccontext()		; make a nested subprogram
       ;;;;;;;;;;;;;;;

    (ct_push `(,*bnl* ,*pnl* ,**current_block**) *contextstack*)
    (%= *bnl* (1+ *_*))
    (%= *pnl* (1+ *_*))
    (%= **current_block** (new_block)))
|#

       ;;;;;;;;;;;
(defun pushcontext()		; make a nested block.
       ;;;;;;;;;;;

    (ct_push `(,*bnl* ,*pnl* ,**current_block**) *contextstack*)
    (and *bnl* (%= *bnl* (1+ *_*))) ;rubustification .. crock crock
    (%= **current_block** (new_block)))

       ;;;;;;;;;;;;;;;
(defun pushproccontext()		; make a nested subprogram
       ;;;;;;;;;;;;;;;

    (ct_push `(,*bnl* ,*pnl* ,**current_block**) *contextstack*)
    (and *bnl* (%= *bnl* (1+ *_*)))
    (and *pnl* (%= *pnl* (1+ *_*)))
    (%= **current_block** (new_block)))

;; pr_in_proc
;;; Parse the syntactic unit as a textually inferior 'subprogram' of the
;;; current subprogram.
       ;;;;;;;;;;
(defun pr_in_proc fexpr (syn)
       ;;;;;;;;;;

    (let ((*bnl* (1+ (or *bnl* 0)))	; increment the block nesting level
	  (*pnl* (1+ (or *pnl* 0)))	  ; increment the procedure nesting level
	  (**current_block** (or (second syn)(new_block))))	  ; create a new block-id.
      (parserd (first syn)))
)

;;; find_name, finds a matching entry in the symbol table and returns a
;;; pointer to the corresponding object in the diana tree.
;;; like ada_declared but works for names in general ... used ada_declared
;;; as a primitive.
  
       ;;;;;;;;;
(defun find_name(n cls &optional all_p)	; n is a structure containing the object.
       ;;;;;;;;;

  (cond
    ((and (not (diana_nodep n))(eq (car n) 'lex_ident))	  ;if its a trivial name...
     (ada_declared n nil cls all_p))
    (t (ct_selectq (and (diana_nodep n)(diana_nodetype_get n))
		   (dn_selected (let ((etry (diana_get n 'as_designator_char))
				      (bt (extract_basetype
						(diana_get n
							   'as_name))))
				     (cond
				       ((and bt
					     (memq (diana_nodetype_get bt)
					    '(dn_record dn_access)))
					(cond (all_p (list n))
					      (t n)))
				       (t 
					(cond (all_p   (list n))
					      (t n))))))
		   (otherwise (cond ((and all_p (diana_nodep n))
				     (list n))
				    (t n)))))
    )
)

;;; add_name(n c d tp)		; name class definition.
;;; adds the name to the symbol table with the current procedure nesting
;;; level and the specified class and definition.
;;; returns the definition parameter unchanged.
    				; add code to check for multiple defn at the
				; same pnl with the same type.
       ;;;;;;;;
(defun add_name(n c d tp)	; name class definition.
       ;;;;;;;;

  (let ((others (get_id n (la_hash (cadr n))))); other identifiers with the
					  ; same name (or nil).
    (cond (others (rem_id n (la_hash (cadr n)))))
    (put_id 
      n					  ; the name to be matched.
      (la_hash (cadr n))		  ; the hash address.
      (cons
	(la_id n *pnl* la_srcpos d c tp **current_block**); the new identifier.
	others))			  ; other identifiers with the same name.
    (diana_put d tp 'ct_st_type)	  ; save for symbol table reproducibility
    (diana_put d **current_block** 'ct_st_defining_block)
    (diana_put d c 'ct_st_class)
    d					  ; this is usually what is wanted -- saves a
					  ; progn in the code.
    ))

;;; Static semantics code for resolving identifiers in a context
;;; The current context is defined by a special variable *blockcontext*
;;; resolution is achieved in three stages.
;;;	Stage 1. Find all defined names that match
;;;	Stage 2. Extract from the above list, those that are in scope
;;;		 and visible in the current context
;;;	Stage 3. Extract from the stage 2 list, those that have a compatible
;;;		 type.
;;; The resulting list should contain one and only one identifier, this one
;;; is the resolved identifier. Should any of the above three stages
;;; terminate without finding any identifiers then the identifier is
;;; 'undeclared'. If the resulting list contains more than a single
;;; identifier, there is an ambiguity and hence illegal. The occurences
;;; should all be listed to indicate to the user what the ambiguity is
;;; and a tv:cvv could be used to choose one of them and proceed.
;;;
;;; Note: a weaker kind of checking is performed by pr_restrict for the
;;;       purpose of resolving ambiguous parses.

;;; new_block - creates a new block in the current context, sets the
;;;             parent block and specifies zero mixinsn.

	;;;;;;;;;
;(defun new_block()		; makes a new block id in the current
	;;;;;;;;;

;				; context.
;   (let ((nublok (intern (gensym))))	; later we may use a dpl.
;                                        ; (intern for debugging only)
;       (putprop nublok **current_block** 'is_enclosed_by); parent block
;       (putprop nublok nil               'mixins)       ; use clauses.
;       nublok
;   )
;)

       ;;;;;;;;;
(defun new_block()
       ;;;;;;;;;

    (sc_diana dn_ct_contextnode
	      ct_is_enclosed_by **current_block** ; parent block
	      ct_mixin_s        nil	  ; packages mixed in.
	      )
)

;;; walk_env (list from shadows) Filter environment
;;; returns a list of all occurences of list that can be reached by
;;; walking the environment tree from 'from'.

       ;;;;;;;;
(defun walk_env(idlist context)(walk_env_rec idlist context nil))
       ;;;;;;;;

       ;;;;;;;;;;;;
(defun walk_env_rec(idlist context shadows); filter out unreachable or hidden ids
       ;;;;;;;;;;;;
  (cond ((null context) nil)		  ; no idents reachable from here.
	(t (let ((hidden_context (diana_get context 'ct_hidden_context)))
;    (cond (hidden_context (break hc)))
	     
	     (do ((found nil)		  ; idents that matched at this block
		  (notfound nil)	  ; idents yet to be found
		  (candidates idlist (cdr candidates)))	  ; the candidates.
		 ((null candidates)	  ; stop when all candidates been tried.
		  (append
		    found
		    (traverse_context notfound context (append found shadows))))
	       (cond
		 ((and
		    (or
		      #| (eq	
		    hidden_context
		    (la_id%db (car candidates)))|#
		      (eq		  ; this candidate was defined in this block
			context
			(la_id%db (car candidates))))
		    (not_obscured_by (car candidates) shadows))
		  (ct_push (car candidates) found))
		 (t
		  (ct_push (car candidates) notfound)))
	       )))))

       ;;;;;;;;;;;;;;;;;;
(defun walk_env_one_level(idlist context shadows); filter unreachable or hidden ids
       ;;;;;;;;;;;;;;;;;;

    (cond 
      ((null context) nil)		  ; no idents reachable from here.
      (t (do ((found nil)		  ; idents that matched at this block
	      (candidates idlist (cdr candidates)))	  ; the candidates.
	     ((null candidates)		  ; stop when all candidates have been tried.
	      found)
	   (cond
	     ((and
		(eq			  ; this candidate was defined in this block
		  context
		  (la_id%db (car candidates)))
		(not_obscured_by (car candidates) shadows))
	      (ct_push (car candidates) found))
	     )
	   ))))

;;; traverse_context(idlist context shadows)
;;; recursively invokes 'walk_env_rec' for the parent node and then searches
;;; mixins.. Incorporates Ada's rules for hiding overloading and ambiguity.
       ;;;;;;;;;;;;;;;;
(defun traverse_context(idlist context shadows)
       ;;;;;;;;;;;;;;;;

    (cond
      ((null context) nil)
      ((null idlist) nil)		  ; nothing left to search for.
      (t (let ((texenc (walk_env_rec 
			 idlist 
			 (diana_get context 'ct_is_enclosed_by)
			 shadows)))
	   (do ((nuidlst (removeall texenc idlist))
		(nushadows (append shadows texenc))
		(foundlist texenc)
		(mixins (diana_get context 'ct_mixin_s) (cdr mixins)))
	       ((null mixins) foundlist)
	     (let ((mixinsfound
		     (walk_env_one_level
		       nuidlst		  ; idents remaining to be found.
		       (car mixins)	  ; this mixin.
		       nushadows)))
	       (%= nuidlst (removeall mixinsfound *_*))
	       (%= foundlist (append mixinsfound  *_*))))))))

#|
;;; traverse_context(idlist context shadows)
;;; recursively invokes 'walk_env_rec' for the parent node and then searches
;;; mixins.. Incorporates Ada's rules for hiding overloading and ambiguity.
       ;;;;;;;;;;;;;;;;
(defun traverse_context(idlist context shadows)
       ;;;;;;;;;;;;;;;;

    (cond
      ((null idlist) nil)		  ; nothing left to search for.
      (t (let ((texenc (walk_env_rec 
			 idlist 
			 (diana_get context 'ct_is_enclosed_by)
			 shadows)))
	   (do ((nuidlst (removeall texenc idlist))
		(nushadows (append shadows texenc))
		(foundlist texenc)
		(mixins (diana_get context 'ct_mixin_s) (cdr mixins)))
	       ((null mixins) foundlist)
	     (let ((mixinsfound
		     (walk_env_rec
		       nuidlst		  ; idents remaining to be found.
		       (car mixins)	  ; this mixin.
		       nushadows)))
	       (%= nuidlst (removeall mixinsfound *_*))
	       (%= foundlist (append mixinsfound  *_*))))))))
|#
	    
;;; removeall (thesefrom those) 
;;; performs set subtraction. result is a list of those elements of 
;;; 'those' that are not present in 'thesefrom'
       ;;;;;;;;;
(defun removeall(thesefrom those)
       ;;;;;;;;;

    (do ((remaining those)
	 (toremove  thesefrom (cdr toremove)))
	((null toremove) remaining)
      (%= remaining (delq (car toremove) remaining))))

;;; not_obscured_by 
;;; A predicate that decides if an identifier is overloaded or hidden, returns
;;; nil if the identifier is HIDDEN and t if it is either overloaded or 
;;; otherwise visible. Interfaces to the type_compatability code.
       ;;;;;;;;;;;;;;;
(defun not_obscured_by(identifier shadows)
       ;;;;;;;;;;;;;;;

    (do ((shade shadows (cdr shade)))
	((or (null shade)
	     (hides_p identifier (car shade)))
	 (null shade))))		  ; return t if identifier is NOT hidden.
	     

(defun generic_defo_p (stub)
  (cond ((and
	   (= (length stub) 1)
	   (eq (diana_nodetype_get (car stub))
	       'dn_generic_id))
	 t)))
	 
;;; Takes a single argument which is a class name and returns nil if it is
;;; not overloadable.
       ;;;;;;;;;;;;;;
(defun overloadable_p(ic)
       ;;;;;;;;;;;;;;

    (memq ic '(procedure function accept entry task package enumeration_literal)))

       ;;;;;;;
(defun hides_p(id1 id2)
       ;;;;;;;

  (cond
    ((eq (la_id%class id1) 'library_unit) nil)
    ((eq (la_id%class id2) 'library_unit) nil)
    ((overloads_p id1 id2) nil)		  ;if it overloads it cannot hide.
    ((same_name_p id1 id2) t  )		  ;if it doesnt overload but has the same
					  ;name, it hides.
    ))					  ;otherwise it doesnt.

       ;;;;;;;;;;;
(defun same_name_p(id1 id2)
       ;;;;;;;;;;;

  (let ((nid1 (diana_get (la_id%dn id1) 'lx_symrep))
	(nid2 (diana_get (la_id%dn id2) 'lx_symrep)))
;    (break nid1 nid2)
    (equal nid1 nid2)))

;;; Takes two identifier symbol table entries. Returns non-nil if
;;;  id2 overloads id1 and nil if id2 hides id1.
       ;;;;;;;;;;;
(defun overloads_p(id1 id2)
       ;;;;;;;;;;;

    (let ((c1 (la_id%class id1))	; Class of id1
	  (c2 (la_id%class id2))	  ; Class of id2
	  (d1 (la_id%dn    id1))	  ; Definition of id1
	  (d2 (la_id%dn    id2)))	  ; Definition of id2
      (cond
	((and (overloadable_p c1)(overloadable_p c2))
	 (or (neq c1 c2)		  ; overload if different
					  ; classes.
	     (not (same_type_profile_p d1 d2))))  ; overloads if different
					  ; type profile (otherwise
					  ; hides).
	(t nil))))			  ; id2 HIDES id1

;;; Takes two definitions of the same class and returns non-nil if they
;;; have the same type profile
       ;;;;;;;;;;;;;;;;;;;
(defun same_type_profile_p(d1 d2)
       ;;;;;;;;;;;;;;;;;;;

;  (break in-same_type_profile_p) t)
   (or (eq d1 d2)			  ;same node MUST have same profile.
       (ct_selectq
	 (diana_nodetype_get d1)	  ;a different rule for each case.
	 (dn_generic_id
	   (cond ((eq (diana_nodetype_get
			(diana_get d1 'sm_spec))
		      'dn_function)
		  (let ((p1 (let ((s1 (diana_get d1 'sm_spec)))
			      (and s1 (diana_get s1 'as_param_s))))
			(p2 (let ((s2 (diana_get d2 'sm_spec)))
			      (and s2 (diana_get s2 'as_param_s)))))
		    (and (compare_parameter_list_types p1 p2)
			 (same_type_despite_privacy
			   (extract_basetype
			     (let ((s1 (diana_get d1 'sm_spec)))
			       (and s1 (diana_get s1 'as_name_void))))
			   (extract_basetype
			     (let ((s2 (diana_get d2 'sm_spec)))
			       (and s2 (diana_get s2 'as_name_void))))))))
		 ((eq (diana_nodetype_get
			(diana_get d1 'sm_spec))
		      'dn_procedure)
		  (let ((p1 (let ((s1 (diana_get d1 'sm_spec)))
			      (and s1 (diana_get s1 'as_param_s))))
			(p2 (let ((s2 (diana_get d2 'sm_spec)))
			      (and s2 (diana_get s2 'as_param_s)))))
		    (compare_parameter_list_types p1 p2)))
		 (t t)))
	 (dn_proc_id
	   (let ((p1 (let ((s1 (diana_get d1 'sm_spec)))
		       (and s1 (diana_get s1 'as_param_s))))
		 (p2 (let ((s2 (diana_get d2 'sm_spec)))
		       (and s2 (diana_get s2 'as_param_s)))))
	     (compare_parameter_list_types p1 p2)))
	 (dn_function_id
	   (let ((p1 (let ((s1 (diana_get d1 'sm_spec)))
		       (and s1 (diana_get s1 'as_param_s))))
		 (p2 (let ((s2 (diana_get d2 'sm_spec)))
		       (and s2 (diana_get s2 'as_param_s)))))
	     (and (compare_parameter_list_types p1 p2)
		  (same_type_despite_privacy
		    (extract_basetype
		      (let ((s1 (diana_get d1 'sm_spec)))
			(and s1 (diana_get s1 'as_name_void))))
		    (extract_basetype
		      (let ((s2 (diana_get d2 'sm_spec)))
			(and s2 (diana_get s2 'as_name_void))))))))
	 (t t))))			  ;if we dont know assume yes!

;;; compares two formal parameter lists for 'same profile-ness'
;;; returns t if they are compatible nil otherwise.
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun compare_parameter_list_types(p1 p2)
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  (let ((a1 nil)(a2 nil))
    (do ((fpgs1 p1 (cdr fpgs1)))	  ; loop on formal parameter groups of p1.
	((null fpgs1))
      (let ((parl1 (diana_get (first fpgs1) 'as_id_s)))
	(do ((afp1 parl1 (cdr afp1)))
	    ((null afp1))
	  (ct_push
	    (list (diana_nodetype_get (car fpgs1))(diana_get (car fpgs1) 'as_name))
	    a1))))
    (do ((fpgs2 p2 (cdr fpgs2)))	  ; loop on formal parameter groups of p2.
	((null fpgs2))
      (let ((parl2 (diana_get (first fpgs2) 'as_id_s)))
	(do ((afp2 parl2 (cdr afp2)))
	    ((null afp2))
	  (ct_push
	    (list (diana_nodetype_get (car fpgs2))(diana_get (car fpgs2) 'as_name))
	    a2))))			  ; add the parameter to the list.
    ;;now check them one by one.
    (or ;(null a1)
	;(null a2)
	(and (= (length a1)(length a2))	  ;must be the same number of them!
	     (do ((pa1 a1 (cdr pa1))
		  (pa2 a2 (cdr pa2)))	  ;iterate on the args.
		 ((or (null pa1)	  ;running out of params is good.
		      (not (eq (caar pa1)(caar pa2)))	  ;not same mode is bad.
		      (not (same_type_despite_privacy
			     (extract_basetype (cadar pa1))
			       (extract_basetype (cadar pa2)))))
		  (null pa1)))))))

       ;;;;;;;;;;;;;;;;;;;;;;;;;
(defun same_type_despite_privacy (t1 t2)
       ;;;;;;;;;;;;;;;;;;;;;;;;;
  (cond ((and t1
	      (memq (diana_nodetype_get t1) '(dn_l_private_type_id
					  dn_private_type_id)))
	 (setq t1 (diana_get t1 'sm_type_spec))))
  (cond ((and t2
	      (memq (diana_nodetype_get t2) '(dn_l_private_type_id
					  dn_private_type_id)))
	 (setq t2 (diana_get t2 'sm_type_spec))))
  (eq t1 t2))

       ;;;;;;;;;;;;;;;;
(defun add_id_to_symtab(laid)
       ;;;;;;;;;;;;;;;;
#|
    (let* ((nam (la_id%name laid))
	   (defs (ada_declared nam nil nil t)))	  ; all same name entries.
      (setq defs (filter_standard_environment defs))	  ; take only those in
					  ; stdenv
      (cond
	((null defs)
	 (let ((hashval (la_hash (cadr nam))))
	   (let ((others (get_id nam hashval)))
	     (cond (others (rem_id nam hashval)))
	     (put_id
	       nam			  ; The name to be hashed against.
	       hashval			  ; The hash value based on the name.
	       (cons laid others))
	     nil)))
	(t  ;(ct_format terminal-io "linking symbol ~A~%" (implode (cadr nam)))
;		(break in-add_id_to_symtab)
	 (first defs))))
|#

      (let* ((nam (la_id%name laid))
	     (hashval (la_hash (cadr nam)))
	     (others (get_id nam hashval)))
	     ;(cond (others (rem_id nam hashval)))
	(cond ((eq (la_id%class laid) 'library_unit)
	       (cond
		 ((eq (diana_nodetype_get (la_id%dn laid))
		      'dn_package_id)
		  (put_id nam hashval
			  (cons
			    (la_id (la_id%name laid)
				   (la_id%pl laid)
				   (la_id%sfn laid)
				   (la_id%dn laid)
				   'package
				   (la_id%typ laid)
				    **current_block**)
			    others))
		  (setq others (get_id nam hashval))));need to put pkgs in twice
	       
	       (%= (la_id%db laid) **current_block**)
	       ;(break installing_lib_unit)
	       ))
	
	(put_id
	       nam			  ; The name to be hashed against.
	       hashval			  ; The hash value based on the name.
	       (cons laid others))
	     
	     ;(ct_format terminal-io "adding ~A to symtab~%"
	     ;		(implode (cadr nam)) )
	     nil))



;;; takes an id node 'me' and a list of id nodes 'them' and returns the result
;;; of filtering out the id's im them with different type profiles from 'me'
       ;;;;;;;;;;;;;;;;;;;;;;
(defun with_same_type_profile(me them)
       ;;;;;;;;;;;;;;;;;;;;;;
  
  (mapcan
    #'(lambda(him)
	(cond
	  ((eq him me) nil) ;;be careful not to include yourself!
	  ((same_type_profile_p me him) (list him))))
    them))

;;; takes an id node 'me' and a list of id nodes 'them' and returns the result
;;; of filtering out the id's im them with same type profiles as 'me'
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun with_different_type_profile(me them)
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;

  (mapcan
    #'(lambda(him)
	(cond
	  ((same_type_profile_p me him) nil)
	  (t (list him))))
    them))

;;; someday this optional should be made mandatory++
;;; cl is an optional class restriction (nil if no restriction)
;;;  p is a predicate to decide what to do if undeclared.
;;;    if p is t, no error message will be generated.. nil will be returned.
       ;;;;;;;;;;;;
(defun ada_declared (id tp &optional cl all_p); check to see if id is declared as a tp.
       ;;;;;;;;;;;;

    (let ((defs (walk_env_rec 
		  (get_id id (la_hash (cadr id))) **current_block** nil)))
      (%= cl (or cl *class_restriction*)) ;for names!
      (%= defs (cond ((null tp) defs)(t (filter_type tp defs))))
      (%= defs (cond ((null cl) defs)
		     (t
		      (cond
			((symbolp cl)(filter_class cl defs))
			(t (mapcan
			     #'(lambda(c)(filter_class c defs))
			     cl))))))   
      (%= defs (filter_private defs))	  ;filter out visible, if private avail.
;      (%= defs (filter_incarnations defs));temp fix
      (%= defs (filter_same_id defs))	  ;filter out identical identifiers.
      (cond
	(defs 
	 (cond
	   (all_p
	    (mapcar
	      #'(lambda(def)
		  (la_id%dn def))
	      defs)) ;; return all if asked for.
	   ((> (length defs) 1)		  ;(break ambiguous-id)
	    (semgripe 'ambig_id_ref
		      (implode (cadr id)))
	    (la_id%dn (car defs)))			  ;pick the first one.
	   (t (la_id%dn  (car defs)))))
	
	((not all_p)			  ;(break undeclared)
	 (semgripe 'undecl_id (implode (cadr id)))
	 (sc_diana dn_used_name_id
		   lx_symrep id)))))

       ;;;;;;;;;;;;;;;;;;;
(defun name_declared_check (dn)
       ;;;;;;;;;;;;;;;;;;;
  (cond
    ((null dn) nil)
    ((diana_nodep dn)
     (ct_selectq (diana_nodetype_get dn)
		 (dn_used_name_id 
		   (cond
		     ((null (diana_get dn 'sm_defn))
		      (ada_undeclared dn)
		      nil)
		     (t t)))		  ;not declared.
		 ((dn_indexed dn_slice dn_selected dn_attribute_call dn_attribute)
		   (name_declared_check (diana_get dn 'as_name)))
		 ((dn_function_call) t)	  ;++
		 (dn_all (name_declared_check (diana_get dn 'as_name)))
		 ((dn_proc_id dn_function_id dn_package_id dn_generic_id)
		  t)			  ;++
		 (otherwise
		   (break in-name_declared_check)
		   t)))
    (t t)))

       ;;;;;;;;;;;;;;
(defun ada_undeclared (dn)
       ;;;;;;;;;;;;;;
  (semgripe
    'undecl_id (implode (cadr (diana_get dn 'lx_symrep)))))

;;; Extracts entries that contain sm_first's that point to other entries.
       ;;;;;;;;;;;;;;;;;;;
(defun filter_incarnations (list)
       ;;;;;;;;;;;;;;;;;;;

    (mapcan
      (function
	(lambda(id)			  ;An la_id record.
	  (cond
	    ((re_incarnation_p id list) nil)
	    (t (list id)))))
      list))

       ;;;;;;;;;;;;;;
(defun filter_private (list)
       ;;;;;;;;;;;;;;

    (mapcan
      (function
	(lambda(id)			  ;An la_id record.
	  (cond
	    ((visible_brother_p id list) nil)
	    (t (list id)))))
      list))

       ;;;;;;;;;;;;;;
(defun filter_same_id (list)
       ;;;;;;;;;;;;;;

    (mapcon
      (function
	(lambda(id)			  ;An la_id record.
	  (cond
	    ((memb_id (la_id%dn (car id)) (cdr id)) nil)
	    (t (list (car id))))))
      list))

(defun memb_id (id l)
  (cond
    ((null l) nil)
    ((eq id (la_id%dn (car l))) t)
    (t (memb_id id (cdr l)))))

;;; returns T if the first id is a reincarnation of one in lids.
       ;;;;;;;;;;;;;;;;
(defun re_incarnation_p(id lids)
       ;;;;;;;;;;;;;;;;

    (let ((this_id (diana_get (la_id%dn id) 'sm_first))) ;this guy's first.
      (cond
        (this_id			  ;only if he has a first.
	 (do ((ids lids (cdr ids)))
	     ((null ids) nil)
	   (let ((that_id (la_id%dn (car ids))))
	     ;(break  re_incarnation_p)
	     (cond
	       ((eq this_id (la_id%dn id)) nil)
	       ((eq (diana_get (la_id%dn id) 'ct_st_defining_block)
		    (diana_get
		      (diana_get this_id 'ct_st_defining_block)
		      'ct_hidden_context))
		(return nil))		  ;dont jump the gun with hidden contexts.
	       ((eq this_id that_id)(return t)))  ;re_incarnation found!
	     ))))))

;;; returns T if the first id is a reincarnation of one in lids.
       ;;;;;;;;;;;;;;;;;
(defun visible_brother_p(id lids)
       ;;;;;;;;;;;;;;;;;

    (let ((this_id (la_id%dn id))) ;this guy's first.
      (cond
        (this_id			  ;only if he has a first.
	 (do ((ids lids (cdr ids)))
	     ((null ids) nil)
	   (let ((that_id (diana_get (la_id%dn (car ids)) 'sm_first)))
	     (cond
	       ((eq this_id that_id)(return t)))  ;visible_brother found!
	     ))))))

;;; Extracts all entries that are NOT in the standard environment
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun filter_standard_environment (list)	
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;

    (mapcan
      (function
	(lambda(id)			  ; An la_id record.
;	      (break in-filter_standard_environment)
	  (cond 
	    ((eq (diana_get id 'ct_st_defining_block)
		 **standard_env**)
	     (list id))			  ;id IS in the standard environment.
	    (t nil))))
      list))

;;; Extracts those identifiers that are type compatibly with the specified
;;; type.
       ;;;;;;;;;;;
(defun filter_type (type list)	; extract entries with matching type.
       ;;;;;;;;;;;

    (mapcan
      (function
	(lambda(id)			  ; An la_id record.
	  (cond 
	    ((eq type (la_id%typ id)) (list id))
	    (t nil))))
      list))

       ;;;;;;;;;;;;
(defun filter_class (class list); extract entries with matching class.
       ;;;;;;;;;;;;

    (mapcan
      (function
	(lambda(id)			  ; An la_id record.
	  (cond
	    ((null (la_id%class id))     (list id))
	    ((eq class (la_id%class id)) (list id))
	    (t nil))))
      list))

       ;;;;;;;;;;;;;;;;;;;;;;;;;
(defun user_definable_function_p(fn)
       ;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;;speed this up with hashtables later
  ;;;little hackeroo since calles with as not( first as)
  (memq (intern (implode (uplowlist (cadar fn)))
		'user)
		 '(|=| |>| |<| |>=| |<=| |and| |or| |xor| |not|
		       |+| |-| |abs| |*| !/ |rem| |mod| |**| |&|)))

       ;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun filter_non_visible_selected (dnl ddn)
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (cond ((diana_nodep dnl)
	 (visible_selected dnl ddn))
	(t (mapcan #'(lambda (dn)
		       (list (visible_selected dn ddn)))
		   dnl))))

(defun find_list_of_compids (comp)
  (ct_selectq
    (diana_nodetype_get comp)
    (dn_var (copylist (diana_get comp 'as_id_s)))
    (dn_variant_part
      (find_list_of_compids (diana_get comp 'as_variant_s)))
    (dn_variant_s
      (mapcan #'find_list_of_compids
	      (diana_get comp 'as_list)))
    (dn_variant
      (find_list_of_compids (diana_get comp 'as_record)))
    (dn_inner_record
      (mapcan #'find_list_of_compids
	      (diana_get comp 'as_list)))
    (dn_null_comp nil)
    (otherwise
      (cond ((status feature debugging)
	     (break what-we-got-others))))))

(defun create_list_of_comps (rec)
  (let* ((smdisc (diana_get rec 'sm_discriminants))
	 (discs (and smdisc (diana_get smdisc 'as_list)))
	 (disclist (mapcan
		     #'(lambda (disc)
			 (copylist (diana_get disc 'as_id_s)))
		     discs))
	 (comps (diana_get rec 'as_list))
	 (complist (mapcan
		     #'find_list_of_compids
		     comps)))
    (append disclist complist)))

       ;;;;;;;;;;;;;;;
(defun compid_in_rec  (dn rec)
       ;;;;;;;;;;;;;;;
  (cond ((eq (diana_nodetype_get dn)
	     'dn_indexed)
	 (and (compid_in_rec (diana_get dn 'as_name) rec) dn))
	(t
	 (let ((compid (diana_get dn 'sm_defn))
	       (asl (create_list_of_comps rec))
	       )
	   (cond ((memq compid asl) dn)
		 (t (semgripe 'not_legal_component
			      (implode (uplowlist
					 (cadr (diana_get dn 'lx_symrep)))))
		    dn))))))


       ;;;;;;;;;;;;;;;;
(defun visible_selected (dn ddn)
       ;;;;;;;;;;;;;;;;
  (let ((dnbnl (cond ((and
			(eq (diana_nodetype_get dn)
			  'dn_used_name_id)
			(diana_get dn 'sm_defn)
			(eq (diana_nodetype_get
			      (diana_get dn 'sm_defn))
			  'dn_package_id))
		      (1+ (diana_get dn 'ct_bnl)))
		     (t (diana_get dn 'ct_bnl))))
	(bnl (cond ((eq (diana_nodetype_get
			  ddn)
			'dn_package_id)
		    (cond ((and
			     (diana_get ddn 'sm_spec)
			     (diana_get
			     (diana_get ddn 'sm_spec)
			     'ct_generic_membership))
			   (- (diana_get ddn 'ct_bnl) 2))
			  (t 
			   (1- (diana_get ddn 'ct_bnl)))))
		   (t (diana_get ddn 'ct_bnl)))))
    (cond
      ((memq
	 (diana_nodetype_get ddn)
	 '(dn_var_id dn_in_id dn_in_out_id dn_out_id))
       (let ((rec (extract_basetype ddn t)))
	 ;if this is a record check the selected is a compid
	 (cond ((and rec
		     (eq (diana_nodetype_get rec )
		    'dn_record))
		(compid_in_rec dn rec))
	       ((and rec (<  dnbnl (diana_get rec 'ct_bnl))) nil)
	       (t dn))
	 ))
      ((and (extract_basetype ddn t)
	    (eq (diana_nodetype_get (extract_basetype ddn t)) 'dn_access))
       (cond ((visible_selected dn (diana_get
				     (extract_basetype
				       ddn t)
				     'as_constrained))
	      )))
      ((eq (diana_nodetype_get dn) 'dn_function_call)
       (cond ((filter_non_visible_selected
		(or (diana_get
		      (diana_get dn 'as_name)
		      'sm_defn)
		    (diana_get dn 'tp_vfuns))
		ddn)
	      dn)
	     (t (diana_put dn nil 'as_name)
		(diana_put dn nil 'tp_vfuns)
		(dissambiguate_function_reference dn))))
      ((<  dnbnl (1+ bnl)) nil)
      (t dn))))

       ;;;;;;;;;;;;;;;;;;
(defun find_named_context (blk)
       ;;;;;;;;;;;;;;;;;;
  (cond ((and blk
	      (eq (diana_nodetype_get blk) 'dn_block))
	 (let* ((asit (car (diana_get blk 'as_item_s)))
	       (asids (and asit
			   (car (diana_get asit 'as_id_s))))
	       (defblk (and asids
			    (diana_get asids 'ct_st_defining_block))))
	   defblk))))
