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.