;;; -*- mode:lisp;package:user;base:10.;fonts:(cptfontb) -*- ;;; $Header: /ct/interp/dsmacs.l,v 1.82 85/01/24 18:10:40 penny Exp $ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; DS_MACS ;;; ;;; Mark L. Miller and Paul Robertson February 8, 1983 ;;; ;;; ;;; ;;; This file defines a set of macros for defining the dynamic ;;; ;;; semantics functions for each type of Diana node -- these nodes ;;; ;;; should always be defined using the macros provided below. ;;; ;;; ;;; ;;; 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: ;;; ;;; Foderaro and Sklower, The FRANZ LISP Manual, September 1981. ;;; ;;; Weinreb and Moon, LISP MACHINE MANUAL, Symbolics, July 1981. ;;; ;;; Charniak et al., 1980. Artificial Intelligence Programming. ;;; ;;; Miller, 1982. The C*T Ada Tutor: Guide to the Implementation. ;;; ;;; Tartan Labs, 1982. The Diana Reference Manual. ;;; ;;; ==> Should merge on-line Diana manual with this file! ++ ;;; ;;; The following code assumes familiarity with these materials. ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Ensure presence of needed files. (comment Assumes ct_load and some suitable ct_daba are present) (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 'time)) ;Timing functions. (eval-when (compile load eval) (ct_load 'diana)) ;LISP rep of datatype. (eval-when (compile load eval) (ct_load 'ctadadt)) ;get datatype definitions. (eval-when (compile load eval) (ct_load 'ctflav)); ct flavor compatability. (eval-when (compile load eval) (ct_load 'charmac)) ; get #$% and #$~. (eval-when (compile load eval) (ct_load 'ferec)) ; get nodestage code. (eval-when (compile load eval) (ct_load 'sema)) ; get sc_diana macro (eval-when (compile load eval) (ct_load 'cache)) ; the ds caching system. (eval-when (compile load eval) (ct_load 'adabe)) (declare (ct_includef 'intrpdcl)) ; declarations. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Compiler Declarations and Global Variables -- ;Temp kludge till we supply ct_compatibility versions of implode, ;exploden, etc. #+lispm (declare (setq obsolete-function-warning-switch nil)) ;+++ #+franz (declare (macros t)) ;Ports/Streams: (declare (special *listing* ; Interpreter out *errin* ; Error query in *errout* ; Error msg out *userin* ; Ada Prog in *userout* ; Ada Prog out pc stage replay *continuation* ;See DRIVER *activation*)) ;See DRIVER ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Externally Call-able Functions/Macros for Defining Diana Nodetypes ;(diana_get_cheaply 'foo 'fred) (eval-when (compile load eval) (defun diana_get_cheaply macro (l) ;(node indicator) `(break diana_get_cheaply_will_make_you_lose_very_badly)) ; `(get (cdr ,(cadr l)) ,(caddr l) )) ) ;;;;;;;;;;;;;; (defun def_diana_node macro (l) ;;;;;;;;;;;;;; (setq l (cdr l)) `(def_diana ,(car l) ; ,(concat 'diana_node_ (car l)) ,(car l) ,(cadr l) ; Locals list ,(cddr l) ; Body diana_node_def)) ;;;;;;;;;;; #+franz (defun fdefinition (x) (getd x)) ; kludge for now ++ ;;;;;;;;;;; ;;;;;;;;; (defun def_diana macro (l) ;;;;;;;;; (setq l (cdr l)) (let ((sym (first l)) (funnam (second l)) (locals (third l)) (body (fourth l)) (ind (fifth l))) `(progn 'compile (defun ,funnam (pc stage) #+lispm (cond (*debugdriver* (freshline *listing*) (ct_princ '(Visiting ,sym) *listing*) (ct_princ stage *listing*) (freshline *listing*))) (prog (replay) ; (setq replay nil) rerun (ct_selectq stage ,@(build_sem_body locals body)) (cond (replay (setq replay nil) (setq stage (1+ stage)) (setnodestage stage) (go rerun))))) #| (putprop ',sym (fdefinition ',funnam) ;not in franz++ ',ind) |# ))) ;;; Put the locals onto the locals alist associated with this node and ;;; activation record. Note that the alist maps local names onto ;;; a list whose car is the value. This is essential so that ;;; nonlocal variables return nil to assoc and trigger a search of the ;;; ds environment. ;;;;;;;;;;;;;; (defun with_ds_locals (pc locals) ; setup ds locals ;;;;;;;;;;;;;; (let ((ds_ns (assoc (diana_get pc 'ct_id) *nodestages*))) (cond ((null ds_ns) ; no node stage created yet. (setq *nodestages* (cons (nodestage pc 1. (mapcar (function (lambda(ln) (list ln nil))) ;(recycle_cached_var ln pc))) locals)) *nodestages*)) (set-iv adabe_activation *activation* 'nodestages *nodestages*)) (t (%= (nodestagerec%alist ds_ns) ; initialize all ds_locals to nil (append (mapcar (function (lambda(ln) (list ln nil))) ;(recycle_cached_var ln pc))) locals) *_*)))))) ;;; Translates a dynamic semantic function into a selectq, breaking it ;;; up into stages as it proceeds. Supports certain primitive control cues ;;; presently ds_follow and ds_exit. ;;;;;;;;;;;;;; (defun build_sem_body(locals steps) ;;;;;;;;;;;;;; (let ((dslabels nil)) (cond ((and (null steps)(null locals))(%= steps '((ds_exit)))) ; void case (locals (ct_push `(with_ds_locals pc ',locals) steps))) (do ((stages nil) ; accumulate stages here. (curstage 1) ; first stage is 1. (thisstage nil) ; build a stage here. (nextstep steps (cdr nextstep)) ; consider forms one at a time. ) ((null nextstep) ; no more steps left in defn. (cond (thisstage ; dont lose any steps! (ct_push `(,curstage . ,(reverse thisstage)) stages) (%= curstage (1+ *_*)))) (reverse stages) ; the body of the selectq in nice order. ) (cond ; check for end of stage. ((eq (caar nextstep) 'ds_follow) (ct_push `(ds_follow ,(cadar nextstep)) thisstage) (ct_push `(,curstage . ,(reverse thisstage)) stages) (%= curstage (1+ *_*)) (%= thisstage nil)) ; start a new stage. ((eq (caar nextstep) 'ds_call_diana) (ct_push `(ds_call_diana ,(cadar nextstep)) thisstage) (ct_push `(,curstage . ,(reverse thisstage)) stages) (%= curstage (1+ *_*)) (%= thisstage nil)) ; start a new stage. ((memq (caar nextstep) '(ds_exit ds_break)) (ct_push `(,curstage . ,(reverse thisstage)) stages) (%= curstage (1+ *_*)) (%= thisstage nil)) ; start a new stage. ((memq (caar nextstep) '(ds_if ds_goto ds_label)) (ct_push (car nextstep) thisstage) (ct_push `(,curstage . ,(reverse thisstage)) stages) (%= curstage (1+ *_*)) (%= thisstage nil)) (t (ct_push (car nextstep) thisstage)))))) #| ;;;;; (defun ds_if fexpr(l) ;;;;; (let ((condition (first l)) (iftrue (second l)) (iffalse (third l))) (setq replay t) ; onto next stage if I dont override. (cond ((eval condition) (eval iftrue)) (iffalse (eval iffalse))))) |# ;;;;; (defun ds_if macro(l) ;;;;; `(progn (setq replay t) ; onto next stage if I don't override. (cond (,(second l) ,(third l)) (t ,(fourth l))))) ;;; eg. (ds_push 1 #$^fred) vs (ct_push 1 #$^fred) ;;; (ds_pop #$~fred) vs (ct_pop #$~fred) ;;;;;;; (defun ds_push macro(l) ;;;;;;; (selfinsertmacro l (let* ((val (second l)) (nam (third l)) (type (car nam))) (ct_selectq type (ds_get_var `(let ((pair (ds_find_var ,(second nam) ,(third nam)))) (rplaca (cdr pair) (cons ,val (cadr pair))))) (ds_get_moms_var `(let* ((*dynamic_locals_alist* nil) (pair (ds_find_var ,(second nam) (dynamic_mother ,(third nam))))) (rplaca (cdr pair) (cons ,val (cadr pair))))) (otherwise (lose 'ds_ima 'ds_push)))))) ;;;;;; (defun ds_pop macro (l) ;;;;;; (let* ((stack (second l)) (type (car stack))) (ct_selectq type (ds_get_var `(let* ((pair (ds_find_var ,(second stack) ,(third stack))) (res (cadr pair))) (rplaca (cdr pair) (cdadr pair)) (car res))) (ds_get_moms_var `(let* ((*dynamic_locals_alist* nil) (pair (ds_find_var ,(second stack) (dynamic_mother ,(third stack)))) (res (cadr pair))) (rplaca (cdr pair) (cdadr pair)) (car res))) (otherwise (lose 'ds_ima 'ds_pop))))) #| ;;;;;;; (defun ds_goto(labelst) ;;;;;;; (%= stage labelst) ; set the new stage. (setnodestage labelst) ; set stage in nodestage. (setq replay t)) ; back to myself!! |# ;;;;;;; (defun ds_goto macro(l) ;;;;;;; (selfinsertmacro l (let ((labelst (second l))) `(progn (%= stage ,labelst) ; set the new stage. (setnodestage ,labelst) ; set stage in nodestage. (setq replay t))))) ;;;;;;;;;;;; (defun setnodestage(n) ;;;;;;;;;;;; (let ((ns *nodestages*)) (let ((thisnode (assq (diana_get pc 'ct_id) ns))) (cond ((null thisnode) (lose 'be_cfnfp 'setnodestage () '("couldn't find nodestages for pc"))) (t (rplaca (cdr thisnode) n)))))) #| ;;;;;;;; (defun ds_label fexpr(l) ;;;;;;;; (let ((var (first l))) (setq replay t) ; onto next stage immediately. (eval `(%= ,var stage)))) ; record current stage. |# ;;; raise the requested exception, we need to do something with the ;;; description dsc. ;;;;;;;;; (defun ada_raise(exc dsc) ;;;;;;;;; (ct_push dsc *exception_reason*) (ct_push exc *exception_name*) (ds_raise_aux exc)) ;when called directly ;;;;;;;; (defun ds_raise (exc) ;;;;;;;; (ada_raise exc "implicit raise") ) ;;; cause an exception of type 'exc' to be raised. ;;;;;;;; (defun ds_raise_aux(exc) ;;;;;;;; (cond ((not *infrontend*) ;;Before we raise the exception, check to see if there is advise for this ;;exception. If there is, call each advise function and THEN, raise the ;;exception. (let ((advice_fcns (get exc 'ada_advise))) (mapc #'(lambda(af) (funcall af exc nil)) ;call the advice function. advice_fcns)) (let ((handler (find_exception_handler_for exc (cond (*exchandler* (dynamic_mother *exchandler*)) (t pc)) *activation*))) (let((handler_process (find_nodes_process_activation (first handler))) (excnod (sc_diana dn_ct_exception_handler as_stm_s (diana_get (second handler) 'as_stm_s) ct_threadp (list pc) ;preserve dynamic environment. ct_raising exc ;name of the exception. ct_id (gensym) ;so that nodestages work. ct_resume (first handler)))) (cond ((eq *activation* handler_process) (%= *nuactivation* nil) ;inhibit a process switch. (%= *continuation* excnod)) (t (set-iv adabe_activation handler_process 'pc excnod) ;goto handler node. (%= *continuation* nil) ;inhibit a local branch. (%= *nuactivation* handler_process) ;switch to appropriate process. )))) (*throw 'implicit_exception 'implicit_exception)) (t (semwarn ' will_raise_exception exc) (throw '*diana_node_not_static_expression* '*diana_node_not_static_expression*) nil))) ;;;;;;;; (defun ds_label macro(l) ;;;;;;;; `(progn (setq replay t) ; onto next stage if I don't override. (%= ,(second l) stage))) #| ;;;;;;;;;; (defun ds_get_var(n pc) ;;;;;;;;;; (let ((dsv (or (assoc n *dynamic_locals_alist*) ;a local ; (assoc n *dynamic_mother_locals_alist*) ;a local of my mother. ))) (cond (dsv (cadr dsv)) (t (ds_get_var_aux n pc))) )) ;;;;;;;;;;;;;;; (defun ds_get_moms_var(n pc) ;;;;;;;;;;;;;;; (let ((mom (or (nodestagerec%caller (assoc (diana_get pc 'ct_id) *nodestages*)) (car #$%ct_threadp)))) (ds_get_var_aux n mom))) |# ;;;;;;;;;;;;;; (defun ds_get_var_aux(n pc) ; The the value associated with the ds ;;;;;;;;;;;;;; ; variable named n and node pc. (let* ((*activation* (find_nodes_process_activation pc)) (*nodestages* (get-iv adabe_activation *activation* 'nodestages)) (ns (assoc (diana_get pc 'ct_id) *nodestages*)) (value (assoc n (nodestagerec%alist ns)))) ;; value if any associated with n (cond (value ; if it is bound in this environment.. (second value)) ; return the value part of it. (t (let ((mom (or (nodestagerec%caller ns) ; called tree? (car (diana_get pc 'ct_threadp))))); get mother node. (cond ((null mom) (lose 'be_udsv 'ds_get_var_aux () '("Unbound DS variable ~A" n))) (t (ds_get_var_aux n mom)))))))) ; search env for n. ;;;;;;;;;;;;;;;;;;; (defun ds_get_var_pair_aux (n pc) ; The the value associated with the ds ;;;;;;;;;;;;;;;;;;; ; variable named n and node pc. (let* ((*activation* (find_nodes_process_activation pc)) (*nodestages* (get-iv adabe_activation *activation* 'nodestages)) (ns (assoc (diana_get pc 'ct_id) *nodestages*)) (value (assoc n (nodestagerec%alist ns)))) ;; value if any associated with n (cond (value ; if it is bound in this environment.. value) (t (let ((mom (or (nodestagerec%caller ns) ; called tree? (car (diana_get pc 'ct_threadp))))); get mother node. (cond ((null mom) (lose 'be_udsv 'ds_get_var_aux () '("Unbound DS variable ~A" n))) (t #| (cond ((eq (diana_nodetype_get mom) 'dn_labeled) (setq pc mom) (setq mom (or (nodestagerec%caller ns) ; called tree? (car (diana_get pc 'ct_threadp))))))|# (ds_get_var_pair_aux n mom)))))))) ; search env for n. #| ;;;;;;;;;; (defun ds_set_var(n pc v) ;;;;;;;;;; (let ((dsv (or (assoc n *dynamic_locals_alist*) ;a local ;; (assoc n *dynamic_mother_locals_alist*) ))) ;a local of my mother. (cond (dsv (%= (cadr dsv) v)) (t (ds_set_var_aux n pc v))))) ;;;;;;;;;;;;;;; (defun ds_set_moms_var(n pc v) ;;;;;;;;;;;;;;; (let ((mom (or (nodestagerec%caller (assoc (diana_get pc 'ct_id) *nodestages*)) (car #$%ct_threadp)))) (ds_set_var_aux n mom v))) |# ;;;;;;;;;;;;;; (defun ds_set_var_aux(n pc v) ; set version of above. ;;;;;;;;;;;;;; (let* ((*activation* (find_nodes_process_activation pc)) (*nodestages* (get-iv adabe_activation *activation* 'nodestages)) (ns (assoc (diana_get pc 'ct_id) *nodestages*)) (value (assoc n (nodestagerec%alist ns)))) ;; value if any associated with n (cond (value ; if it is bound in this environment.. (%= (cadr value) v)) ; set the value part of it. (t (let ((mom (or (nodestagerec%caller ns) ; called tree? (car (diana_get pc 'ct_threadp))))); get mother node. (cond ((null mom) (lose 'be_udsv 'ds_set_var_aux () '("Undeclared DS variable ~A" n))) (t (ds_set_var_aux n mom v)))))))) ; search env for n. (eval-when (compile load eval) (defprop ds_get_var ds_set_var set_program) ; make it work for %= (defprop ds_get_moms_var ds_set_moms_var set_program)) ;;;follow passes control onto the specified node. If the specified node ;;;turns out to be nil, stage is incremented and the process is repeated ;;;on the same node. This is helpful for embedding follows as well as ;;;reducing the number of dn_void nodes in the diana tree. ;;;;;;;;; (defun ds_follow macro (l) ;;;;;;;;; (selfinsertmacro l (let ((x (second l))) `(cond ((null ,x) (setq replay nil) (setq *continuation* 'as_you_were)) (t (setq replay nil)(setq *continuation* ,x)))))) ;;;Update the variable named name with the value value.++ ; (defun ds_update(name path value) ; (let ((varnam (diana_get name 'lx_symrep)) ; (varpnl (diana_get name 'ct_pnl)) ; (defpnl (diana_get (diana_get name 'sm_defn) 'ct_pnl))) ; (let ((lvslot ; (assoc varnam ; (get-iv adabe_activation *activation* 'locals)))) ; (and lvslot (ct_send (cdr lvslot) 'set_val path value))))) ;;; new winning version that uses jrm's activation record support. ;;;;;;;;; (defun ds_update(name path value) ;;;;;;;;; (let ((lvslot (look_up_ident name))) (or (and lvslot (prog1 t (ct_send (cdr lvslot) 'set_val path value))) (lose 'be_ffv 'ds_update () '("failed to find variable"))))) ;;;;;;; (defun ds_exit macro(l) ;;;;;;; (selfinsertmacro l `(setq replay nil))) ;;;;;;;; (defun ds_break macro(l) ;;;;;;;; (selfinsertmacro l `(setq replay nil))) ;;;;;;;; (defun ds_valof(name) ;;;;;;;; (let ((lvslot (look_up_ident name))) (cond (lvslot (ct_send (cdr lvslot) 'get_val nil)) (t (lose 'ffv 'ds_valof () '("failed to find variable")))))) ;;;;;;; (defun ds_succ(name) ;;;;;;; (let ((lvslot (look_up_ident name))) (or (and lvslot (let ((val (ct_send (cdr lvslot) 'attribute_handler '|succ| nil))) (ct_send (cdr lvslot) 'set_val nil val) val)) (lose 'be_ffv 'ds_succ () '("failed to find variable"))))) ;;;;;;; (defun ds_pred(name) ;;;;;;; (let ((lvslot (look_up_ident name))) (or (and lvslot (let ((val (ct_send (cdr lvslot) 'attribute_handler '|pred| nil))) (ct_send (cdr lvslot) 'set_val nil val) val)) (lose 'be_ffv 'ds_pred () '("failed to find variable"))))) ;;;;;;;;;; (defun ds_undeclare(name) ; create a new object in local environment. ;;;;;;;;;; (set-iv adabe_activation *activation* 'locals (delq (assq name (get-iv adabe_activation *activation* 'locals)) (get-iv adabe_activation *activation* 'locals)))) ;;;;;;;;;; (defun ds_declare(name flav &optional (initializep t)) ; create a new object in local environment. ;;;;;;;;;; (car (set-iv adabe_activation *activation* 'locals (cons (let ((nuobj `(,(diana_get name 'sm_defn) . ,(ct_make_instance flav)))) (ct_send (cdr nuobj) 'set-ada_name (intern (implode (cadr (diana_get name 'lx_symrep))) 'user)) (ct_send (cdr nuobj) 'set-ada_index nil) (cond (initializep (ct_send (cdr nuobj) 'initialize (list (extract_basetype (diana_get name 'sm_defn)) nil nil (diana_get name 'sm_defn))) (ct_send (cdr nuobj) 'set_val nil '*unassigned*))) nuobj) (get-iv adabe_activation *activation* 'locals))))) ;;;;;;;;;;;;;;;;;;; (defun ds_return_to_caller macro (l) ; switch contexts back to mommy. ;;;;;;;;;;;;;;;;;;; (selfinsertmacro l `(%= *nuactivation* (get-iv adabe_activation *activation* 'clink)))) ; mommy's place. ;;;;;;;;;;; (defun ds_resultis macro (l) ;;;;;;;;;;; (selfinsertmacro l `(ct_push ,(second l) #$^res))) ; (let ((value (second l))) ; `(let ((pc (car #$%ct_threadp)) ; bind up mommy's environment. ; (val ,value)) ; value in my environment. ; (ct_push val #$~res))))) ; set DS variable res in mothers env. ; (ds_set_var 'res #$%threadp value)) ;;;;;;;;;;;; (defun ds_resultset macro (l) ;;;;;;;;;;;; (selfinsertmacro l `(%= #$^res ,(second l)))) ; (let ((value (second l))) ; `(let ((pc (car #$%ct_threadp)) ; bind up mommy's environment. ; (val ,value)) ; value in my environment. ; (%= #$~res val))))) ; set DS variable res in mothers env. ;;;;;;;;;;;; (defun ds_returnres macro(l) ;;;;;;;;;;;; (selfinsertmacro l `(let* ((val ,(second l)) (*activation* (get-iv adabe_activation *activation* 'clink)) ; parent process. (*nodestages* (get-iv adabe_activation *activation* 'nodestages)) (pc (get-iv adabe_activation *activation* 'pc)) ; parent node. ) ; value to deliver. (%= #$~funres val)))) ;;; actuals is a list of evaluated actual (normalized) parameters. ;;; formals is a list of formal parameters (as_param_s). ;;; returns an alist of formal name and value. (cf ds_declare). ;;; parameter group refers to the fact that parameters are grouped ;;; by parameter type. ;;;;;;;;;;;;;;;; (defun buildparamlocals (actuals formals) ;;;;;;;;;;;;;;;; (do ((pg formals (cdr pg)) ; iterate on the parameter groups. (parnum 1) (locals nil)) ; collect locals here. ((null pg) locals) (do ((ps (diana_get (car pg) 'as_id_s) (cdr ps)) ; iterate on params. (groupbasetype (basetype (diana_get (car pg) 'as_name))) (grouptype (diana_get (car pg) 'as_name)) (ptype (diana_nodetype_get (car pg)))) ; one of dn_in, dn_out, dn_in_out. ((null ps)) ; no more parameters in this group. (cond ((null actuals) (lose 'be_iap 'buildparamlocals () '("Insufficient actual parameters")))) (let ((nuobj (ct_make_instance ; create local variable. (type_builder groupbasetype) 'ada_name nil 'ada_index nil))) ; (break buildparamlocals) (ct_send nuobj 'initialize (pinitfun groupbasetype grouptype (car ps) (n_th (1- parnum) (reverse #$~pils)))) (ct_send nuobj 'set-ada_name (intern (implode (cadr (diana_get (car ps) 'lx_symrep))) 'user)) (cond ((or (neq ptype 'dn_out) (eq groupbasetype 'array)) (ct_send nuobj 'set_val nil (ct_pop actuals))) (t (ct_pop actuals))) ; initialize (ct_push ; add variable/value pair to locals. `(,(diana_get (car ps) 'sm_defn) . ,nuobj) locals)) (setq parnum (1+ parnum))) )) (defun find_fixed_bits (suggestion) (cond (suggestion suggestion) (t (do ((parms #$~pils (cdr parms))) ((or (car parms) (null parms)) (car parms)))))) ;;;;;;;; (defun pinitfun (gbt gt id con) ;;;;;;;; ; (break pinitfun) (ct_selectq gbt (|record| (list gt con #'pinitrec id)) (record (list gt con #'pinitrec id)) (|array| (list gt nil nil id)) (array (list gt nil nil id)) (|fixed| (list gt (find_fixed_bits con) nil id)) (fixed (list gt (find_fixed_bits con) nil id)) (otherwise (list gt con nil id)))) ;;;;;;;; (defun pinitrec (i) ;;;;;;;; nil) ;;; function to selectively copy back out (and in out) parameters. ;;; Actuals, is a list of unevaluated actual parameters. ;;; Formals, is the list of formal parameters ;;; ar is the activation record containing the variables. ;;;;;;;;;;;;;;;;;;;;;;;; (defun copy_back_out_parameters (actuals formals ar) ;;;;;;;;;;;;;;;;;;;;;;;; (do ((pg formals (cdr pg)) ; iterate on the parameter groups. (written nil)) ((null pg) written) ;nothing to return. (do ((ps (diana_get (car pg) 'as_id_s) (cdr ps)) ; iterate on params. (groupbasetype (basetype (diana_get (car pg) 'as_name))) (ptype (diana_nodetype_get (car pg)))) ; one of dn_in, dn_out, dn_in_out. ((null ps)) ; no more parameters in this group. (cond ((null actuals) (lose 'be_iap 'copy_back_out_parameters () '("Insufficient actual parameters")))) (cond ((eq ptype 'dn_in) (ct_push nil written) (ct_pop actuals)) ;skip in parameters. (t (let ((actual (ct_pop actuals))) ;get actual param. (let ( ;(obj (look_up_ident actual)) ;;find the object. (updated_value (ct_send (cdr (assq (diana_get (car ps) 'sm_defn) (ct_send ar 'locals))) 'get_val nil))) (ct_push updated_value written) (ct_send actual ;(cdr obj) 'set_val nil updated_value)))))))) ;;;;;;;; (defun typemark(ts) ;;;;;;;; (ct_selectq (diana_nodetype_get ts) (dn_used_name_id ; if its a type mark. (typemark (diana_get ts 'sm_defn))) (dn_constrained ;if its constrained. (typemark (diana_get ts 'as_name))) (dn_type_id ts) ;if its a type_id. (dn_derived ts) ;if its a derived type (dn_subtype_id ts) ;if its a type_id. (dn_l_private_type_id ts) (dn_private_type_id ts) (dn_predefined_type nil) (t (lose 'be_cft 'typemark () '("cant find typemark"))) )) ;;;;;;;;;; (defun find_range(dn) ;;;;;;;;;; (ct_selectq (diana_nodetype_get dn) (dn_used_name_id (find_range (diana_get dn 'sm_defn))) (dn_array (diana_get dn 'as_dscrt_range_s)) ((dn_range dn_attribute_call) dn) (dn_integer (find_range (diana_get dn 'as_range))) (dn_derived (find_range (diana_get dn 'as_constrained))) (dn_constrained (find_range (diana_get dn 'as_constraint))) (dn_subtype_id (find_range (diana_get dn 'sm_type_spec))) (dn_type_id (find_range (diana_get dn 'sm_type_spec))) (dn_record nil) (otherwise (lose 'be_cfr 'find_range)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun extract_delta_from_fixed_pt_subtype (dn) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (ct_selectq (diana_nodetype_get dn) (dn_constrained (extract_delta_from_fixed_pt_subtype (diana_get dn 'as_name))) (dn_type_id (extract_delta_from_fixed_pt_subtype (diana_get dn 'sm_type_spec))) (dn_subtype_id (extract_delta_from_fixed_pt_subtype (diana_get dn 'sm_type_spec))) (dn_fixed (be_static_eval (diana_get dn 'as_exp))) (dn_used_name_id (extract_delta_from_fixed_pt_subtype (diana_get dn 'sm_defn))) (dn_var_id (extract_delta_from_fixed_pt_subtype (diana_get dn 'sm_obj_type))) (otherwise (lose 'be_bft 'extract_delta_from_fixed_pt_subtype )))) ;;; basetype should be called basekind. It returns the 'kind' of datatype ;;; ie: array record float fixed etc. ;;;;;;;; (defun basetype(ts) ;;;;;;;; (cond ((eq ts *universal_fixed*) 'fixed) (t (ct_selectq (diana_nodetype_get ts) (dn_used_name_id ; if its a type mark. (basetype (diana_get ts 'sm_defn))) (dn_array ; if its an array type. 'array) (dn_access ; if its an access type. 'access) (dn_slice ; if its an array type. 'array) (dn_record ; if its an record type. 'record) (dn_integer 'integer) (dn_float 'float) (dn_fixed 'fixed) (dn_task_spec 'task) (dn_predefined_type ; if its a predefined type. (intern (implode (cadr (diana_get ts 'lx_symrep))) 'user)) (dn_enum_literal_s 'enumeration) ; if its an enumeration type. (dn_constrained ;if its constrained. (basetype (diana_get ts 'as_name))) (dn_selected (basetype (diana_get ts 'as_designator_char))) (dn_type_id ;if its a type_id. (basetype (diana_get ts 'sm_type_spec))) (dn_derived ;if its a derived type (basetype (diana_get ts 'as_constrained))) (dn_subtype_id ;if its a type_id. (basetype (diana_get ts 'sm_type_spec))) (dn_l_private_type_id (basetype (diana_get ts 'sm_type_spec))) (dn_private_type_id (basetype (diana_get ts 'sm_type_spec))) (dn_var_id (basetype (diana_get ts 'sm_obj_type))) ((dn_formal_dscrt dn_formal_integer dn_formal_float dn_formal_fixed) nil) (t (lose 'be_cft 'basetype () '("cant find type"))) )))) #| (cond ((eq (car ts) 'dn_used_name_id) ; if its a type mark. (basetype (diana_get ts 'sm_defn))) ((eq (car ts) 'dn_array) ; if its an array type. 'array) ((eq (car ts) 'dn_slice) ; if its an array type. 'array) ((eq (car ts) 'dn_record) ; if its an record type. 'record) ((eq (car ts) 'dn_predefined_type) ; if its a predefined type. (intern (implode (cadr (diana_get ts 'lx_symrep))) 'user)) ((eq (car ts) 'dn_enum_literal_s) 'enumeration) ((eq (car ts) 'dn_constrained) ;if its constrained. (basetype (diana_get ts 'as_name))) ((eq (car ts) 'dn_type_id) ;if its a type_id. (basetype (diana_get ts 'sm_type_spec))) ((eq (car ts) 'dn_subtype_id) ;if its a type_id. (basetype (diana_get ts 'sm_type_spec))) (t (lose 'be_cft 'basetype () '("cant find type"))) ) |# ;;; finds base type from a type spec. ;;;;;;;;;;;; (defun ds_find_type(ts) ;;;;;;;;;;;; (%= #$~basetype (basetype ts))) ;;;;;;;;;;;;;;;;;;;;;; (defun ds_find_base_type_spec(ts) ;;;;;;;;;;;;;;;;;;;;;; (cond ((null ts) nil) (t (ct_selectq (diana_nodetype_get ts) (dn_used_name_id ; if its a type mark. (ds_find_base_type_spec (diana_get ts 'sm_defn))) (dn_array ts) ; if its an array type. (dn_access ts) ; if its an access type. (dn_record (dscrmt_record ;a discriminant record. nil ts (ds_find_dscrmt_vars ts))) (dn_integer (ds_find_base_type_spec (diana_get ts 'as_range))) (dn_float ts);(ds_find_base_type_spec (diana_get ts 'as_range_void))) (dn_private nil) (dn_fixed ts) (dn_task_spec nil) (dn_index nil) (dn_range ts) (dn_var_id (ds_find_base_type_spec (diana_get ts 'sm_obj_type))) (dn_predefined_type nil) (dn_enum_literal_s ts) ; if its an enumeration type. (dn_constrained ;if its constrained. (cond ((or (null (diana_get ts 'as_constraint)) (eq (diana_nodetype_get (diana_get ts 'as_constraint)) 'dn_void)) (ds_find_base_type_spec (diana_get ts 'as_name))) ((eq (diana_nodetype_get (diana_get ts 'as_constraint)) 'dn_dscrmt_aggregate) (dscrmt_record ;a discriminant record. (diana_get ts 'as_constraint) (let ((rts (ds_find_base_type_spec (diana_get ts 'as_name)))) (cond ((is_dscrmt_record rts) (dscrmt_record%record rts)) (t rts))) (ds_find_dscrmt_vars (diana_get ts 'as_name)))) (t (diana_get ts 'as_constraint)))) (dn_type_id ;if its a type_id. (ds_find_base_type_spec (diana_get ts 'sm_type_spec))) (dn_selected (ds_find_base_type_spec (diana_get ts 'as_designator_char))) (dn_slice (diana_get ts 'as_dscrt_range)) ;if its a slice (dn_derived ;if its a derived (ds_find_base_type_spec (diana_get ts 'as_constrained))) (dn_subtype_id ;if its a type_id. (ds_find_base_type_spec (diana_get ts 'sm_type_spec))) (dn_l_private_type_id ;if its a type_id. (ds_find_base_type_spec (diana_get ts 'sm_type_spec))) (dn_private_type_id ;if its a type_id. (ds_find_base_type_spec (diana_get ts 'sm_type_spec))) (t nil) ))) ) ;;;;;;;;;;;;;;;;;;; (defun ds_find_dscrmt_vars (ts) ;;;;;;;;;;;;;;;;;;; (ct_selectq (diana_nodetype_get ts) (dn_used_name_id (ds_find_dscrmt_vars (diana_get ts 'sm_defn))) (dn_dscrmt_var_s (diana_get ts 'as_list)) (dn_record (diana_get ts 'sm_discriminants)) (dn_private_type_id (ds_find_dscrmt_vars (diana_get ts 'sm_type_spec))) (dn_l_private_type_id (ds_find_dscrmt_vars (diana_get ts 'sm_type_spec))) (dn_type_id (diana_get (car (diana_get ts 'ct_threadp)) 'as_dscrmt_var_s)) (otherwise (lose 'be_cfdv 'ds_find_dscrmt_vars)))) ;;;calls a diana subtree as a function. A call is essentially a two step ;;;operation. first of all save the return address, and then 'goto' the ;;;destination (diana subtree). The former is achieved by setting up ;;;a nodestage for the destination tree with the 'caller' slot filled in to ;;; the current node (pc). The latter is achieved simply by setting the ;;; continuation. ;;;;;;;;;;;;; (defun ds_call_diana (dt) ;;;;;;;;;;;;; (cond (dt (setq replay nil) (let ((nns (nodestagerec (diana_ct_id dt) 1 nil pc)));dest nodestage. (setq *nodestages* (cons nns *nodestages*)) ;add new nodestage. (set-iv adabe_activation *activation* 'nodestages *nodestages*) (setq *diana_subtree_call* (cons dt nns)) )))) ;set continuation. #+franz (eval-when (compile load eval) (ct_load 'loop)) ;;;Activation record functions -- jrm, 2/23/83 ;;;;;;;;; (defun env_depth (id_node) ;;;;;;;;; (let ((defocc (diana_get id_node 'sm_defn))) (cond ((eq id_node defocc) (- (get-iv adabe_activation *activation* 'pnl) (diana_get defocc 'ct_pnl))) (t (- ;(diana_get id_node 'ct_pnl) (get-iv adabe_activation *activation* 'pnl) ;(1+ (ct_send *activation* 'pnl)) (or (diana_get defocc 'ct_pnl) 1)))))) ;;;LOOK_UP_IDENT: *********************************************************** ;;;Given a Diana ID_NODE, locate the binding for that node. ;;;This depends upon the addition of Diana attribute CT_PNL, which describes ;;;the procedure nesting level of ID_NODE and of *ACTIVATION* (the currently ;;;executing process). ;;;;;;;;;;;;; (defun look_up_ident (id_node &aux target_record) ;;;;;;;;;;;;; ;;Follow the ALINK from the current activation record; the number of links ;;to cross is the difference between the PNL of *ACTIVATION* and of ;;ID_NODE. ASSQ then finds the appropriate entry for the id_node in ;;the locals of the corresponding activation record. LOOK_UP_IDENT ;;returns the (id . binding) entry from those locals. (assq (or (diana_get (diana_get id_node 'sm_defn) 'sm_defn);strip one off++ (diana_get id_node 'sm_defn)) (ct_send (follow_alink_n_times *activation* (env_depth id_node)) 'locals))) ;;;FOLLOW_ALINK_N_TIMES: **************************************************** ;;;Follow the ALINK path from the current activation record N times, ;;;returning the activation record found at that point. ;;;;;;;;;;;;;;;;;;;; (defun follow_alink_n_times (act_rec n) ;;;;;;;;;;;;;;;;;;;; ;;If N=0, we've reached the desired activation record: return (cond ((zerop n) act_rec) ;;Otherwise, follow the activation record's ALINK up to the next ;;node and decrement n. (t (follow_alink_n_times (get-iv adabe_activation act_rec 'alink) (sub1 n))))) ;;;MAKE_ACTIVATION_RECORD: *************************************************** ;;;Make and return an instance of ADABE_ACTIVATION at procedure nesting level ;;;NEW_RECORD_PNL, with ALINK and CLINK filled in corresponding to the ;;;current value of *ACTIVATION*. ;;;;;;;;;;;;;;;;;;;;;; (defun make_activation_record (current_pnl new_record_pnl) ;;;;;;;;;;;;;;;;;;;;;; (ct_make_instance 'adabe_activation ;;CT_PNL is given in the call. 'pnl (1+ new_record_pnl) ;;CLINK: The record that is the dynamic superior of the new record is, ;;by definition, always *ACTIVATION*. 'clink *activation* ;;ALINK: The textual superior record is the superior of *ACTIVATION*, ;;but we may have to search back a bit to find it. 'alink (let ((current_pnl (get-iv adabe_activation *activation* 'pnl))) ;;CURRENT_PNL had better be greater than NEW_RECORD_PNL; ;;flag an error if this is not true. (cond ((> (1- new_record_pnl) current_pnl) (break current_pnl_less_than_new_record_pnl t)) ;;OK: search up from *ACTIVATION* through ;;(- current_pnl (1- new_record_pnl)) records, and copy ;;that record's ALINK. Note that zero searches ;;may be done, which is ok. (t (follow_alink_n_times *activation* (- current_pnl new_record_pnl)) ))) 'taskinstance *current_task* ;assume same task. 'arid (gensym) ;unique AR identifier 'enhook nil 'exhook nil 'nodestages nil)) ; (t (get-iv adabe_activation ; (follow_alink_n_times ; *activation* ; (- current_pnl (1- new_record_pnl))) ; 'alink)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Internal Use Only Functions/Macros -- ;;; None. ;;;;;;;;;; (defun coerce_int(av) ;;;;;;;;;; (cond ((numberp av) av) ((and (diana_nodep av)(memq (diana_nodetype_get av) '(dn_enum_id dn_def_char))) (diana_get av 'sm_pos)) (t (lose 'be_coerce_int 'coerce_int () '("Value not an integer or enumeration literal."))))) ;;;;;;;; (defun ada_succ(v) ; finds the successor of v ;;;;;;;; (cond ((numberp v)(1+ v)) ; thats easy!. ((and (diana_nodep v) (memq (diana_nodetype_get v) '(dn_def_char dn_enum_id))) (let* ((mom (diana_get v 'sm_obj_type)) (lit (diana_get mom 'as_list)) (rest (memq v lit)) (next (cadr rest))) (cond ((null next) (ada_raise '|constraint_error| "can't take the successor of the last")) (t next)))) (t (lose 'be_cfst 'ada_succ () '("dont know how to find succ of that!!"))))) ;;;;;;;; (defun ada_pred(v) ; finds the predecessor of v ;;;;;;;; (cond ((numberp v)(1- v)) ; thats easy!. ((and (diana_nodep v) (memq (diana_nodetype_get v) '(dn_def_char dn_enum_id))) (let ((lst (diana_get (diana_get v 'sm_obj_type) 'as_list))) (do ((enl lst (cdr enl))) ((or (null enl)(eq (cadr enl) v)) (cond ((null enl) (ada_raise '|constraint_error| "can't take the predecessor of the first")) (t (car enl))))))) (t (lose 'be_cfpt 'ada_pred () '("dont know how to find pred of that!!"))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Functions to support Exceptions - MLM,JM & PR. 5-5-83 ;;;;;;;;;; (defun next_level (this_node ar) ;;;;;;;;;; (let ((next_node (dynamic_mother this_node)) (thistop (get-iv adabe_activation ar 'node))) ;top node of this activation record. (let ((alternatives (and next_node (eq (diana_nodetype_get next_node) 'dn_block) (diana_get next_node 'as_alternative_s)))) (cond ((eq alternatives this_node)(next_level next_node ar)) ((eq this_node thistop) ;have we reached the top of the tree? (let ((parent_ar (get-iv adabe_activation ar 'clink))) ;dynamic following. (cond ((null parent_ar) nil) (t `(,(get-iv adabe_activation parent_ar 'pc) ,parent_ar))))) (t `(,next_node ,ar)))))) ;;; find exception handler. ;;; Searches from 'pc'. for the dynamically closest diana node that contains ;;; an exception handler that is either exactly 'raised' or OTHERS. ;;; The diana subtree for this exception handler is returned as a result. ;;; if no matching exception handler is found a runtime error is generated ;;; with 'raised' in the message. ;;; The result is a pair of diana tree's. (block handler) ;;; block is the diana node that has an as_alternatives slot with a matching ;;; handler. This is used to find the parent process. ;;; the handler, is the diana subtree for the handler that control will be ;;; passed to. ;;;;;;;;;;;;;;;;;;;;;;;;;; (defun find_exception_handler_for(raised pc ar) ;;;;;;;;;;;;;;;;;;;;;;;;;; (cond ((null pc) ; (ferror "Runtime error: ~A" raised) (setq *exception* (exceptionrec raised)) ;error type ;(break foo) (*throw 'runtime_error 'runtime_error)) (t (let ((handlers (let ((exh (and (eq (diana_nodetype_get pc) 'dn_block) (diana_get pc 'as_alternative_s)))) (and exh (diana_get exh 'as_list))))) (cond ;; exception handlers found for this node, check to see if one ;;of them matches 'raised' (handlers (search_for_matching_handler raised pc handlers ar)) ;; exception handler not found at this node. (t (let ((nl (next_level pc ar))) (find_exception_handler_for raised (first nl) (second nl))))))))) ;;; search_for_matching_handler ;;; searches through the handler list to find a handler that matches 'raised'. ;;; it it finds one, the (block handler) pair is returned, otherwise ;;; find_exception_for is recursively invoked to search the dynamic ;;; environment. ;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun search_for_matching_handler(raised pc handlers ar) ;;;;;;;;;;;;;;;;;;;;;;;;;;; (do ((ehs handlers (cdr ehs)) (found nil)) ((cond ;; If the ehs have all been checked and none match, we must end the ;; loop and try in the parent node. Note: find_exception_handler ;; cannot return nil. ((null ehs) (setq found (let ((nl (next_level pc ar))) (find_exception_handler_for raised (first nl) (second nl)))) ) ((let ((choices (diana_get (car ehs) 'as_choice_s))) (do ((chs choices (cdr chs))) ((cond ((null chs)) ((or ;(break) (eq (diana_nodetype_get (car chs)) 'dn_others) (eq raised (intern (implode (cadr (diana_get (find_selected (car chs)) 'lx_symrep))) 'user))) (setq found `(,pc ,(car ehs) ,ar))) ;; catch for 'others' should go here++ ) found))))) found))) ;;; find_nodes_process ;;; searches the dynamic runtime clink chain and finds the process that owns ;;; the node. Takes two arguments, an activation record and a node. Returns ;;; an activation record. ;;;;;;;;;;;;;;;;;; (defun find_nodes_process_activation ( node) ;;;;;;;;;;;;;;;;;; (let ((ns (assoc (diana_get node 'ct_id) *nodestages*))) (cond (ns *activation* ) ;if we found it..return the process. (t (find_nodes_process *activation* node))))) ;;;;;;;;;;;;;;;;;; (defun find_nodes_process (ar node) ;;;;;;;;;;;;;;;;;; (cond ((null ar)(lose 'be_cfpt 'find_nodes_process () '("cannot find process for this node"))) (t (let ((ns (assoc (diana_get node 'ct_id) (get-iv adabe_activation ar 'nodestages)))) (cond (ns ar) ;if we found it..return the process. (t (find_nodes_process (get-iv adabe_activation ar 'clink) node))))))) ;;; This function takes an alist and rplaces the cars with their ;;; symreps -- This is used to make the alist in the AR readable ;;; by the inspector ;;;;;;;;;;;; (defun inspectorate (alist) ;;;;;;;;;;;; (mapcar #'(lambda (x) `(,(concat '||) . ,(cdr x))) alist)) ;;new way to find the main procedure, given a dn_compilation ;;;;;;;;;;;;;;;;; (defun ds_find_main_prog(dn) ;;;;;;;;;;;;;;;;; (do ((cu (diana_get dn 'as_list) (cdr cu))) ((null cu) (ada_raise '|program_error| "main program missing")) (ct_selectq (diana_nodetype_get (car cu)) (dn_comp_unit (let* ((thing (diana_get (car cu) 'as_unit_body)) (kind (diana_nodetype_get thing))) (ct_selectq kind (dn_subprogram_decl (let ((sp (diana_get thing 'as_designator))) (cond ((and (eq (diana_nodetype_get sp) 'dn_proc_id) (null (diana_get sp 'sm_spec))) (return (car cu))))))))) (otherwise (lose 'be_mfd 'ds_find_main_prog))))) (declare (special *units*)) ;;;;;;;;;;;;;;;;;;;;;;;; (defun ds_find_list_of_contexts(cus mp) ;;;;;;;;;;;;;;;;;;;;;;;; (let* ((ccls (mapcan #'(lambda(cu) (let ((cuc (mapcan #'(lambda(cc) (cond ((eq (diana_nodetype_get cc) 'dn_with) (list (diana_get cc 'as_list))))) (let* ((ctx (diana_get cu 'as_context)) (ctxl (and ctx (diana_get ctx 'as_list)))) ctxl)))) (cond (cuc (list (cons (diana_get cu 'as_unit_body) cuc)))))) cus)) (root (cdr (assq (diana_get mp 'as_unit_body) ccls)))) (do ((subtree root (cdr subtree)) (*units* nil)) ((null subtree) (nreverse *units*)) (find_new_units_recursively subtree ccls)))) ;;;;;;;;;;;;;;;;;;;;;;;;;; (defun find_new_units_recursively(dns cual) ;;;;;;;;;;;;;;;;;;;;;;;;;; (do ((group dns (cdr group))) ((null group)) (do ((sg (car group) (cdr sg))) ((null sg)) (let ((defo (diana_get (car sg) 'sm_defn))) (cond ((not (memq defo *units*)) ;(break here) (find_new_units_recursively (cdr (assq (car (diana_get defo 'ct_threadp)) cual)) cual) (ct_push defo *units*))))))) ;;; eof ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;