TiogaRopesImpl.mesa
Mike Spreitzer August 5, 1986 4:26:06 pm PDT
Last tweaked by Mike Spreitzer on November 30, 1987 3:50:09 pm PST
DIRECTORY Basics, Rope, RuntimeError, TextNode, TiogaRopes;
TiogaRopesImpl: CEDAR PROGRAM
IMPORTS Rope, RuntimeError, TextNode
EXPORTS TiogaRopes
=
BEGIN OPEN TiogaRopes;
Location: TYPE = TextNode.Location;
TiogaRope: TYPE = REF TiogaRopePrivate;
TiogaRopePrivate: TYPE = RECORD [
node: Node,
start, length: INT,
skipCommentNode: BOOL,
curNode: Node ← NIL,
curNodeStart, curNodeLength: INT ← 0,
curRope: ROPE
];
RopeFromTioga: PUBLIC PROC [node: Node, start: INT ← 0, length: INTLAST[INT], skipCommentNode: BOOLFALSE] RETURNS [asRope: ROPE] = {
end: Location = DocEnd[node, skipCommentNode];
nodeLoc: Location = [node, 0];
remSize: INT = TextNode.LocOffset[nodeLoc, end, 1, skipCommentNode];
IF start >= remSize THEN RETURN [NIL];
{curRope: ROPE = node.NodeRope[];
tr: TiogaRope = NEW [TiogaRopePrivate ← [
node: node,
start: start,
length: MIN[length, remSize - start],
skipCommentNode: skipCommentNode,
curNode: node,
curNodeStart: 0,
curNodeLength: curRope.Length[],
curRope: curRope
]];
asRope ← Rope.MakeRope[tr, tr.length, FetchFromTiogaRope, NIL, MoveFromTiogaRope];
}};
JumpTo: PROC [tr: TiogaRope, index: INT] = {
newOffset: INT = tr.start+index;
here: Location = IF newOffset >= tr.curNodeStart/2 THEN LocRelative[[tr.curNode, 0], newOffset-tr.curNodeStart, 1, tr.skipCommentNode] ELSE LocRelative[[tr.node, 0], newOffset, 1, tr.skipCommentNode];
tr.curNode ← here.node;
tr.curNodeStart ← newOffset - here.where;
tr.curRope ← TextNode.NodeRope[tr.curNode];
tr.curNodeLength ← tr.curRope.Length[];
};
LocRelative: PROC [location: Location, count: INT,
break: NAT ← 1, skipCommentNodes: BOOLFALSE] RETURNS [rel: Location] = {
SELECT count FROM
=0 => rel ← location --avoid the bogosity in TextNodeImpl.LocRelative--;
>0 => rel ← TextNode.LocRelative[location, count, break, skipCommentNodes];
<0 => {--TextNodeImpl.LocRelative won't backup over node boundaries
backParent: Node ← NIL;
rel ← location;
WHILE count + rel.where < 0 DO
count ← count + rel.where;
[rel.node, backParent, ] ← TextNode.Backward[rel.node, backParent];
rel.where ← IF (NOT skipCommentNodes) OR (NOT rel.node.comment) THEN rel.node.rope.Length[] + break ELSE 0;
ENDLOOP;
rel.where ← count + rel.where;
};
ENDCASE => ERROR;
rel ← rel;
};
FetchFromTiogaRope: PROC [data: REF, index: INT] RETURNS [CHAR] --Rope.FetchType-- = {
tr: TiogaRope = NARROW[data];
IF NOT index IN [0 .. tr.length) THEN ERROR RuntimeError.BoundsFault;
{rel: INT ← index+tr.start - tr.curNodeStart;
{IF rel<0 THEN GOTO Fixit;
SELECT tr.curNodeLength FROM
>rel => GOTO TakeIt;
=rel => RETURN ['\n];
ENDCASE => GOTO Fixit;
EXITS
Fixit => {
JumpTo[tr, index];
rel ← index+tr.start - tr.curNodeStart;
IF rel=tr.curNodeLength THEN RETURN ['\n]};
TakeIt => NULL};
RETURN [tr.curRope.InlineFetch[rel]]}};
MoveFromTiogaRope: UNSAFE PROC [block: Basics.UnsafeBlock, data: REF ANY, start: INT] RETURNS [charsMoved: INT ← 0] ~ CHECKED {
tr: TiogaRope = NARROW[data];
IF NOT start IN [0 .. tr.length) THEN ERROR RuntimeError.BoundsFault;
WHILE block.count>0 DO
rel: INT ← start + tr.start - tr.curNodeStart;
IF rel NOT IN [0 .. tr.curNodeLength] THEN {JumpTo[tr, start]; rel ← start + tr.start - tr.curNodeStart};
IF rel < tr.curNodeLength THEN {
n: INT;
TRUSTED {n ← Rope.UnsafeMoveChars[block: block, rope: tr.curRope, start: rel]};
start ← start + n;
charsMoved ← charsMoved + n;
block.startIndex ← block.startIndex + n;
block.count ← block.count - n;
};
IF block.count # 0 THEN {
TRUSTED {LOOPHOLE[block.base, LONG POINTER TO Basics.RawChars][block.startIndex] ← '\n};
start ← start + 1;
charsMoved ← charsMoved + 1;
block.startIndex ← block.startIndex + 1;
block.count ← block.count - 1;
};
ENDLOOP;
RETURN};
DocEnd: PROC [node: Node, skipCommentNode: BOOL] RETURNS [endLoc: Location] = {
endNode: Node ← TextNode.Root[node];
IF endNode = NIL THEN ERROR;
DO
next: Node ← TextNode.LastChild[endNode];
IF next = NIL THEN EXIT;
endNode ← next;
ENDLOOP;
IF skipCommentNode THEN WHILE endNode.comment DO endNode ← TextNode.StepBackward[endNode] ENDLOOP;
endLoc ← [endNode, TextNode.NodeRope[endNode].Length[]+1];
};
END.