-- RopeReaderImpl.mesa; written by Bill Paxton, January 1981
-- edited by McGregor, February 8, 1983 10:58 am
-- edited by Bill Paxton, December 22, 1981 10:24 am
-- edited by Maxwell, January 5, 1983 12:05 pm
DIRECTORY
RopeReader,
Rope,
RopeInline;
RopeReaderImpl:
CEDAR PROGRAM
IMPORTS Rope, RopeInline
EXPORTS RopeReader
SHARES RopeReader, Rope =
BEGIN OPEN RopeReader, RopeInline;
ReadOffEnd: PUBLIC ERROR = CODE;
ReadChar:
PUBLIC
PROC [reader: Ref, mode: Mode]
RETURNS [char:
CHAR] = {
base: ROPE ← reader.rope;
index, current: Offset ← reader.index+reader.current-reader.first;
after: Offset ← InlineSize[base];
first: Offset ← 0;
OffEnd:
PROC
RETURNS [
CHAR] = {
IF ~reader.charForEndOfRope THEN ERROR ReadOffEnd;
RETURN [reader.endChar]};
SetReader:
PROC = {
reader.index ←
SELECT mode
FROM
get => index+1,
backwards => index-1,
peek, peekbackwards => index,
ENDCASE => ERROR;
reader.current ← reader.first ← reader.after ← 0};
SetInfo:
PROC [txtFlag:
BOOLEAN]
RETURNS [c:
NAT] = {
c ← Short[current];
reader.first ← Short[first];
reader.after ← Short[after];
reader.txtFlag ← txtFlag;
SELECT mode
FROM
get => { reader.current ← c+1; reader.index ← index+first-c };
peekbackwards => { reader.current ← c+1; reader.index ← index+first-c-1 };
backwards => { reader.current ← c; reader.index ← index+first-c-1 };
peek => { reader.current ← c; reader.index ← index+first-c };
ENDCASE => ERROR };
SELECT mode FROM
backwards, peekbackwards =>
IF current=0
THEN
RETURN[OffEnd[]]
ELSE current ← current-1;
get, peek => NULL;
ENDCASE => ERROR;
IF current >= after THEN RETURN[OffEnd[]];
TRUSTED {WHILE base #
NIL
DO
WITH x:base
SELECT
FROM
text => { reader.text ← @x; RETURN [x[SetInfo[TRUE]]] };
node =>
WITH x:x
SELECT
FROM
object =>
IF current < x.size
THEN
WITH x.base
SELECT
FROM
y: Chars => { reader.chars ← y; RETURN [y[SetInfo[FALSE]]] };
ENDCASE => { SetReader; RETURN [x.fetch[x.base, current]] };
substr =>
IF current < x.size
THEN {
offset: Offset;
current ← current + (offset ← x.start);
first ← first + offset; after ← after + offset;
base ← x.base; LOOP };
concat =>
IF current < x.size
THEN {
xpos: Offset;
IF current >= (xpos ← x.pos)
THEN {
current ← current - xpos; after ← after - xpos;
first ← IF first <= xpos THEN 0 ELSE first - xpos;
base ← x.rest; LOOP };
IF after > xpos THEN after ← xpos; base ← x.base; LOOP };
replace =>
IF current < x.size
THEN {
xstart: Offset ← x.start;
newPos, oldPos: Offset;
IF current < xstart
THEN {
IF after > xstart THEN after ← xstart;
base ← x.base; LOOP };
IF current < (newPos ← x.newPos)
THEN {
current ← current - xstart;
after ← MIN[after, newPos] - xstart;
first ← IF first <= xstart THEN 0 ELSE first-xstart;
base ← x.replace; LOOP };
current ← current - newPos + (oldPos ← x.oldPos);
after ← after - newPos + oldPos;
first ← IF first >= newPos THEN first - newPos + oldPos ELSE oldPos;
base ← x.base; LOOP };
ENDCASE => ERROR Rope.NoRope;
ENDCASE => ERROR Rope.NoRope;
EXIT;
ENDLOOP};
RETURN[OffEnd[]]};
END.