-- Test3Impl.mesa -- written by Bill Paxton, April 1981 -- last edit by Bill Paxton, 28-Jul-81 10:12:47 DIRECTORY EditTest, EditSpan, UndoEvent, TextNode, RandomLongInt, TreeCheck; Test3Impl: PROGRAM IMPORTS EditTest, EditSpan, TreeCheck, TextNode, RandomLongInt, UndoEvent EXPORTS EditTest = BEGIN OPEN EditTest, spanI:EditSpan, randLI:RandomLongInt, undoI:UndoEvent, nodeI:TextNode; Span: TYPE = nodeI.Span; -- ***** Node Edit operations PickNodeDest: PROC [tree: Ref] RETURNS [dest: Location, start, loc, size: Offset, where: Place, after, before: Ref] = { [dest, loc, size] _ PickNodeLoc[tree]; IF size=0 THEN { dest _ nodeI.MakeNodeLoc[tree]; loc _ -1; where _ child } ELSE where _ PickPlace[]; IF where#before THEN { after _ nodeI.StepForward[before _ dest.node]; start _ loc+1 } ELSE { before _ nodeI.StepBackward[after _ dest.node]; start _ loc }}; CheckSpan: PROC [span: Span, spanStart, spanLen, treeSize: Offset, beforeSpan, afterSpan: Ref] = { start, len, size: Offset; before, after: Ref; [start, len, size] _ LocateSpan[span]; IF size # treeSize OR start # spanStart OR len # spanLen THEN ERROR; IF (before _ nodeI.StepForward[beforeSpan]) # span.start.node THEN ERROR; IF afterSpan # (after _ nodeI.StepForward[span.end.node]) THEN ERROR }; ReplaceNodes: PUBLIC PROC = { CheckReplace: PROC = { TreeCheck.Verify[destTree]; TreeCheck.Verify[nodeI.Root[dest.start.node]]; CheckSpan[result, destStart, sourceLen, resultSize, beforeDest, afterDest] }; sourceTree, destTree: Ref; source, dest, result: Span; beforeDest, afterDest: Ref; destStart, destLen, destSize, sourceStart, sourceLen, sourceSize: Offset; resultSize: Offset; [sourceTree, destTree] _ PickTrees[]; [source, sourceStart, sourceLen, sourceSize] _ PickNodeSpan[sourceTree]; [dest, destStart, destLen, destSize] _ PickNodeSpan[destTree]; beforeDest _ nodeI.StepBackward[dest.start.node]; afterDest _ nodeI.StepForward[dest.end.node]; undoI.Reset[event]; result _ spanI.Replace[dest, source, FALSE, event]; resultSize _ destSize+sourceLen-destLen; CheckReplace; undoI.Reset[undoEvent]; undoI.Undo[event, undoEvent]; TreeCheck.Verify[destTree]; TreeCheck.Verify[nodeI.Root[result.start.node]]; CheckSpan[dest, destStart, destLen, destSize, beforeDest, afterDest]; undoI.Undo[undoEvent]; -- undo the previous undo CheckReplace; AdjustTree[destTree, resultSize] }; DeleteFromTree: PUBLIC PROC [tree: Ref, size, num: Offset] RETURNS [newsize: Offset] = { newsize _ size; WHILE num > 0 DO start: Location; last, before, after: Ref; len, destLoc, destSize: Offset; [start, destLoc, destSize] _ PickNodeLoc[tree]; IF (len _ MIN[num,destSize-destLoc])=0 THEN ERROR; last _ FindLastNode[start.node, len]; after _ nodeI.StepForward[last]; before _ nodeI.StepBackward[start.node]; [] _ spanI.Delete[[start,nodeI.MakeNodeLoc[last]]]; newsize _ newsize-len; num _ num-len; CheckDelete[tree, before, after, start.node, newsize]; ENDLOOP }; CheckDelete: PROC [destTree, beforeDest, afterDest, inDest: Ref, resultSize: Offset] = { size: Offset; next: Ref; TreeCheck.Verify[destTree]; TreeCheck.Verify[nodeI.Root[inDest]]; IF (size _ TreeSize[destTree]) # resultSize THEN ERROR; IF (next _ nodeI.StepForward[beforeDest]) # afterDest THEN ERROR }; DeleteNodes: PUBLIC PROC = { destTree: Ref; dest: Span; beforeDest, afterDest: Ref; destStart, destLen, destSize: Offset; resultSize: Offset; destTree _ PickTree[]; [dest, destStart, destLen, destSize] _ PickNodeSpan[destTree]; beforeDest _ nodeI.StepBackward[dest.start.node]; afterDest _ nodeI.StepForward[dest.end.node]; undoI.Reset[event]; spanI.Delete[dest, event]; resultSize _ destSize-destLen; CheckDelete[destTree, beforeDest, afterDest, dest.start.node, resultSize]; undoI.Reset[undoEvent]; undoI.Undo[event, undoEvent]; -- undo the delete TreeCheck.Verify[destTree]; CheckSpan[dest, destStart, destLen, destSize, beforeDest, afterDest]; undoI.Undo[undoEvent]; -- undo the previous undo CheckDelete[destTree, beforeDest, afterDest, dest.start.node, resultSize]; AdjustTree[destTree, resultSize] }; InsertInTree: PUBLIC PROC [tree: Ref, size, num: Offset] RETURNS [newsize: Offset] = { newsize _ size; WHILE num > 0 DO newsize _ InsertOne[tree]; num _ num-1; ENDLOOP }; InsertNode: PUBLIC PROC = { tree: Ref _ PickTree[]; size: Offset _ InsertOne[tree]; AdjustTree[tree, size] }; InsertOne: PROC [tree: Ref] RETURNS [size: Offset] = { dest: Location; destStart, destLoc, destSize: Offset; new, afterDest, beforeDest: Ref; where: Place; [dest,destStart,destLoc,destSize,where,afterDest,beforeDest] _ PickNodeDest[tree]; new _ spanI.Insert[dest.node, where]; TreeCheck.Verify[tree]; CheckSpan[nodeI.MakeNodeSpan[new,new], destStart, 1, destSize+1, beforeDest, afterDest]; RETURN [destSize+1] }; CopyNodes: PUBLIC PROC = { sourceTree, destTree: Ref; source, result: Span; dest: Location; beforeDest, afterDest: Ref; destStart, destLoc, destSize, sourceStart, sourceLen, sourceSize: Offset; undoLoc, undoSize, resultSize: Offset; where: Place; [sourceTree, destTree] _ PickTrees[]; [source, sourceStart, sourceLen, sourceSize] _ PickNodeSpan[sourceTree]; [dest,destStart,destLoc,destSize,where,afterDest,beforeDest] _ PickNodeDest[destTree]; undoI.Reset[event]; result _ spanI.Copy[dest, source, FALSE, where, 0, event]; TreeCheck.Verify[destTree]; CheckSpan[result, destStart, sourceLen, resultSize _ destSize+sourceLen, beforeDest, afterDest]; undoI.Reset[undoEvent]; undoI.Undo[event, undoEvent]; -- undo the copy TreeCheck.Verify[destTree]; [undoLoc, undoSize] _ LocateNode[dest.node]; IF undoSize # destSize OR undoLoc # destLoc THEN ERROR; undoI.Undo[undoEvent]; -- undo the previous undo TreeCheck.Verify[destTree]; CheckSpan[result, destStart, sourceLen, resultSize, beforeDest, afterDest]; AdjustTree[destTree, resultSize] }; MoveNodes: PUBLIC PROC = { CheckMove: PROC = { next: Ref; size: Offset; TreeCheck.Verify[destTree]; IF result # source THEN ERROR; IF (next _ nodeI.StepForward[beforeSource]) # afterSource THEN ERROR; IF sourceTree=destTree THEN { resultSize _ sourceSize; resultStart _ IF destStart > sourceStart THEN destStart-sourceLen ELSE destStart } ELSE { TreeCheck.Verify[sourceTree]; IF (size _ TreeSize[sourceTree]) # sourceSize-sourceLen THEN ERROR; resultSize _ destSize+sourceLen; resultStart _ destStart }; CheckSpan[result, resultStart, sourceLen, resultSize, beforeDest, afterDest] }; sourceTree, destTree, beforeDest, afterDest, beforeSource, afterSource: Ref; moveToEnd: BOOLEAN; source, result: Span; dest: Location; sourceStart, sourceLen, sourceSize, destStart, destLoc, destSize: Offset; where: Place; undoLoc, undoSize, resultStart, resultSize: Offset; [sourceTree, destTree] _ PickTrees[]; [source, sourceStart, sourceLen, sourceSize] _ PickNodeSpan[sourceTree]; IF sourceTree=destTree THEN { destSize _ sourceSize; IF moveToEnd_RandomBoolean[] THEN { -- move toward end sourceEnd: Offset _ sourceStart+sourceLen; IF sourceSize=sourceEnd THEN RETURN; -- cannot move toward end where _ IF RandomBoolean[] THEN after ELSE child; destLoc _ randLI.Choose[sourceEnd,sourceSize-1] } ELSE { -- move toward front IF sourceStart=0 THEN RETURN; -- cannot move toward front where _ before; destLoc _ randLI.Choose[0,sourceStart-1] }; dest _ [FindTreeNode[destTree,destLoc],nodeI.NodeItself]; IF where#before THEN { afterDest _ nodeI.StepForward[beforeDest _ dest.node]; destStart _ destLoc+1 } ELSE { beforeDest _ nodeI.StepBackward[afterDest _ dest.node]; destStart _ destLoc }} ELSE [dest,destStart,destLoc,destSize,where,afterDest,beforeDest] _ PickNodeDest[destTree]; afterSource _ nodeI.StepForward[source.end.node]; beforeSource _ nodeI.StepBackward[source.start.node]; undoI.Reset[event]; result _ spanI.Move[dest, source, FALSE, where, 0, event]; CheckMove; undoI.Reset[undoEvent]; undoI.Undo[event, undoEvent]; -- undo the move TreeCheck.Verify[destTree]; IF sourceTree#destTree THEN TreeCheck.Verify[sourceTree]; [undoLoc, undoSize] _ LocateNode[dest.node]; IF undoSize # destSize OR undoLoc # destLoc THEN ERROR; CheckSpan[source, sourceStart, sourceLen, sourceSize, beforeSource, afterSource]; undoI.Undo[undoEvent]; -- undo the previous undo CheckMove; IF sourceTree#destTree THEN { AdjustTree[destTree, destSize+sourceLen]; AdjustTree[sourceTree, sourceSize-sourceLen] }}; MoveNodesOnto: PUBLIC PROC = { CheckMoveOnto: PROC = { IF result # source THEN ERROR; TreeCheck.Verify[destTree]; IF sourceTree = destTree THEN { -- check for overlap or adjacent IF destEnd=sourceStart THEN CheckSpan[result, destStart, sourceLen, sourceSize-destLen, beforeDest, afterSource] ELSE IF sourceEnd=destStart THEN CheckSpan[result, sourceStart, sourceLen, sourceSize-destLen, beforeSource, afterDest] ELSE IF sourceStart IN [destStart..destEnd) THEN IF sourceEnd IN [destStart..destEnd] THEN CheckSpan[result, destStart, sourceLen, sourceSize+sourceLen-destLen, beforeDest, afterDest] ELSE CheckSpan[result, destStart, sourceLen, sourceSize+destStart-sourceStart, beforeDest, afterSource] ELSE IF sourceEnd IN [destStart..destEnd) THEN CheckSpan[result, sourceStart, sourceLen, sourceSize+sourceEnd-destEnd, beforeSource, afterDest] ELSE IF sourceStart < destStart THEN IF sourceEnd >= destEnd THEN CheckSpan[result, sourceStart, sourceLen, sourceSize, beforeSource, afterSource] ELSE CheckSpan[result, destStart-sourceLen, sourceLen, sourceSize-destLen, beforeDest, afterDest] ELSE CheckSpan[result, destStart, sourceLen, sourceSize-destLen, beforeDest, afterDest] } ELSE { size: Offset; next: Ref; TreeCheck.Verify[sourceTree]; IF (size _ TreeSize[sourceTree]) # sourceSize-sourceLen THEN ERROR; IF (next _ nodeI.StepForward[beforeSource]) # afterSource THEN ERROR; CheckSpan[result, destStart, sourceLen, destSize+sourceLen-destLen, beforeDest, afterDest] }}; sourceTree, destTree: Ref; source, dest, result: Span; beforeDest, afterDest, beforeSource, afterSource: Ref; destStart, destLen, destSize, sourceStart, sourceLen, sourceSize: Offset; destEnd, sourceEnd: Offset; [sourceTree, destTree] _ PickTrees[]; [source, sourceStart, sourceLen, sourceSize] _ PickNodeSpan[sourceTree]; sourceEnd _ sourceStart+sourceLen; [dest, destStart, destLen, destSize] _ PickNodeSpan[destTree]; destEnd _ destStart+destLen; beforeDest _ nodeI.StepBackward[dest.start.node]; afterDest _ nodeI.StepForward[dest.end.node]; beforeSource _ nodeI.StepBackward[source.start.node]; afterSource _ nodeI.StepForward[source.end.node]; undoI.Reset[event]; result _ spanI.MoveOnto[dest, source, FALSE, event]; CheckMoveOnto; undoI.Reset[undoEvent]; undoI.Undo[event, undoEvent]; -- undo the move TreeCheck.Verify[destTree]; IF sourceTree # destTree THEN TreeCheck.Verify[sourceTree]; CheckSpan[dest, destStart, destLen, destSize, beforeDest, afterDest]; CheckSpan[source, sourceStart, sourceLen, sourceSize, beforeSource, afterSource]; undoI.Undo[undoEvent]; -- undo the previous undo CheckMoveOnto; IF sourceTree # destTree THEN { AdjustTree[destTree, destSize+sourceLen-destLen]; AdjustTree[sourceTree, sourceSize-sourceLen] } ELSE AdjustTree[destTree, TreeSize[destTree]] }; TransposeNodes: PUBLIC PROC = { CheckTranspose: PROC = { TreeCheck.Verify[alphaTree]; IF alphaTree = betaTree THEN { IF ~alphaFirst THEN { CheckSpan[alpha, betaStart, alphaLen, alphaSize, beforeBeta, afterBeta]; CheckSpan[beta, alphaStart+alphaLen-betaLen, betaLen, alphaSize, beforeAlpha, afterAlpha] } ELSE { CheckSpan[alpha, betaStart-alphaLen+betaLen, alphaLen, alphaSize, beforeBeta, afterBeta]; CheckSpan[beta, alphaStart, betaLen, alphaSize, beforeAlpha, afterAlpha] }} ELSE { TreeCheck.Verify[betaTree]; CheckSpan[alpha, betaStart, alphaLen, betaSize+alphaLen-betaLen, beforeBeta, afterBeta]; CheckSpan[beta, alphaStart, betaLen, alphaSize+betaLen-alphaLen, beforeAlpha, afterAlpha] }}; alphaTree, betaTree: Ref; alpha, beta, alphaResult, betaResult: Span; beforeAlpha, afterAlpha, beforeBeta, afterBeta: Ref; alphaStart, alphaLen, alphaSize, betaStart, betaLen, betaSize: Offset; alphaEnd, betaEnd: Offset; alphaFirst: BOOLEAN; [alphaTree, betaTree] _ PickTrees[]; [alpha, alphaStart, alphaLen, alphaSize] _ PickNodeSpan[alphaTree]; alphaEnd _ alphaStart+alphaLen; beforeAlpha _ nodeI.StepBackward[alpha.start.node]; afterAlpha _ nodeI.StepForward[alpha.end.node]; IF alphaTree = betaTree THEN { betaFirst, betaLast: Ref; betaSize _ alphaSize; IF alphaFirst_RandomBoolean[] THEN { IF alphaEnd+1 >= alphaSize THEN RETURN; -- nothing after alpha [betaStart,betaEnd] _ ChooseTwo[alphaEnd+1,alphaSize] } ELSE { -- pick beta section to left of alpha IF alphaStart <= 1 THEN RETURN; -- nothing before alpha [betaStart,betaEnd] _ ChooseTwo[0,alphaStart-1] }; IF (betaLen _ betaEnd-betaStart) = 0 THEN RETURN; betaFirst _ FindTreeNode[betaTree, betaStart]; betaLast _ FindTreeNode[betaTree, betaEnd-1]; beta _ nodeI.MakeNodeSpan[betaFirst, betaLast] } ELSE [beta, betaStart, betaLen, betaSize] _ PickNodeSpan[betaTree]; beforeBeta _ nodeI.StepBackward[beta.start.node]; afterBeta _ nodeI.StepForward[beta.end.node]; undoI.Reset[event]; [alphaResult,betaResult] _ spanI.Transpose[alpha, beta, FALSE, event]; IF alpha # alphaResult OR beta # betaResult THEN ERROR; CheckTranspose; undoI.Reset[undoEvent]; undoI.Undo[event, undoEvent]; -- undo the transpose TreeCheck.Verify[alphaTree]; IF alphaTree # betaTree THEN TreeCheck.Verify[betaTree]; CheckSpan[alpha, alphaStart, alphaLen, alphaSize, beforeAlpha, afterAlpha]; CheckSpan[beta, betaStart, betaLen, betaSize, beforeBeta, afterBeta]; undoI.Undo[undoEvent]; -- undo the previous undo CheckTranspose; IF alphaTree # betaTree THEN { AdjustTree[alphaTree, alphaSize+betaLen-alphaLen]; AdjustTree[betaTree, betaSize+alphaLen-betaLen] } ELSE AdjustTree[alphaTree, alphaSize] }; SplitNode: PUBLIC PROC = { CheckSplit: PROC = { TreeCheck.Verify[destTree]; CheckSpan[nodeI.MakeNodeSpan[newNode,newNode], destLoc, 1, destSize+1, before, splitNode] }; destTree: Ref _ PickTree[]; destLoc, destSize, splitLoc: Offset; dest: Location; splitNode: Node; before, after, newNode: Ref; [dest, destLoc, destSize] _ PickNodeLoc[destTree]; after _ nodeI.StepForward[dest.node]; before _ nodeI.StepBackward[dest.node]; splitLoc _ PickOne[splitNode _ nodeI.NarrowToTextNode[dest.node]]; undoI.Reset[event]; newNode _ spanI.Split[[splitNode,splitLoc], event]; CheckSplit; undoI.Reset[undoEvent]; undoI.Undo[event, undoEvent]; -- undo the split TreeCheck.Verify[destTree]; CheckSpan[nodeI.MakeNodeSpan[splitNode,splitNode], destLoc, 1, destSize, before, after]; undoI.Undo[undoEvent]; -- undo the undo CheckSplit; AdjustTree[destTree, destSize+1] }; MergeNodes: PUBLIC PROC = { CheckMerge: PROC = { TreeCheck.Verify[destTree]; IF mergeNode # before THEN ERROR; CheckSpan[nodeI.MakeNodeSpan[mergeNode,mergeNode], destLoc-1, 1, destSize-1, nodeI.StepBackward[before], after] }; destTree: Ref _ PickTree[]; destLoc, destSize: Offset; dest: Location; before, after, destNode, mergeNode: Ref; mergeLoc: Location; [dest, destLoc, destSize] _ PickNodeLoc[destTree]; IF destLoc=0 THEN RETURN; -- no predecessor to merge with destNode _ dest.node; after _ nodeI.StepForward[destNode]; before _ nodeI.StepBackward[destNode]; undoI.Reset[event]; mergeLoc _ spanI.Merge[destNode, event]; mergeNode _ mergeLoc.node; CheckMerge; undoI.Reset[undoEvent]; undoI.Undo[event, undoEvent]; -- undo the merge TreeCheck.Verify[destTree]; CheckSpan[nodeI.MakeNodeSpan[destNode,destNode], destLoc, 1, destSize, before, after]; undoI.Undo[undoEvent]; -- undo the undo CheckMerge; AdjustTree[destTree, destSize-1] }; NestNodes: PUBLIC PROC = { ChangeNesting[1] }; UnNestNodes: PUBLIC PROC = { ChangeNesting[-1] }; ChangeNesting: PROC [change: INTEGER] = { destTree: Ref; dest, result: Span; before, after: Ref; destStart, destLen, destSize: Offset; destTree _ PickTree[]; [dest, destStart, destLen, destSize] _ PickNodeSpan[destTree]; before _ nodeI.StepBackward[dest.start.node]; after _ nodeI.StepForward[dest.end.node]; undoI.Reset[event]; result _ spanI.ChangeNesting[dest, change, event]; IF result # dest THEN ERROR; CheckSpan[dest, destStart, destLen, destSize, before, after]; undoI.Reset[undoEvent]; undoI.Undo[event, undoEvent]; -- undo the change in nesting TreeCheck.Verify[destTree]; CheckSpan[dest, destStart, destLen, destSize, before, after]; undoI.Undo[undoEvent]; -- undo the previous undo CheckSpan[dest, destStart, destLen, destSize, before, after] }; END.