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
Last edited by: Christian Jacobi, October 16, 1986 5:33:17 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.
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;
remoteDesign: CD.Design;
remoteInfo: REF NameRec ← RemoteInfo[passTable];
--test for silly case of using same design name
IF Rope.Equal[remoteInfo.name, design.name]
THEN {
ob ← CDDirectory.Fetch[design, key].object;
RETURN
};
remoteDesign ← 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
checkWasCalled: BOOL ← FALSE;
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.ROPE ← CDIO.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.