<> <> <> <<>> <> 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]]; <> <> 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]; <> MinSize: NAT = MIN[SubstrSize, ConcatSize, ReplaceSize, ObjectSize]; <> 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]]]; <> RETURN[x[mod]]; <> }; 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.