-- File: ScriptTreeImpl.mesa - last edit by -- Karlton: 16-Aug-82 15:49:42 DIRECTORY ScriptTree USING [ Direction, EnumerateOrder, ErrorCode, Handle, Object]; ScriptTreeImpl: PROGRAM EXPORTS ScriptTree = { Error: PUBLIC ERROR [code: ScriptTree.ErrorCode] = CODE; Handle: TYPE = ScriptTree.Handle; TreeHandle: TYPE = LONG POINTER TO TreeObject; TreeObject: PUBLIC TYPE = RECORD [ enumerators: CARDINAL _ 0, root: Handle _ NIL, z: UNCOUNTED ZONE]; Create: PUBLIC PROCEDURE [z: UNCOUNTED ZONE] RETURNS [tree: TreeHandle] = { tree _ z.NEW[TreeObject _ [z: z]]}; Destroy: PUBLIC PROCEDURE [tree: TreeHandle] = { z: UNCOUNTED ZONE = tree.z; IF tree.enumerators # 0 THEN ERROR Error[outstandingEnumerator]; z.FREE[@tree]}; RootNode: PUBLIC PROCEDURE [tree: TreeHandle] RETURNS [node: Handle] = { RETURN[tree.root]}; AddNode: PUBLIC PROCEDURE [tree: TreeHandle, parent, leftSibling: Handle] RETURNS [node: Handle] = { node _ tree.z.NEW[ScriptTree.Object _ []]; EnlinkNode[tree, node, parent, leftSibling]}; EnlinkNode: PROCEDURE [tree: TreeHandle, node, parent, leftSibling: Handle] = { node.parent _ parent; node.leftSibling _ leftSibling; IF parent = NIL THEN { IF leftSibling # NIL THEN ERROR Error[siblingNotChildOfParent]; IF tree.root # NIL THEN ERROR Error[alreadyHasRoot]; tree.root _ node; RETURN}; IF tree.root = NIL THEN ERROR Error[noRoot]; IF leftSibling # NIL AND leftSibling.parent # parent THEN ERROR Error[siblingNotChildOfParent]; IF leftSibling = NIL THEN { node.rightSibling _ parent.child; parent.child _ node} ELSE { node.rightSibling _ leftSibling.rightSibling; leftSibling.rightSibling _ node}; IF node.rightSibling # NIL THEN node.rightSibling.leftSibling _ node}; MoveNode: PUBLIC PROCEDURE [ tree: TreeHandle, node, newParent, newLeftSibling: Handle] = { DelinkNode[tree, node]; EnlinkNode[tree, node, newParent, newLeftSibling]}; DelinkNode: PROCEDURE [tree: TreeHandle, node: Handle] = { IF node.rightSibling # NIL THEN node.rightSibling.leftSibling _ node.leftSibling; IF node.leftSibling # NIL THEN node.leftSibling.rightSibling _ node.rightSibling; IF node.parent = NIL THEN tree.root _ NIL ELSE IF node.parent.child = node THEN node.parent.child _ node.rightSibling; node.parent _ node.leftSibling _ node.rightSibling _ NIL}; RemoveNode: PUBLIC PROCEDURE [tree: TreeHandle, node: Handle] = { IF node = NIL THEN RETURN; WHILE node.child # NIL DO RemoveNode[tree, node.child] ENDLOOP; DelinkNode[tree, node]; tree.z.FREE[@node]}; Enumerator: TYPE = LONG POINTER TO EnumerateState; EnumerateState: PUBLIC TYPE = RECORD [ last: Handle _ NIL, order: ScriptTree.EnumerateOrder, done: BOOLEAN _ FALSE, origin: Handle, tree: TreeHandle]; Enumerate: PUBLIC PROCEDURE [state: Enumerator] RETURNS [Handle] = { IF state = NIL OR state.done THEN RETURN[NIL]; SELECT state.order FROM pre => state.last _ FindNextPreOrder[state]; end => state.last _ FindNextEndOrder[state]; ENDCASE => ERROR Error[implementationBug]; RETURN[state.last]}; FindNextPreOrder: PROCEDURE [state: Enumerator] RETURNS [node: Handle] = { SELECT TRUE FROM state.last = NIL => RETURN[state.origin]; state.last.child # NIL => RETURN[state.last.child]; state.last.rightSibling # NIL => RETURN[state.last.rightSibling]; ENDCASE; WHILE (state.last _ state.last.parent) # state.origin DO IF state.last.rightSibling # NIL THEN RETURN[state.last.rightSibling] ENDLOOP; state.done _ TRUE; RETURN[NIL]}; FindEnd: PROCEDURE [node: Handle] RETURNS [son: Handle] = { son _ node; WHILE son.child # NIL DO son _ son.child ENDLOOP}; FindNextEndOrder: PROCEDURE [state: Enumerator] RETURNS [node: Handle] = { tree: TreeHandle = state.tree; SELECT TRUE FROM state.last = NIL => RETURN[FindEnd[state.origin]]; state.last.rightSibling # NIL => RETURN[FindEnd[state.last.rightSibling]]; ENDCASE => { state.done _ (state.last.parent = state.origin); RETURN[state.last.parent]}}; CreateEnumerator: PUBLIC PROCEDURE [ tree: TreeHandle, order: ScriptTree.EnumerateOrder, origin: Handle] RETURNS [state: Enumerator] = { IF tree = NIL THEN RETURN[NIL]; tree.enumerators _ tree.enumerators + 1; state _ tree.z.NEW[EnumerateState _ [ tree: tree, order: order, origin: IF origin = NIL THEN tree.root ELSE origin]]}; DestroyEnumerator: PUBLIC PROCEDURE [state: Enumerator] = { tree: TreeHandle; IF state = NIL THEN RETURN; tree _ state.tree; tree.enumerators _ tree.enumerators - 1; tree.z.FREE[@state]}; SetEnumerator: PUBLIC PROCEDURE [ state: Enumerator, order: ScriptTree.EnumerateOrder, origin: Handle] = { state.origin _ IF origin = NIL THEN state.tree.root ELSE origin; state.order _ order; state.done _ FALSE}; Walk: PUBLIC PROCEDURE [node: Handle, direction: ScriptTree.Direction] RETURNS [newNode: Handle] = { IF node = NIL THEN RETURN[NIL]; RETURN[SELECT direction FROM left => node.leftSibling, right => node.rightSibling, up => node.parent, down => node.child, ENDCASE => ERROR]}; }. -- of ScriptTreeImpl