-- 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