-- TextTestImpl.mesa -- written by Bill Paxton, April 1981 -- last edit by Bill Paxton, 11-Jun-81 15:23:01 -- This module provides random testing for editing Text nodes -- Initially was part of EditTestImpl.mesa DIRECTORY EditTest, TextEdit, RopeEdit, TextNode, RunReader, RopeReader, Rope, RopeInline, RandomLongInt; TextTestImpl: PROGRAM IMPORTS EditTest, TextEdit, RopeEdit, RunReader, RopeReader, Rope, RandomLongInt EXPORTS EditTest = BEGIN OPEN rI:Rope, EditTest, editI:TextEdit, ropeI:RopeEdit, nodeI:TextNode, runrdrI:RunReader, roperdrI:RopeReader, randLI:RandomLongInt; -- ***** Text Edit operations ReplaceText: PUBLIC PROC = { source, dest: Node; destStart, destEnd, sourceStart, sourceEnd: Offset; [source,dest] ← PickNodes[]; [destStart,destEnd] ← PickTwo[dest]; [sourceStart,sourceEnd] ← PickTwo[source]; DoReplaceText[dest, source, destStart, destEnd, sourceStart, sourceEnd]; AdjustLength[dest] }; DoReplaceText: PROC [ dest, source: Node, destStart, destEnd, sourceStart, sourceEnd: Offset] = { destLen, sourceLen, oldPos, newPos, oldSize: Offset; sourceRope, newRope, oldRope: Rope; sourceRuns, newRuns, oldRuns: Runs; sourceRope ← editI.GetRope[source]; sourceRuns ← editI.GetRuns[source]; oldSize ← editI.Size[dest]; oldRope ← editI.GetRope[dest]; oldRuns ← editI.GetRuns[dest]; editI.ReplaceText[ dest,destStart,destLen←destEnd-destStart, source,sourceStart,sourceLen←sourceEnd-sourceStart]; newRope ← editI.GetRope[dest]; newRuns ← editI.GetRuns[dest]; CheckSize[dest,oldSize+sourceLen-destLen]; CheckRopes[newRope,0,oldRope,0,destStart]; CheckRopes[newRope,destStart,sourceRope,sourceStart,sourceLen]; oldPos ← destStart+destLen; newPos ← destStart+sourceLen; CheckRopes[newRope,newPos,oldRope,oldPos,oldSize-oldPos]; CheckRuns[newRuns,0,oldRuns,0,destStart]; CheckRuns[newRuns,destStart,sourceRuns,sourceStart,sourceLen]; CheckRuns[newRuns,newPos,oldRuns,oldPos,oldSize-oldPos] }; DeleteText: PUBLIC PROC = { node: Node ← PickNode[]; DeleteFromNode[node]; AdjustLength[node] }; DeleteFromNode: PUBLIC PROC [node: Node] = { start, end: Offset; [start,end] ← PickTwo[node]; DoReplaceText[node,NIL,start,end,0,0] }; CopyText: PUBLIC PROC = { source, dest: Node; destLoc, sourceStart, sourceEnd: Offset; [source,dest] ← PickNodes[]; [sourceStart,sourceEnd] ← PickTwo[source]; destLoc ← PickOne[dest]; DoReplaceText[dest, source, destLoc, destLoc, sourceStart, sourceEnd]; AdjustLength[dest] }; MoveText: PUBLIC PROC = { source, dest: Node; destLoc, sourceStart, sourceEnd, sourceLen, oldSourceSize, oldDestSize: Offset; oldSourceRope, newSourceRope, oldDestRope, newDestRope: Rope; oldSourceRuns, newSourceRuns, oldDestRuns, newDestRuns: Runs; moveToRight: BOOLEAN; [source,dest] ← PickNodes[]; [sourceStart,sourceEnd] ← PickTwo[source]; IF source=dest THEN { IF moveToRight←RandomBoolean[] THEN { -- move to right size: Offset ← editI.Size[source]; IF size=sourceEnd THEN RETURN; -- cannot move to right destLoc ← randLI.Choose[sourceEnd,size] } ELSE { -- move to left IF sourceStart=0 THEN RETURN; -- cannot move to left destLoc ← randLI.Choose[0,sourceStart] }; oldSourceSize ← oldDestSize ← editI.Size[dest]; oldSourceRope ← oldDestRope ← editI.GetRope[dest]; oldSourceRuns ← oldDestRuns ← editI.GetRuns[dest] } ELSE { destLoc ← PickOne[dest]; oldSourceSize ← editI.Size[source]; oldDestSize ← editI.Size[dest]; oldDestRope ← editI.GetRope[dest]; oldSourceRope ← editI.GetRope[source]; oldDestRuns ← editI.GetRuns[dest]; oldSourceRuns ← editI.GetRuns[source] }; editI.MoveText[dest,destLoc,source,sourceStart,sourceLen←sourceEnd-sourceStart]; IF source=dest THEN { newSourceRope ← editI.GetRope[source]; newSourceRuns ← editI.GetRuns[source]; CheckSize[source,oldSourceSize]; IF moveToRight THEN { -- switch so like moving to left temp: Offset ← destLoc; destLoc ← sourceStart; sourceStart ← sourceEnd; sourceEnd ← temp; sourceLen ← sourceEnd-sourceStart }; CheckRopes[newSourceRope,0,oldSourceRope,0,destLoc]; CheckRopes[newSourceRope,destLoc,oldSourceRope,sourceStart,sourceLen]; CheckRopes[newSourceRope,destLoc+sourceLen,oldSourceRope,destLoc, sourceStart-destLoc]; CheckRopes[newSourceRope,sourceEnd,oldSourceRope,sourceEnd, oldSourceSize-sourceEnd]; CheckRuns[newSourceRuns,0,oldSourceRuns,0,destLoc]; CheckRuns[newSourceRuns,destLoc,oldSourceRuns,sourceStart,sourceLen]; CheckRuns[newSourceRuns,destLoc+sourceLen,oldSourceRuns,destLoc, sourceStart-destLoc]; CheckRuns[newSourceRuns,sourceEnd,oldSourceRuns,sourceEnd, oldSourceSize-sourceEnd] } ELSE { newDestRope ← editI.GetRope[dest]; newSourceRope ← editI.GetRope[source]; newDestRuns ← editI.GetRuns[dest]; newSourceRuns ← editI.GetRuns[source]; CheckSize[source,oldSourceSize-sourceLen]; CheckSize[dest,oldDestSize+sourceLen]; CheckRopes[newDestRope,0,oldDestRope,0,destLoc]; CheckRopes[newDestRope,destLoc,oldSourceRope,sourceStart,sourceLen]; CheckRopes[newDestRope,destLoc+sourceLen,oldDestRope,destLoc, oldDestSize-destLoc]; CheckRopes[newSourceRope,0,oldSourceRope,0,sourceStart]; CheckRopes[newSourceRope,sourceStart,oldSourceRope,sourceEnd, oldSourceSize-sourceEnd]; CheckRuns[newDestRuns,0,oldDestRuns,0,destLoc]; CheckRuns[newDestRuns,destLoc,oldSourceRuns,sourceStart,sourceLen]; CheckRuns[newDestRuns,destLoc+sourceLen,oldDestRuns,destLoc, oldDestSize-destLoc]; CheckRuns[newSourceRuns,0,oldSourceRuns,0,sourceStart]; CheckRuns[newSourceRuns,sourceStart,oldSourceRuns,sourceEnd, oldSourceSize-sourceEnd]; AdjustLengths[] }}; MoveTextOnto: PUBLIC PROC = { source, dest: Node; destStart, destEnd, destLen, sourceStart, sourceEnd, sourceLen, oldSourceSize, oldDestSize: Offset; oldSourceRope, newSourceRope, oldDestRope, newDestRope: Rope; oldSourceRuns, newSourceRuns, oldDestRuns, newDestRuns: Runs; [source,dest] ← PickNodes[]; [sourceStart,sourceEnd] ← PickTwo[source]; [destStart,destEnd] ← PickTwo[dest]; oldSourceSize ← editI.Size[source]; oldDestSize ← editI.Size[dest]; oldDestRope ← editI.GetRope[dest]; oldSourceRope ← editI.GetRope[source]; oldDestRuns ← editI.GetRuns[dest]; oldSourceRuns ← editI.GetRuns[source]; editI.MoveTextOnto[dest,destStart,destLen←destEnd-destStart, source,sourceStart,sourceLen←sourceEnd-sourceStart]; IF source=dest THEN { newSourceRope ← editI.GetRope[source]; newSourceRuns ← editI.GetRuns[source]; IF sourceStart IN [destStart..destEnd) THEN { CheckRopes[newSourceRope,0,oldSourceRope,0,destStart]; CheckRopes[newSourceRope,destStart,oldSourceRope,sourceStart,sourceLen]; CheckRuns[newSourceRuns,0,oldSourceRuns,0,destStart]; CheckRuns[newSourceRuns,destStart,oldSourceRuns,sourceStart,sourceLen]; IF sourceEnd IN [destStart..destEnd] THEN { CheckSize[source,oldSourceSize+sourceLen-destLen]; CheckRopes[newSourceRope,destStart+sourceLen, oldSourceRope,destEnd,oldSourceSize-destEnd]; CheckRuns[newSourceRuns,destStart+sourceLen, oldSourceRuns,destEnd,oldSourceSize-destEnd] } ELSE { CheckSize[source,oldSourceSize+destStart-sourceStart]; CheckRopes[newSourceRope,destStart+sourceLen, oldSourceRope,sourceEnd,oldSourceSize-sourceEnd]; CheckRuns[newSourceRuns,destStart+sourceLen, oldSourceRuns,sourceEnd,oldSourceSize-sourceEnd] }} ELSE IF sourceEnd IN [destStart..destEnd) THEN { CheckSize[source,oldSourceSize+sourceEnd-destEnd]; CheckRopes[newSourceRope,0,oldSourceRope,0,sourceEnd]; CheckRopes[newSourceRope,sourceEnd, oldSourceRope,destEnd,oldSourceSize-destEnd]; CheckRuns[newSourceRuns,0,oldSourceRuns,0,sourceEnd]; CheckRuns[newSourceRuns,sourceEnd, oldSourceRuns,destEnd,oldSourceSize-destEnd] } ELSE IF sourceStart < destStart THEN { IF sourceEnd >= destEnd THEN { CheckSize[source,oldSourceSize]; CheckRopes[newSourceRope,0,oldSourceRope,0,oldSourceSize]; CheckRuns[newSourceRuns,0,oldSourceRuns,0,oldSourceSize] } ELSE { CheckSize[source,oldSourceSize-destLen]; CheckRopes[newSourceRope,0,oldSourceRope,0,sourceStart]; CheckRopes[newSourceRope,sourceStart, oldSourceRope,sourceEnd,destStart-sourceEnd]; CheckRopes[newSourceRope,sourceStart+destStart-sourceEnd, oldSourceRope,sourceStart,sourceLen]; CheckRopes[newSourceRope,destStart, oldSourceRope,destEnd,oldSourceSize-destEnd]; CheckRuns[newSourceRuns,0,oldSourceRuns,0,sourceStart]; CheckRuns[newSourceRuns,sourceStart, oldSourceRuns,sourceEnd,destStart-sourceEnd]; CheckRuns[newSourceRuns,sourceStart+destStart-sourceEnd, oldSourceRuns,sourceStart,sourceLen]; CheckRuns[newSourceRuns,destStart, oldSourceRuns,destEnd,oldSourceSize-destEnd] }} ELSE { CheckSize[source,oldSourceSize-destLen]; CheckRopes[newSourceRope,0,oldSourceRope,0,destStart]; CheckRopes[newSourceRope,destStart, oldSourceRope,sourceStart,sourceLen]; CheckRopes[newSourceRope,destStart+sourceLen, oldSourceRope,destEnd,sourceStart-destEnd]; CheckRopes[newSourceRope,sourceEnd-destLen, oldSourceRope,sourceEnd,oldSourceSize-sourceEnd]; CheckRuns[newSourceRuns,0,oldSourceRuns,0,destStart]; CheckRuns[newSourceRuns,destStart, oldSourceRuns,sourceStart,sourceLen]; CheckRuns[newSourceRuns,destStart+sourceLen, oldSourceRuns,destEnd,sourceStart-destEnd]; CheckRuns[newSourceRuns,sourceEnd-destLen, oldSourceRuns,sourceEnd,oldSourceSize-sourceEnd] }} ELSE { newDestRope ← editI.GetRope[dest]; newSourceRope ← editI.GetRope[source]; newDestRuns ← editI.GetRuns[dest]; newSourceRuns ← editI.GetRuns[source]; CheckSize[source,oldSourceSize-sourceLen]; CheckSize[dest,oldDestSize+sourceLen-destLen]; CheckRopes[newDestRope,0,oldDestRope,0,destStart]; CheckRopes[newDestRope,destStart,oldSourceRope,sourceStart,sourceLen]; CheckRopes[newDestRope,destStart+sourceLen,oldDestRope,destEnd, oldDestSize-destEnd]; CheckRopes[newSourceRope,0,oldSourceRope,0,sourceStart]; CheckRopes[newSourceRope,sourceStart,oldSourceRope,sourceEnd, oldSourceSize-sourceEnd]; CheckRuns[newDestRuns,0,oldDestRuns,0,destStart]; CheckRuns[newDestRuns,destStart,oldSourceRuns,sourceStart,sourceLen]; CheckRuns[newDestRuns,destStart+sourceLen,oldDestRuns,destEnd, oldDestSize-destEnd]; CheckRuns[newSourceRuns,0,oldSourceRuns,0,sourceStart]; CheckRuns[newSourceRuns,sourceStart,oldSourceRuns,sourceEnd, oldSourceSize-sourceEnd]; AdjustLengths[] }}; TransposeText: PUBLIC PROC = { alpha, beta: Node; alphaStart, alphaEnd, betaStart, betaEnd, oldAlphaSize, oldBetaSize, alphaLen, betaLen: Offset; oldAlphaRope, oldBetaRope, newAlphaRope, newBetaRope: Rope; oldAlphaRuns, oldBetaRuns, newAlphaRuns, newBetaRuns: Runs; betaOnRight: BOOLEAN; [alpha,beta] ← PickNodes[]; [alphaStart,alphaEnd] ← PickTwo[alpha]; IF alpha=beta THEN { oldAlphaSize ← oldBetaSize ← editI.Size[alpha]; oldAlphaRope ← oldBetaRope ← editI.GetRope[alpha]; oldAlphaRuns ← oldBetaRuns ← editI.GetRuns[alpha]; IF betaOnRight←RandomBoolean[] THEN { -- pick beta section to right of alpha IF alphaEnd=oldAlphaSize THEN RETURN; -- cannot [betaStart,betaEnd] ← ChooseTwo[alphaEnd,oldAlphaSize] } ELSE { -- pick beta section to left of alpha IF alphaStart=0 THEN RETURN; -- cannot [betaStart,betaEnd] ← ChooseTwo[0,alphaStart] }} ELSE { oldAlphaSize ← editI.Size[alpha]; oldBetaSize ← editI.Size[beta]; oldAlphaRope ← editI.GetRope[alpha]; oldBetaRope ← editI.GetRope[beta]; oldAlphaRuns ← editI.GetRuns[alpha]; oldBetaRuns ← editI.GetRuns[beta]; [betaStart,betaEnd] ← PickTwo[beta] }; editI.TransposeText[ alpha,alphaStart,alphaEnd-alphaStart, beta,betaStart,betaEnd-betaStart]; IF alpha = beta THEN { newAlphaRope ← editI.GetRope[alpha]; newAlphaRuns ← editI.GetRuns[alpha]; CheckSize[alpha,oldAlphaSize]; IF ~betaOnRight THEN { -- switch so like beta section on right temp: Offset ← alphaStart; alphaStart ← betaStart; betaStart ← temp; temp ← alphaEnd; alphaEnd ← betaEnd; betaEnd ← temp }; alphaLen ← alphaEnd-alphaStart; betaLen ← betaEnd-betaStart; CheckRopes[newAlphaRope,0,oldAlphaRope,0,alphaStart]; CheckRopes[newAlphaRope,alphaStart,oldAlphaRope,betaStart,betaLen]; CheckRopes[newAlphaRope,alphaStart+betaLen,oldAlphaRope, alphaEnd,betaStart-alphaEnd]; CheckRopes[newAlphaRope,alphaStart+betaEnd-alphaEnd, oldAlphaRope,alphaStart,alphaLen]; CheckRopes[newAlphaRope,betaEnd,oldAlphaRope,betaEnd, oldAlphaSize-betaEnd]; CheckRuns[newAlphaRuns,0,oldAlphaRuns,0,alphaStart]; CheckRuns[newAlphaRuns,alphaStart,oldAlphaRuns,betaStart,betaLen]; CheckRuns[newAlphaRuns,alphaStart+betaLen,oldAlphaRuns, alphaEnd,betaStart-alphaEnd]; CheckRuns[newAlphaRuns,alphaStart+betaEnd-alphaEnd, oldAlphaRuns,alphaStart,alphaLen]; CheckRuns[newAlphaRuns,betaEnd,oldAlphaRuns,betaEnd, oldAlphaSize-betaEnd] } ELSE { alphaLen ← alphaEnd-alphaStart; betaLen ← betaEnd-betaStart; newBetaRope ← editI.GetRope[beta]; newAlphaRope ← editI.GetRope[alpha]; newBetaRuns ← editI.GetRuns[beta]; newAlphaRuns ← editI.GetRuns[alpha]; CheckSize[alpha,oldAlphaSize-alphaLen+betaLen]; CheckSize[beta,oldBetaSize-betaLen+alphaLen]; CheckRopes[newAlphaRope,0,oldAlphaRope,0,alphaStart]; CheckRopes[newAlphaRope,alphaStart,oldBetaRope,betaStart,betaLen]; CheckRopes[newAlphaRope,alphaStart+betaLen,oldAlphaRope, alphaEnd,oldAlphaSize-alphaEnd]; CheckRopes[newBetaRope,0,oldBetaRope,0,betaStart]; CheckRopes[newBetaRope,betaStart,oldAlphaRope,alphaStart,alphaLen]; CheckRopes[newBetaRope,betaStart+alphaLen,oldBetaRope, betaEnd,oldBetaSize-betaEnd]; CheckRuns[newAlphaRuns,0,oldAlphaRuns,0,alphaStart]; CheckRuns[newAlphaRuns,alphaStart,oldBetaRuns,betaStart,betaLen]; CheckRuns[newAlphaRuns,alphaStart+betaLen,oldAlphaRuns, alphaEnd,oldAlphaSize-alphaEnd]; CheckRuns[newBetaRuns,0,oldBetaRuns,0,betaStart]; CheckRuns[newBetaRuns,betaStart,oldAlphaRuns,alphaStart,alphaLen]; CheckRuns[newBetaRuns,betaStart+alphaLen,oldBetaRuns, betaEnd,oldBetaSize-betaEnd]; AdjustLengths[] }}; ReplaceByChar: PUBLIC PROC = { dest: Node ← PickNode[]; destStart, destEnd, destLen, oldSize, oldPos, newPos: Offset; newRope, oldRope: Rope; newRuns, oldRuns: Runs; inherit: BOOLEAN ← RandomBoolean[]; looks: Looks; IF ~inherit THEN looks ← PickLooks[]; [destStart,destEnd] ← PickTwo[dest]; oldSize ← editI.Size[dest]; oldRope ← editI.GetRope[dest]; oldRuns ← editI.GetRuns[dest]; editI.ReplaceByChar[dest,'#,destStart,destLen←destEnd-destStart,inherit,looks]; newRope ← editI.GetRope[dest]; newRuns ← editI.GetRuns[dest]; CheckSize[dest,oldSize+1-destLen]; CheckRopes[newRope,0,oldRope,0,destStart]; IF editI.FetchChar[dest,destStart] # '# THEN ERROR; oldPos ← destStart+destLen; newPos ← destStart+1; CheckRopes[newRope,newPos,oldRope,oldPos,oldSize-oldPos]; CheckRuns[newRuns,0,oldRuns,0,destStart]; IF ~inherit AND editI.FetchLooks[dest,destStart] # looks THEN ERROR; CheckRuns[newRuns,newPos,oldRuns,oldPos,oldSize-oldPos]; AdjustLength[dest] }; InsertChar: PUBLIC PROC = { dest: Node ← PickNode[]; destLoc: Offset ← PickOne[dest]; oldSize, loc, oldPos, newPos: Offset; newRope, oldRope: Rope; newRuns, oldRuns: Runs; inherit: BOOLEAN ← RandomBoolean[]; looks: Looks; num: NAT ← ChooseNAT[1,20]; -- number of chars to insert IF ~inherit THEN looks ← PickLooks[]; oldSize ← editI.Size[dest]; oldRope ← editI.GetRope[dest]; oldRuns ← editI.GetRuns[dest]; loc ← destLoc; FOR i:NAT IN [0..num) DO editI.InsertChar[dest,'z-i,loc,inherit,looks]; loc ← loc+1; ENDLOOP; newRope ← editI.GetRope[dest]; newRuns ← editI.GetRuns[dest]; CheckSize[dest,oldSize+num]; CheckRopes[newRope,0,oldRope,0,destLoc]; loc ← destLoc; FOR i:NAT IN [0..num) DO IF editI.FetchChar[dest,loc] # 'z-i THEN ERROR; IF ~inherit AND editI.FetchLooks[dest,loc] # looks THEN ERROR; loc ← loc+1; ENDLOOP; oldPos ← destLoc; newPos ← destLoc+num; CheckRopes[newRope,newPos,oldRope,oldPos,oldSize-oldPos]; CheckRuns[newRuns,0,oldRuns,0,destLoc]; CheckRuns[newRuns,newPos,oldRuns,oldPos,oldSize-oldPos]; AdjustLength[dest] }; AppendChar: PUBLIC PROC = { dest: Node ← PickNode[]; inherit: BOOLEAN ← RandomBoolean[]; looks: Looks; loc, oldSize: Offset; newRope, oldRope: Rope; newRuns, oldRuns: Runs; num: NAT ← ChooseNAT[1,20]; -- number of chars to append IF ~inherit THEN looks ← PickLooks[]; oldSize ← editI.Size[dest]; oldRope ← editI.GetRope[dest]; oldRuns ← editI.GetRuns[dest]; FOR i:NAT IN [0..num) DO editI.AppendChar[dest,'Z-i,inherit,looks]; ENDLOOP; newRope ← editI.GetRope[dest]; newRuns ← editI.GetRuns[dest]; CheckSize[dest,oldSize+num]; CheckRopes[newRope,0,oldRope,0,oldSize]; loc ← oldSize; FOR i:NAT IN [0..num) DO IF editI.FetchChar[dest,loc] # 'Z-i THEN ERROR; IF ~inherit AND editI.FetchLooks[dest,loc] # looks THEN ERROR; loc ← loc+1; ENDLOOP; CheckRuns[newRuns,0,oldRuns,0,oldSize]; AdjustLength[dest] }; string: REF READONLY TEXT ← "1234567890123456789012345678901234567890"; stringRope: Rope ← rI.FromString[string]; ReplaceByString: PUBLIC PROC = { dest: Node ← PickNode[]; destStart, destEnd, destLen, oldSize, oldPos, newPos: Offset; newRope, oldRope: Rope; newRuns, oldRuns: Runs; inherit: BOOLEAN ← RandomBoolean[]; looks: Looks; strStart, strEnd, strLen: NAT; oldSize ← editI.Size[dest]; oldRope ← editI.GetRope[dest]; oldRuns ← editI.GetRuns[dest]; IF ~inherit THEN looks ← PickLooks[]; [destStart,destEnd] ← PickTwo[dest]; [strStart,strEnd] ← ChooseTwoNATs[0,string.length]; editI.ReplaceByString[dest,string,strStart,strLen←strEnd-strStart, destStart,destLen←destEnd-destStart,inherit,looks]; newRope ← editI.GetRope[dest]; newRuns ← editI.GetRuns[dest]; CheckSize[dest,oldSize+strLen-destLen]; CheckRopes[newRope,0,oldRope,0,destStart]; CheckRopes[newRope,destStart,stringRope,strStart,strLen]; oldPos ← destStart+destLen; newPos ← destStart+strLen; CheckRopes[newRope,newPos,oldRope,oldPos,oldSize-oldPos]; CheckRuns[newRuns,0,oldRuns,0,destStart]; IF ~inherit AND strLen>0 AND editI.FetchLooks[dest,destStart] # looks THEN ERROR; CheckRuns[newRuns,newPos,oldRuns,oldPos,oldSize-oldPos]; AdjustLength[dest] }; InsertString: PUBLIC PROC = { dest: Node ← PickNode[]; InsertStringInNode[dest]; AdjustLength[dest] }; InsertStringInNode: PUBLIC PROC [dest: Node] = { oldSize: Offset; destLoc: Offset ← PickOne[dest]; inherit: BOOLEAN ← RandomBoolean[]; newRope, oldRope: Rope; newRuns, oldRuns: Runs; looks: Looks; strStart, strEnd, strLen: NAT; IF ~inherit THEN looks ← PickLooks[]; [strStart,strEnd] ← ChooseTwoNATs[0,string.length]; oldSize ← editI.Size[dest]; oldRope ← editI.GetRope[dest]; oldRuns ← editI.GetRuns[dest]; editI.InsertString[dest,string,strStart,strLen←strEnd-strStart, destLoc,inherit,looks]; newRope ← editI.GetRope[dest]; newRuns ← editI.GetRuns[dest]; CheckSize[dest,oldSize+strLen]; CheckRopes[newRope,0,oldRope,0,destLoc]; CheckRopes[newRope,destLoc,stringRope,strStart,strLen]; CheckRopes[newRope,destLoc+strLen,oldRope,destLoc,oldSize-destLoc]; CheckRuns[newRuns,0,oldRuns,0,destLoc]; IF ~inherit AND strLen>0 AND editI.FetchLooks[dest,destLoc] # looks THEN ERROR; CheckRuns[newRuns,destLoc+strLen,oldRuns,destLoc,oldSize-destLoc] }; AppendString: PUBLIC PROC = { dest: Node ← PickNode[]; inherit: BOOLEAN ← RandomBoolean[]; looks: Looks; oldSize: Offset; newRope, oldRope: Rope; newRuns, oldRuns: Runs; strStart, strEnd, strLen: NAT; IF ~inherit THEN looks ← PickLooks[]; [strStart,strEnd] ← ChooseTwoNATs[0,string.length]; oldSize ← editI.Size[dest]; oldRope ← editI.GetRope[dest]; oldRuns ← editI.GetRuns[dest]; editI.AppendString[dest,string,strStart,strLen←strEnd-strStart, inherit,looks]; newRope ← editI.GetRope[dest]; newRuns ← editI.GetRuns[dest]; CheckSize[dest,oldSize+strLen]; CheckRopes[newRope,0,oldRope,0,oldSize]; CheckRopes[newRope,oldSize,stringRope,strStart,strLen]; CheckRuns[newRuns,0,oldRuns,0,oldSize]; IF ~inherit AND strLen>0 AND editI.FetchLooks[dest,oldSize] # looks THEN ERROR; AdjustLength[dest] }; ReplaceByRope: PUBLIC PROC = { dest: Node ← PickNode[]; rope: Rope ← PickRope[]; newRope, oldRope: Rope; newRuns, oldRuns: Runs; destStart, destEnd, destLen, oldSize, oldPos, newPos, ropeLen: Offset; inherit: BOOLEAN ← RandomBoolean[]; looks: Looks; [destStart,destEnd] ← PickTwo[dest]; IF ~inherit THEN looks ← PickLooks[]; oldSize ← editI.Size[dest]; oldRope ← editI.GetRope[dest]; oldRuns ← editI.GetRuns[dest]; ropeLen ← ropeI.Size[rope]; editI.ReplaceByRope[dest,rope,destStart,destLen←destEnd-destStart,inherit,looks]; newRope ← editI.GetRope[dest]; newRuns ← editI.GetRuns[dest]; CheckSize[dest,oldSize+ropeLen-destLen]; CheckRopes[newRope,0,oldRope,0,destStart]; CheckRopes[newRope,destStart,rope,0,ropeLen]; oldPos ← destStart+destLen; newPos ← destStart+ropeLen; CheckRopes[newRope,newPos,oldRope,oldPos,oldSize-oldPos]; CheckRuns[newRuns,0,oldRuns,0,destStart]; IF ~inherit AND ropeLen>0 AND editI.FetchLooks[dest,destStart] # looks THEN ERROR; CheckRuns[newRuns,newPos,oldRuns,oldPos,oldSize-oldPos]; AdjustLength[dest] }; InsertRope: PUBLIC PROC = { dest: Node ← PickNode[]; destLoc: Offset ← PickOne[dest]; oldSize, ropeLen: Offset; rope: Rope ← PickRope[]; newRope, oldRope: Rope; newRuns, oldRuns: Runs; inherit: BOOLEAN ← RandomBoolean[]; looks: Looks; IF ~inherit THEN looks ← PickLooks[]; oldSize ← editI.Size[dest]; oldRope ← editI.GetRope[dest]; oldRuns ← editI.GetRuns[dest]; ropeLen ← ropeI.Size[rope]; editI.InsertRope[dest,rope,destLoc,inherit,looks]; newRope ← editI.GetRope[dest]; newRuns ← editI.GetRuns[dest]; CheckSize[dest,oldSize+ropeLen]; CheckRopes[newRope,0,oldRope,0,destLoc]; CheckRopes[newRope,destLoc,rope,0,ropeLen]; CheckRopes[newRope,destLoc+ropeLen,oldRope,destLoc,oldSize-destLoc]; CheckRuns[newRuns,0,oldRuns,0,destLoc]; IF ~inherit AND ropeLen>0 AND editI.FetchLooks[dest,destLoc] # looks THEN ERROR; CheckRuns[newRuns,destLoc+ropeLen,oldRuns,destLoc,oldSize-destLoc]; AdjustLength[dest] }; AppendRope: PUBLIC PROC = { dest: Node ← PickNode[]; rope: Rope ← PickRope[]; oldSize, ropeLen: Offset; newRope, oldRope: Rope; newRuns, oldRuns: Runs; inherit: BOOLEAN ← RandomBoolean[]; looks: Looks; IF ~inherit THEN looks ← PickLooks[]; oldSize ← editI.Size[dest]; oldRope ← editI.GetRope[dest]; oldRuns ← editI.GetRuns[dest]; ropeLen ← ropeI.Size[rope]; editI.AppendRope[dest,rope,inherit,looks]; newRope ← editI.GetRope[dest]; newRuns ← editI.GetRuns[dest]; CheckSize[dest,oldSize+ropeLen]; CheckRopes[newRope,0,oldRope,0,oldSize]; CheckRopes[newRope,oldSize,rope,0,ropeLen]; CheckRuns[newRuns,0,oldRuns,0,oldSize]; IF ~inherit AND ropeLen>0 AND editI.FetchLooks[dest,oldSize] # looks THEN ERROR; AdjustLength[dest] }; END.