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: Jacobi July 23, 1986 3:00:32 pm PDT
DIRECTORY
CD,
CDGenerate,
CDGenerateBackdoor,
CDDirectory,
CDIO,
CDProperties,
CDRemote,
CDValue,
FileNames,
RefTab,
Rope,
SymTab,
TerminalIO;
CDRemoteImpl: CEDAR PROGRAM
IMPORTS CDGenerate, CDGenerateBackdoor, CDDirectory, CDIO, CDProperties, CDValue, FileNames, 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
dotIndex: INT; remoteName, objectName: Rope.ROPE NIL;
name: Rope.ROPE ← FileNames.GetShortName[key];
dotIndex ← Rope.Index[name, 0, "."]; --the first dot! multiple dots belong to the object name
IF dotIndex < Rope.Length[name] THEN {
objectName ← Rope.Substr[name, dotIndex+1];
remoteName ← Rope.Substr[name, 0, dotIndex]
};
IF ~Rope.IsEmpty[remoteName] AND ~Rope.IsEmpty[objectName] THEN {
table: CDGenerate.Table ← GetTable[remoteName];
ob ← CDGenerate.FetchNCall[table, design, objectName];
}
ELSE TerminalIO.WriteRopes["**tried to access remote with bad syntax; [", key, "]\n"];
END;
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.ROPENIL, reload: BOOLFALSE] 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.ROPENIL] =
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.ROPENIL] RETURNS [design: CD.Design←NIL] =
BEGIN
checkWasCalled: BOOLFALSE;
Check: PROC [design: CD.Design] RETURNS [ok: BOOL] =
BEGIN
checkWasCalled ← TRUE;
IF ok ← design.technology=importer.technology THEN {
ok ← Rope.Equal[remoteName, CDIO.DesignInReadOperation[].name];
IF NOT ok THEN TerminalIO.WriteRope[Rope.Cat["file """, fileName, """ has different design: """, CDIO.DesignInReadOperation[].name, """\n"]];
}
ELSE TerminalIO.WriteRopes["**Technology missmatch: remote design is ", design.technology.name, "\n"];
END;
name1: Rope.ROPE;
TerminalIO.WriteRopes["load remote design ", remoteName, "\n"];
IF Rope.IsEmpty[fileName] THEN fileName ← remoteName;
name1 ← CDIO.MakeName[base: fileName, ext: "dale", wDir: CDIO.GetWorkingDirectory[importer]];
design ← CDIO.ReadDesign[name1, Check];
IF ~checkWasCalled AND design=NIL THEN {
name2: Rope.ROPECDIO.MakeName[base: fileName, ext: "dale", wDir: CDIO.GetWorkingDirectory[NIL]];
IF ~Rope.Equal[name1, name2, FALSE] THEN design ← CDIO.ReadDesign[name2, Check];
};
TerminalIO.WriteRopes["loading remote design ", (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.