TiogaTreeOpsImpl.mesa; Written by S. McGregor, February 1983
Edited by Paxton, July 26, 1983 11:07 am
Edited by McGregor, May 12, 1983 5:00 pm
DIRECTORY
TiogaNode,
TiogaNodeOps,
CreateNode,
TiogaTreeOps;
TiogaTreeOpsImpl: CEDAR PROGRAM
IMPORTS CreateNode, TiogaNodeOps
EXPORTS TiogaTreeOps
SHARES TiogaNode =
BEGIN OPEN TiogaTreeOps;
RefBoxNode: TYPE = TiogaNode.RefBoxNode;
RefListNode: TYPE = TiogaNode.RefListNode;
Tree traversal
Parent: PUBLIC PROC [n: Ref] RETURNS [Ref] = {
IF n=NIL OR n.deleted THEN RETURN [NIL];
UNTIL n.last DO n ← n.next; ENDLOOP;
IF n.next # NIL THEN RETURN [n.next];
RETURN [NIL] };
Root: PUBLIC PROC [n: Ref] RETURNS [RefBranchNode] = {
p: Ref;
DO IF (p←Parent[n])=NIL THEN RETURN[TiogaNodeOps.NarrowToBranchNode[n]]; n ← p; ENDLOOP };
Next: PUBLIC PROC [n: Ref] RETURNS [Ref] = {
IF n.last THEN RETURN [NIL];
WITH n ← n.next SELECT FROM
br: RefBranchNode => CheckInternalRep[br];
ENDCASE;
RETURN [n] };
Contents: PUBLIC PROC [n: Ref] RETURNS [Ref] = {
IF n=NIL THEN RETURN [NIL];
WITH n SELECT FROM
br: RefBranchNode => { CheckInternalRep[br]; n ← br.contents };
bx: RefBoxNode => n ← bx.contents;
ls: RefListNode => n ← ls.contents;
ENDCASE => RETURN [NIL];
RETURN [n] };
BranchChild: PUBLIC PROC [n: RefBranchNode] RETURNS [RefBranchNode] = {
IF n=NIL THEN RETURN [NIL];
CheckInternalRep[n];
IF (n ← n.child)=NIL THEN RETURN [NIL];
CheckInternalRep[n];
RETURN [n] };
FirstSibling: PUBLIC PROC [n: Ref, parent: Ref ← NIL] RETURNS [sib: Ref] = {
Returns n if n is the first sibling
IF n=NIL THEN RETURN [NIL];
IF parent=NIL THEN parent ← Parent[n];
IF parent=NIL THEN RETURN [NIL];
WITH parent SELECT FROM
br: RefBranchNode =>
IF TiogaNodeOps.IsBranch[n] THEN
CheckInternalRep[TiogaNodeOps.NarrowToBranchNode[sib ← br.child]]
ELSE sib ← br.contents;
bx: RefBoxNode => sib ← bx.contents;
ls: RefListNode => sib ← ls.contents;
ENDCASE => ERROR -- parent must be a branch, a box, or a list -- };
LastSibling: PUBLIC PROC [n: Ref] RETURNS [sib: Ref] = {
Returns n if n is the last sibling
DO IF n.last THEN EXIT; n ← n.next; ENDLOOP;
WITH n SELECT FROM
br: RefBranchNode => CheckInternalRep[br];
ENDCASE };
Previous: PUBLIC PROC [n: Ref, parent: Ref ← NIL] RETURNS [sib: Ref] = {
Returns NIL if n=FirstSibling[n]
nxt: Ref;
IF (sib ← FirstSibling[n, parent])=n THEN RETURN [NIL];
DO IF sib.last THEN ERROR; IF (nxt ← sib.next)=n THEN EXIT; sib ← nxt; ENDLOOP;
WITH sib SELECT FROM
br: RefBranchNode => CheckInternalRep[br];
ENDCASE };
LastWithin: PUBLIC PROC [n: Ref] RETURNS [Ref] = {
nxt: Ref;
DO
IF n=NIL THEN RETURN [NIL];
IF (nxt ← BranchChild[TiogaNodeOps.NarrowToBranchNode[n]])=NIL THEN nxt ← Contents[n];
IF nxt=NIL THEN RETURN [n];
n ← LastSibling[nxt];
ENDLOOP };
ContainingStatement: PUBLIC PROC [n: Ref] RETURNS [s: RefBranchNode] = {
UNTIL (s ← TiogaNodeOps.NarrowToBranchNode[n]) # NIL DO n ← Parent[n]; ENDLOOP };
Forward and Backward in Tree
StepForwardNode: PUBLIC PROC [node: Ref] RETURNS [nxt: Ref] = {
returns next node in standard tree walk order; visits branch contents before branch children
isBranch: BOOLFALSE; -- indicates whether or not node is a branch node
IF node=NIL THEN RETURN [NIL];
WITH node SELECT FROM
br: RefBranchNode => {
isBranch ← TRUE;
CheckInternalRep[br];
IF (nxt ← br.contents)=NIL THEN nxt ← br.child };
bx: RefBoxNode => nxt ← bx.contents;
ls: RefListNode => nxt ← ls.contents;
ENDCASE => nxt ← NIL;
IF nxt # NIL THEN RETURN; -- descend in the tree
DO
IF ~node.last THEN { -- return the next sibling
IF isBranch THEN CheckInternalRep[TiogaNodeOps.NarrowToBranchNode[node.next]];
RETURN [node.next] };
IF (node ← node.next) = NIL THEN RETURN [NIL]; -- move to the parent
IF ~isBranch THEN WITH node SELECT FROM
br: RefBranchNode => { -- have visited contents of this branch; now visit children
The previous node is not a branch, but its parent is.
This implies that previous node was last of branch contents since child of branch must be a branch.
IF br.child # NIL THEN RETURN[BranchChild[br]];
isBranch ← TRUE };
ENDCASE;
ENDLOOP };
Forward: PUBLIC PROC [node: RefBranchNode] RETURNS [nx: RefBranchNode, levelDelta: INTEGER] = {
returns next branch in standard tree walk order
child: RefBranchNode;
n: Ref;
IF node=NIL THEN RETURN [NIL, 0];
IF (child ← BranchChild[node]) # NIL THEN RETURN [child, 1]; -- descend in the tree
levelDelta ← 0;
n ← node;
DO -- move to next node, sibling or up* then sibling
IF ~n.last THEN { -- return the sibling
br: RefBranchNode = TiogaNodeOps.NarrowToBranchNode[n.next];
CheckInternalRep[br]; RETURN [br, levelDelta] };
IF (n ← n.next) = NIL THEN RETURN [NIL, 0]; -- move to the parent
levelDelta ← levelDelta-1;
ENDLOOP };
StepBackwardNode: PUBLIC PROC [node: Ref, parent: Ref ← NIL] RETURNS [back, backparent: Ref] = {
child, child2: Ref;
isBranch: BOOLFALSE; -- indicates whether or not node is a branch node
IF parent = NIL THEN parent ← Parent[node];
IF parent = NIL OR node=NIL THEN RETURN [NIL, NIL];
WITH parent SELECT FROM
br: RefBranchNode => child ← IF TiogaNodeOps.IsBranch[node] THEN br.child ELSE br.contents;
bx: RefBoxNode => child ← bx.contents;
ls: RefListNode => child ← ls.contents;
ENDCASE => child ← NIL;
IF child = node THEN RETURN [parent, Parent[parent]]; -- node is first contents
DO -- find predecessor of node
IF child.last THEN ERROR; -- incorrect value supplied for parent
IF (child2 ← child.next)=node THEN EXIT;
child ← child2;
ENDLOOP;
DO -- find last node within predecessor
WITH child SELECT FROM
br: RefBranchNode => { CheckInternalRep[br]; IF (child2 ← br.child)=NIL THEN child2 ← br.contents };
bx: RefBoxNode => child2 ← bx.contents;
ls: RefListNode => child2 ← ls.contents;
ENDCASE => child2 ← NIL;
IF child2=NIL THEN RETURN [child, parent];
parent ← child; child ← LastSibling[child2];
ENDLOOP };
Backward: PUBLIC PROC [node: RefBranchNode, parent: Ref ← NIL]
RETURNS [back: RefBranchNode, backparent: Ref, levelDelta: INTEGER] = {
returns preceeding node in standard tree walk order
child, child2: Ref;
parentBranch: RefBranchNode;
IF parent = NIL THEN parent ← Parent[node];
IF parent = NIL OR node = NIL THEN RETURN [NIL,NIL,0];
WITH parent SELECT FROM
br: RefBranchNode => { CheckInternalRep[parentBranch ← br]; child ← br.child };
bx: RefBoxNode => child ← bx.contents;
ls: RefListNode => child ← ls.contents;
ENDCASE => child ← NIL;
IF child = node THEN RETURN [parentBranch, Parent[parentBranch], -1]; -- node is first child
DO -- find the predecessor
IF child.last THEN ERROR; -- incorrect value supplied for parent
IF (child2 ← child.next)=node THEN {
CheckInternalRep[TiogaNodeOps.NarrowToBranchNode[child]]; EXIT };
child ← child2;
ENDLOOP;
levelDelta ← 0;
DO -- find last branch within the predecessor
childBranch: RefBranchNode = TiogaNodeOps.NarrowToBranchNode[child];
IF (child2 ← childBranch.child) = NIL THEN
RETURN [childBranch, parent, levelDelta];
levelDelta ← levelDelta+1;
parent ← child; child ← LastSibling[child2]; ENDLOOP };
Miscellaneous
LastBranchWithin: PUBLIC PROC [n: RefBranchNode] RETURNS [RefBranchNode] = {
nxt: RefBranchNode;
IF n=NIL THEN RETURN [NIL];
DO
IF (nxt ← BranchChild[n])=NIL THEN RETURN [n];
n ← TiogaNodeOps.NarrowToBranchNode[LastSibling[nxt]];
ENDLOOP };
Level: PUBLIC PROC [n: Ref] RETURNS [level: INTEGER] = {
level ← 0; UNTIL (n ← Parent[n])=NIL DO level ← level+1; ENDLOOP };
MakeTreeLoc: PUBLIC PROC [n: Ref] RETURNS [TreeLoc] = {
RETURN [[n, TiogaNode.NodeItself]] };
MakeTreeSpan: PUBLIC PROC [first, last: Ref] RETURNS [TreeSpan] = {
RETURN [[MakeTreeLoc[first], MakeTreeLoc[last]]] };
MakeBranchLoc: PUBLIC PROC [n: RefBranchNode] RETURNS [BranchLoc] = {
RETURN [[n, TiogaNode.NodeItself]] };
MakeBranchSpan: PUBLIC PROC [first, last: RefBranchNode] RETURNS [BranchSpan] = {
RETURN [[MakeBranchLoc[first], MakeBranchLoc[last]]] };
BackLoc: PUBLIC PROC [loc: TreeLoc] RETURNS [new: TreeLoc] = {
text: TiogaNode.RefTextNode;
new.node ← StepBackwardNode[loc.node].back;
new.where ← IF loc.where=TiogaNode.NodeItself OR (text ← TiogaNodeOps.NarrowToTextNode[new.node])=NIL
THEN TiogaNode.NodeItself ELSE TiogaNodeOps.Size[text] };
ForwardLoc: PUBLIC PROC [loc: TreeLoc] RETURNS [new: TreeLoc] = {
new.node ← StepForwardNode[loc.node];
new.where ← IF loc.where=TiogaNode.NodeItself OR TiogaNodeOps.NarrowToTextNode[new.node]=NIL
THEN TiogaNode.NodeItself ELSE 0 };
CheckInternalRep: PROC [br: TiogaNode.RefBranchNode] = INLINE {
IF ~br.internalRepCreated THEN CreateNode.CreateInternalRep[br] };
END.