############################################################################
#
#	File:     evaltree.icn
#
#	Subject:  Procedures to maintain activation tree
#
#	Author:   Clinton Jeffery
#
#	Date:     June 19, 1994
#
###########################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#  Usage: evaltree(cset, procedure, record constructor)
#
#  The record type must have fields node, parent, children
#
#  See "A Framework for Monitoring Program Execution", Clinton L. Jeffery,
#  TR 93-21, Department of Computer Science, The University of Arizona,
#  July 30, 1993.
#
############################################################################
#
#  Requires:  MT Icon and event monitoring
#
############################################################################

$include "evdefs.icn"

record __evaltree_node(node,parent,children)

global CallCodes,
   SuspendCodes,
   ResumeCodes,
   ReturnCodes,
   FailCodes,
   RemoveCodes

procedure evaltree(mask, callback, activation_record)
   local c, current, p, child


   /activation_record := __evaltree_node
   CallCodes := string(mask ** cset(E_Pcall || E_Fcall || E_Ocall || E_Snew))
   SuspendCodes := string(mask ** cset(E_Psusp || E_Fsusp ||
      E_Osusp || E_Ssusp))
   ResumeCodes := string(mask ** cset(E_Presum || E_Fresum || E_Oresum ||
      E_Sresum))
   ReturnCodes  := string(mask ** cset(E_Pret || E_Fret || E_Oret))
   FailCodes := string(mask ** cset(E_Pfail || E_Ffail || E_Ofail || E_Sfail))
   RemoveCodes  := string(mask ** cset(E_Prem || E_Frem || E_Orem || E_Srem))

   current := activation_record()
   current.parent := activation_record()
   current.children := []
   current.parent.children := []

   while EvGet(mask) do {
      case &eventcode of {
	 !CallCodes: {
	    c := activation_record()
	    c.node := &eventvalue
	    c.parent := current
	    c.children := []
	    put(current.children, c)
	    current := c
	    callback(current, current.parent)
	    }
	 !ReturnCodes | !FailCodes: {
	    p := pull(current.parent.children)
	    current := current.parent
	    callback(current, p)
	    }
	 !SuspendCodes: {
	    current := current.parent
	    callback(current, current.children[-1])
	    }
	 !ResumeCodes: {
	    current := current.children[-1]
	    callback(current, current.parent)
	    }
	 !RemoveCodes: {
	    if child := pull(current.children) then {
	       while put(current.children, pop(child.children))
	       callback(current, child)
	       }
	    else {
	       if current === current.parent.children[-1] then {
		  p := pull(current.parent.children)
		  current := current.parent
		  callback(current, p)
		  next
		  }
	       else stop("evaltree: unknown removal")
	       }
	    }
	 default: {
	    callback(current, current)
	    }
	 }
      }
end

