<> <> <> <> <> <> <> DIRECTORY Ascii USING [Lower], Rope USING [InlineFetch, InlineSize, ContainingPiece, Map, NoRope, ROPE, Size, Text], RopePrivate USING [InlineDepth, SingleSize, NonNeg, DoubleSize]; RopeImplExt: CEDAR PROGRAM IMPORTS Ascii, Rope, RopePrivate EXPORTS Rope SHARES Rope = BEGIN OPEN Rope, RopePrivate; <> Run: PUBLIC PROC [s1: ROPE, pos1: INT, s2: ROPE, pos2: INT, case: BOOL _ TRUE] RETURNS [result: INT] = TRUSTED { <> <> <> <> <> <> len1,len2: INT; str1, str2: Text; [len1, str1] _ SingleSize[s1]; [len2, str2] _ SingleSize[s2]; result _ 0; IF NonNeg[pos1] >= len1 OR NonNeg[pos2] >= len2 THEN RETURN; {r1,r2: ROPE _ NIL; st1,sz1,lm1: INT _ 0; st2,sz2,lm2: INT _ 0; c1,c2: CHAR; DO IF st1 = lm1 THEN { <> [r1, st1, sz1] _ ContainingPiece[s1, pos1 _ pos1 + sz1]; IF sz1 = 0 THEN RETURN; lm1 _ st1 + sz1}; IF st2 = lm2 THEN { <> [r2, st2, sz2] _ ContainingPiece[s2, pos2 _ pos2 + sz2]; IF sz2 = 0 THEN RETURN; lm2 _ st2 + sz2}; c1 _ InlineFetch[r1, st1]; c2 _ InlineFetch[r2, st2]; IF case THEN {IF c1 # c2 THEN RETURN} ELSE {IF Ascii.Lower[c1] # Ascii.Lower[c2] THEN RETURN}; result _ result + 1; st1 _ st1 + 1; st2 _ st2 + 1; ENDLOOP; }}; Find: PUBLIC PROC [s1, s2: ROPE, pos1: INT _ 0, case: BOOL _ TRUE] RETURNS [INT] = TRUSTED { index: INT _ Index[s1, pos1, s2, case]; IF index = InlineSize[s1] THEN RETURN [-1]; RETURN [index]; }; Index: PUBLIC PROC [s1: ROPE, pos1: INT, s2: ROPE, case: BOOL _ TRUE] RETURNS [INT] = TRUSTED { <> <= pos1. If s2 does not>> <> <>> <> < s2 does not occur in s1>> <> <> len1,len2, rem: INT; both: BOOL; [len1,len2,both] _ DoubleSize[s1, s2]; rem _ IF pos1 >= len1 THEN 0 ELSE len1 - NonNeg[pos1]; IF rem < len2 THEN RETURN [len1]; IF len2 = 0 THEN RETURN [pos1]; {c: CHAR _ InlineFetch[s2, 0]; Cmp: PROC [cc: CHAR] RETURNS [BOOL] = TRUSTED { IF c = cc AND Run[s1, pos1+1, s2, 1, case]+1 = len2 THEN RETURN [TRUE]; pos1 _ pos1 + 1; RETURN [FALSE]; }; LCmp: PROC [cc: CHAR] RETURNS [BOOL] = TRUSTED { IF c = Ascii.Lower[cc] AND Run[s1, pos1+1, s2, 1, case]+1 = len2 THEN RETURN [TRUE]; pos1 _ pos1 + 1; RETURN [FALSE]; }; rem _ rem - len2 + 1; IF case THEN {IF Map[s1, pos1, rem, Cmp] THEN RETURN [pos1]} ELSE {c _ Ascii.Lower[c]; IF Map[s1, pos1, rem, LCmp] THEN RETURN [pos1]}; }; RETURN [len1]; }; Match: PUBLIC PROC [pattern, object: ROPE, case: BOOL _ TRUE] RETURNS [BOOL] = TRUSTED { <> <> <<0 or more characters will match. Returns FALSE>> <> <> <> <> <> submatch: PROC [i1: INT, len1: INT, i2: INT, len2: INT] RETURNS [BOOL] = TRUSTED { WHILE len1 > 0 DO c1: CHAR _ InlineFetch[pattern, i1]; IF c1 = '* THEN {-- quick kill for * at end of pattern IF len1 = 1 THEN RETURN [TRUE]; <> {-- first, accept the * j1: INT _ i1 + 1; nlen1: INT _ len1 - 1; j2: INT _ i2; nlen2: INT _ len2; WHILE nlen2 >= 0 DO IF submatch[j1, nlen1, j2, nlen2] THEN RETURN [TRUE]; j2 _ j2 + 1; nlen2 _ nlen2 - 1; ENDLOOP; }; RETURN [FALSE]; }; IF len2 <= 0 THEN RETURN [FALSE]; <> {c2: CHAR _ InlineFetch[object, i2]; IF c1 # c2 THEN IF case OR (Ascii.Lower[c1] # Ascii.Lower[c2]) THEN RETURN [FALSE]; }; i1 _ i1 + 1; len1 _ len1 - 1; i2 _ i2 + 1; len2 _ len2 - 1; ENDLOOP; RETURN [len2 = 0]; }; len1: INT _ InlineSize[pattern]; len2: INT _ InlineSize[object]; RETURN [submatch [0, len1, 0, len2]]; }; SkipTo: PUBLIC PROC [s: ROPE, pos: INT, skip: ROPE] RETURNS [INT] = TRUSTED { <> <= pos. If no such character occurs>> <> len: INT _ InlineSize[s]; skiplen: INT _ InlineSize[skip]; CharMatch: PROC [c: CHAR] RETURNS [BOOL] = TRUSTED { SubMatch: PROC [cc: CHAR] RETURNS [BOOL] = TRUSTED {RETURN [c = cc]}; IF Map[skip, 0, skiplen, SubMatch] THEN RETURN [TRUE]; pos _ pos + 1; RETURN [FALSE]}; IF pos < len AND Map[s, pos, len - pos, CharMatch] THEN RETURN [pos]; RETURN [len]; }; SkipOver: PUBLIC PROC [s: ROPE, pos: INT, skip: ROPE] RETURNS [INT] = TRUSTED { <> <= pos. If no such character occurs>> <> len: INT _ InlineSize[s]; skiplen: INT _ InlineSize[skip]; CharMatch: PROC [c: CHAR] RETURNS [BOOL] = TRUSTED { SubMatch: PROC [cc: CHAR] RETURNS [BOOL] = TRUSTED {RETURN [c = cc]}; IF NOT Map[skip, 0, skiplen, SubMatch] THEN RETURN [TRUE]; pos _ pos + 1; RETURN [FALSE]}; IF pos < len AND Map[s, pos, len - pos, CharMatch] THEN RETURN [pos]; RETURN [len]; }; VerifyStructure: PUBLIC PROC [s: ROPE] RETURNS [leaves,nodes,maxDepth: INT] = TRUSTED { <> <> leaves _ 0; maxDepth _ 0; nodes _ 0; IF s = NIL THEN RETURN; WITH x: s SELECT FROM text => {leaves _ 1; IF x.length > x.max THEN ERROR VerifyFailed}; node => WITH x: x SELECT FROM substr => { ref: ROPE _ x.base; len1: INT _ Size[x.base]; IF x.start < 0 OR x.size <= 0 THEN ERROR VerifyFailed; IF len1 < x.start + x.size THEN ERROR VerifyFailed; [leaves, nodes, maxDepth] _ VerifyStructure[ref]; nodes _ nodes + 1}; concat => { leaves1,nodes1,maxDepth1: INT; left: ROPE _ x.base; lSize: INT _ Size[left]; right: ROPE _ x.rest; rSize: INT _ Size[right]; [leaves1, nodes1, maxDepth1] _ VerifyStructure[left]; [leaves, nodes, maxDepth] _ VerifyStructure[right]; leaves _ leaves + leaves1; nodes _ nodes + nodes1 + 1; IF maxDepth1 > maxDepth THEN maxDepth _ maxDepth1; IF x.size # lSize + rSize THEN ERROR VerifyFailed; IF x.pos # lSize THEN ERROR VerifyFailed; }; replace => { leaves1,nodes1,maxDepth1: INT; old: ROPE _ x.base; oldSize: INT _ Size[old]; repl: ROPE _ x.replace; replSize: INT _ Size[repl]; [leaves, nodes, maxDepth] _ VerifyStructure[old]; [leaves1, nodes1, maxDepth1] _ VerifyStructure[repl]; leaves _ leaves + leaves1; nodes _ nodes + nodes1 + 1; IF maxDepth < maxDepth1 THEN maxDepth _ maxDepth1; IF x.start > x.oldPos OR x.start > x.newPos THEN ERROR VerifyFailed; IF x.newPos - x.start # replSize THEN ERROR VerifyFailed; IF x.start < 0 OR x.start > x.size THEN ERROR VerifyFailed; IF x.oldPos > oldSize THEN ERROR VerifyFailed; }; object => { leaves _ 1; IF x.size < 0 OR x.fetch = NIL THEN ERROR VerifyFailed; }; ENDCASE => ERROR NoRope; ENDCASE => ERROR NoRope; maxDepth _ maxDepth + 1; IF maxDepth # InlineDepth[s] THEN ERROR VerifyFailed; }; VerifyFailed: PUBLIC ERROR = CODE; END.