CDRemoteImpl.mesa (part of ChipNDale)
Copyright © 1985 by Xerox Corporation. All rights reserved.
by Christian Jacobi, June 5, 1985 8:02:35 pm PDT
Last Edited by Christian Jacobi, March 25, 1986 1:15:40 pm PST
DIRECTORY
CD,
CDGenerate,
CDGenerateBackdoor,
CDDirectory,
CDIO,
CDProperties,
CDRemote,
CDValue,
RefTab,
Rope,
SymTab,
TerminalIO;
CDRemoteImpl:
CEDAR
PROGRAM
IMPORTS CDGenerate, CDGenerateBackdoor, CDDirectory, CDIO, CDProperties, CDValue, RefTab, Rope, SymTab, TerminalIO
EXPORTS CDRemote =
BEGIN
--implements two methods of generator tables
--tables as exported from CDRemote: selecting an object from one specific remote design
--table "INCLUDE": generator key is designName.objectName; for any designName
dummy: CDGenerate.Table ← CDGenerate.Create[];
tableToName: RefTab.Ref ← RefTab.Create[];
-- table ==> remote design name
-- entries of type REF NameRec
NameRec: TYPE = RECORD [name: Rope.ROPE, key: REF];
nameToTable: SymTab.Ref ← SymTab.Create[];
-- remote design name ==> table
UnspecSelector: CDGenerateBackdoor.SelectorProc = {
key ← TerminalIO.RequestRope[" include [design.oject] >"];
};
Selector: CDGenerateBackdoor.SelectorProc = {
dName: Rope.ROPE = DesignName[table];
key ← TerminalIO.RequestRope[Rope.Cat[label, " include oject from ", dName, " >"]];
};
UnspecRemoteIGenerator: CDGenerateBackdoor.IGeneratorProc =
--this one even does not know what design to use
BEGIN
dot: INT = TrailingDot[key];
remoteName: Rope.ROPE←NIL;
objectName: Rope.ROPE←NIL;
table: CDGenerate.Table;
IF dot < Rope.Length[key]
THEN {
objectName ← Rope.Substr[key, dot+1];
remoteName ← Rope.Substr[key, 0, dot]
};
IF ~Rope.IsEmpty[remoteName]
AND ~Rope.IsEmpty[objectName]
THEN {
table ← GetTable[remoteName];
ob ← CDGenerate.FetchNCall[table, design, objectName];
}
ELSE TerminalIO.WriteRope["**tried to access remote with bad syntax\n"];
END;
TrailingDot:
PROC [base: Rope.
ROPE]
RETURNS [
INT] = {
--position of last dot
len: INT ← Rope.Length[base];
pos: INT ← len;
WHILE pos > 0
DO
SELECT Rope.Fetch[base, pos ← pos - 1]
FROM
'. => RETURN [pos];
'!, '], '>, '/ => EXIT;
ENDCASE;
ENDLOOP;
RETURN [len];
};
GetTable:
PUBLIC PROC [remoteDesign: Rope.
ROPE]
RETURNS [table: CDGenerate.Table←NIL] =
TRUSTED BEGIN
IF Rope.IsEmpty[remoteDesign] THEN ERROR;
WITH nameToTable.Fetch[remoteDesign].val
SELECT
FROM
t: CDGenerate.Table => RETURN [t]
ENDCASE => NULL;
table ← CDGenerateBackdoor.CreateIndirect[onTopOf: dummy, iGenerator: RemoteIGenerator,
selector: Selector, cache: TRUE, flushThrough: FALSE, clearThrough: FALSE, registerThrough: FALSE];
[] ← tableToName.Insert[
LOOPHOLE[table],
NEW[NameRec ← [name: remoteDesign, key: NEW[INT]] ]
];
IF nameToTable.Insert[remoteDesign, LOOPHOLE[table]] THEN RETURN;
RETURN [GetTable[remoteDesign]] --indirection for concurrency problems
END;
ioFailed: PUBLIC SIGNAL = CODE;
GetTableUsingFile:
PUBLIC PROC [for:
CD.Design, remoteDesign: Rope.
ROPE, remoteFile: Rope.
ROPE ←
NIL, reload:
BOOL ←
FALSE]
RETURNS [CDGenerate.Table] =
--Creates a generator table, "generating" = fetching an object from the remote design.
--Reads remoteDesign if necessary or reload
-- remoteFile defaults to remoteDesign
-- re-reading may cause children objects to be duplicated
BEGIN
remote: CD.Design ← NIL;
IF ~reload THEN remote ← FetchDesign[for, remoteDesign];
IF remote=
NIL
THEN {
remote ← DoLoad[importer: for, remoteName: remoteDesign, fileName: remoteFile];
IF remote#NIL THEN CacheDesign[for, remote] ELSE SIGNAL ioFailed;
};
RETURN [ GetTable[remoteDesign] ];
END;
Get:
PUBLIC
PROC [for:
CD.Design, remoteDesign: Rope.
ROPE, object: Rope.
ROPE]
RETURNS [ob:
CD.Object] =
BEGIN
table: CDGenerate.Table = GetTable[remoteDesign];
ob ← CDGenerate.FetchNCall[table, for, object];
END;
RemoteInfo:
PROC [table: CDGenerate.Table]
RETURNS [r:
REF NameRec←
NIL] =
TRUSTED BEGIN
WITH tableToName.Fetch[
LOOPHOLE[table]].val
SELECT
FROM
rn: REF NameRec => RETURN [rn];
ENDCASE => {
table ← CDGenerateBackdoor.Indiretee[table];
IF table#NIL THEN RETURN[RemoteInfo[table]]
};
END;
DesignName:
PUBLIC
PROC [table: CDGenerate.Table]
RETURNS [r: Rope.
ROPE←
NIL] =
BEGIN
rn: REF NameRec ← RemoteInfo[table];
IF rn#NIL THEN RETURN [rn.name]
END;
RemoteIGenerator: CDGenerateBackdoor.IGeneratorProc =
BEGIN
replaceList: CDDirectory.ReplaceList ← NIL;
GetOrLoad:
PROC [importer:
CD.Design, remoteInfo:
REF NameRec]
RETURNS [design:
CD.Design←
NIL] =
BEGIN
IF remoteInfo=
NIL
OR Rope.IsEmpty[remoteInfo.name]
THEN {
TerminalIO.WriteRope["**generate with bad remote name\n"];
RETURN
};
WITH CDValue.Fetch[boundTo: importer, key: remoteInfo.key]
SELECT
FROM
d: CD.Design => design ← d;
ENDCASE => NULL;
IF design=
NIL
THEN {
design ← DoLoad[importer, remoteInfo.name];
CDValue.Store[boundTo: importer, key: remoteInfo.key, value: design];
};
END;
EachChild: CDDirectory.EnumerateObjectsProc
= -- PROC [me: CD.Object, x: REF] --
BEGIN
IF me.class.inDirectory
THEN {
name: Rope.ROPE ← CDDirectory.Name[me];
ob1: CD.Object ← CDGenerate.FetchNCall[realTable, design, name];--will be cached!
replaceRec:
REF CDDirectory.ReplaceRec ←
NEW[CDDirectory.ReplaceRec ← [
old: me,
oldSize: me.size,
new: ob1,
newSize: ob1.size,
off: [0, 0]
]];
replaceList ← CONS[replaceRec, replaceList];
}
END;
remoteInfo: REF NameRec ← RemoteInfo[passTable];
remoteDesign: CD.Design ← GetOrLoad[design, remoteInfo];
IF remoteDesign#
NIL
THEN {
rob: CD.Object ← CDDirectory.Fetch[remoteDesign, key].object;
IF rob#
NIL
THEN {
tm, cm: CDDirectory.DMode;
[ob, tm, cm] ← CDDirectory.Another[me: rob, fromOrNil: remoteDesign, into: design];
IF ob#
NIL
THEN {
IF cm=immutable
THEN {
CDDirectory.EnumerateChildObjects[me: ob, p: EachChild];
IF replaceList#
NIL
THEN
[] ← CDDirectory.ReplaceDirectChild[me: ob, design: design, replace: replaceList];
};
IF tm=ready THEN [] ← CDDirectory.Include[design: design, object: ob];
CDProperties.PutObjectProp[ob, $CameFrom, remoteDesign.name];
CDProperties.PutObjectProp[ob, $OriginalName, key];
RETURN [ob]
};
};
};
END;
CacheDesign:
PUBLIC
PROC [for:
CD.Design, remote:
CD.Design] =
--caller MUST guarantee: remote will NEVER be changed
-- (but a different design with the same name might be cached later...)
--CDRemote guarantees: it will never change remote
BEGIN
rn: REF NameRec;
IF for.technology#remote.technology THEN ERROR;
rn ← RemoteInfo[GetTable[remote.name]];
IF rn#NIL THEN CDValue.Store[boundTo: for, key: rn.key, value: remote]
ELSE
TerminalIO.WriteRope["**CacheRemoteDesign failed; debugging is appropriate\n"];
END;
FetchDesign:
PUBLIC
PROC [for:
CD.Design, name: Rope.
ROPE]
RETURNS [remote:
CD.Design ←
NIL] =
BEGIN
rn: REF NameRec ← RemoteInfo[GetTable[name]];
WITH CDValue.Fetch[boundTo: for, key: rn.key, propagation: design]
SELECT
FROM
d: CD.Design => remote ← d
ENDCASE => NULL;
END;
DoLoad:
PROC [importer:
CD.Design, remoteName: Rope.
ROPE, fileName: Rope.
ROPE←
NIL]
RETURNS [design:
CD.Design←
NIL] =
BEGIN
Check:
PROC [design:
CD.Design]
RETURNS [ok:
BOOL] =
BEGIN
ok ← design.technology=importer.technology;
IF
NOT ok
THEN {
TerminalIO.WriteRopes["Technology missmatch: remote design is ", design.technology.name, "\n"];
RETURN
};
ok ← Rope.Equal[remoteName, CDIO.DesignInReadOperation[].name];
IF
NOT ok
THEN {
TerminalIO.WriteRope[Rope.Cat["file """, fileName, """ has different design: """, CDIO.DesignInReadOperation[].name, """\n"]];
};
END;
wDir: Rope.ROPE ← CDIO.GetWorkingDirectory[importer];
TerminalIO.WriteRope["load a remote design\n"];
IF Rope.IsEmpty[fileName] THEN fileName ← remoteName;
design ← CDIO.ReadDesign[CDIO.MakeName[base: fileName, ext: "dale", wDir: wDir], Check];
TerminalIO.WriteRope["loading remote design "];
TerminalIO.WriteRope[(IF design#NIL THEN "done\n" ELSE "not done\n")];
END;
unspecRemoteTable: CDGenerate.Table ← CDGenerateBackdoor.CreateIndirect[
onTopOf: dummy,
iGenerator: UnspecRemoteIGenerator,
selector: UnspecSelector
];
TRUSTED {
[] ← SymTab.Insert[CDGenerateBackdoor.publicTables, "INCLUDE", LOOPHOLE[unspecRemoteTable]];
};
[] ← CDProperties.RegisterAndInstall[$CameFrom, [autoRem: TRUE]];
[] ← CDProperties.RegisterAndInstall[$OriginalName, [autoRem: TRUE]];
END.