RemoteRopeImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) August 20, 1985 11:14:47 am PDT
This module implements access to remote ropes. This module must remain closely coupled to RopeImpl to remain valid.
DIRECTORY
AMBridge USING [TVToLC, GetWorld],
AMTypes USING [Class, Error, TVType, UnderClass, TV],
Basics USING [bytesPerWord],
RemoteRope USING [],
Rope USING [MakeRope, NoRope, ROPE, RopeRep],
RuntimeError USING [BoundsFault],
WorldVM USING [Address, CopyRead, World];
RemoteRopeImpl: CEDAR PROGRAM
IMPORTS AMBridge, AMTypes, Rope, RuntimeError, WorldVM
EXPORTS RemoteRope
SHARES Rope
= BEGIN OPEN Rope, WorldVM;
TV: TYPE = AMTypes.TV;
bytesPerWord: NAT = Basics.bytesPerWord;
RemRope: TYPE = LONG POINTER TO RemRopeRep;
RemRopeRep: TYPE = Rope.RopeRep;
InitSize: NAT = SIZE[TEXT[1]];
Beware: highly machine dependent!
enough to get tag & length for text variant ONLY
SubstrSize: NAT = SIZE[RemRopeRep[node][substr]];
ConcatSize: NAT = SIZE[RemRopeRep[node][concat]];
ReplaceSize: NAT = SIZE[RemRopeRep[node][replace]];
ObjectSize: NAT = SIZE[RemRopeRep[node][object]];
MaxSize: NAT = MAX[SubstrSize, ConcatSize, ReplaceSize, ObjectSize];
enough to hold ANY non-text variant
MinSize: NAT = MIN[SubstrSize, ConcatSize, ReplaceSize, ObjectSize];
enough to determine tag & size of ANY non-text variant
RopeFromTV: PUBLIC PROC [tv: TV] RETURNS [ROPE] = TRUSTED {
size: INT ← RemoteLength[tv];
IF size = 0 THEN RETURN [NIL];
RETURN [Rope.MakeRope[tv, size, LOOPHOLE[RemoteFetch]]];
};
RemoteLength: PUBLIC PROC [tv: TV] RETURNS [len: INT] = TRUSTED {
world: WorldVM.World ← AMBridge.GetWorld[tv];
addr: Address ← AMBridge.TVToLC[tv];
scratch: ARRAY [0..MaxSize) OF CARDINAL;
ptr: LONG POINTER ← @scratch;
remrope: RemRope ← LOOPHOLE[ptr];
class: AMTypes.Class ← AMTypes.UnderClass[AMTypes.TVType[tv]];
SELECT class FROM
nil => RETURN [0];
rope => {};
ENDCASE => ERROR NoRope;
IF addr = 0 THEN RETURN [0];
WorldVM.CopyRead[world, addr, InitSize, ptr]; -- get tag & size
WITH x: remrope SELECT FROM
text => len ← x.length;
node => len ← x.size;
ENDCASE => ERROR NoRope;
};
RemoteFetch: PUBLIC PROC [tv: TV, index: INT] RETURNS [CHAR] = TRUSTED {
world: WorldVM.World ← AMBridge.GetWorld[tv];
addr: Address ← AMBridge.TVToLC[tv];
scratch: ARRAY [0..MaxSize) OF CARDINAL;
ptr: LONG POINTER ← @scratch;
remrope: RemRope ← LOOPHOLE[ptr];
class: AMTypes.Class ← AMTypes.UnderClass[AMTypes.TVType[tv]];
SELECT class FROM
nil => ERROR RuntimeError.BoundsFault;
rope => {};
ENDCASE => ERROR Rope.NoRope;
DO
x: RemRope ← remrope;
IF index < 0 OR addr = 0 THEN ERROR RuntimeError.BoundsFault;
WorldVM.CopyRead[world, addr, InitSize, ptr]; -- get tag & size
WITH x: x SELECT FROM
text => {
i: NAT ← index;
mod: NAT ← i MOD bytesPerWord;
IF index >= x.length THEN ERROR RuntimeError.BoundsFault;
WorldVM.CopyRead[world, addr+SIZE[TEXT[i-mod]], 1, ptr+SIZE[TEXT[0]]];
get word containing char
RETURN[x[mod]];
get the exact character
};
node => {
WorldVM.CopyRead[world, addr, MinSize, ptr]; -- get node tag & size
IF index >= x.size THEN ERROR RuntimeError.BoundsFault;
WITH x: x SELECT FROM
substr => {
WorldVM.CopyRead[world, addr+MinSize, SubstrSize-MinSize, ptr+MinSize];
addr ← LOOPHOLE[x.base];
index ← index + x.start;
};
concat => {
WorldVM.CopyRead[world, addr+MinSize, ConcatSize-MinSize, ptr+MinSize];
IF index < x.pos THEN {addr ← LOOPHOLE[x.base]; LOOP};
addr ← LOOPHOLE[x.rest];
index ← index - x.pos;
};
replace => {
WorldVM.CopyRead[world, addr+MinSize, ReplaceSize-MinSize, ptr+MinSize];
IF index < x.start THEN {addr ← LOOPHOLE[x.base]; LOOP};
IF index < x.newPos THEN {
addr ← LOOPHOLE[x.replace];
index ← index - x.start;
LOOP};
addr ← LOOPHOLE[x.base];
index ← index - x.newPos + x.oldPos;
};
object => ERROR AMTypes.Error[notImplemented, "remote user-defined ropes"];
ENDCASE => ERROR NoRope;
};
ENDCASE => ERROR NoRope;
ENDLOOP;
};
END.