CDRemoteImpl.mesa (part of ChipNDale)
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, June 5, 1985 8:02:35 pm PDT
Last edited by: Christian Jacobi, October 20, 1986 12:56:51 pm PDT
DIRECTORY
CD,
CDGenerate,
CDGenerateBackdoor,
CDDirectory,
CDEnvironment,
CDIO,
CDProperties,
CDRemote,
CDValue,
FileNames,
RefTab,
Rope,
SymTab,
TerminalIO,
TokenIO,
UserProfile;
CDRemoteImpl: CEDAR PROGRAM
IMPORTS CDGenerate, CDGenerateBackdoor, CDDirectory, CDEnvironment, CDIO, CDProperties, CDValue, FileNames, RefTab, Rope, SymTab, TerminalIO, UserProfile
EXPORTS CDRemote =
BEGIN
--implements two methods of generator contexts
--contexts as exported from CDRemote: selecting an object from one specific remote design
--context "INCLUDE": generator key is designName.objectName; for any designName
ROPE: TYPE = Rope.ROPE;
dummy: CDGenerate.Context ← CDGenerate.Create[];
contextToName: RefTab.Ref ← RefTab.Create[];
-- context ==> remote design name
-- entries of type REF NameRec
NameRec: TYPE = RECORD [name: ROPE, key: REF];
nameToContext: SymTab.Ref ← SymTab.Create[];
-- remote design name ==> context
UnspecSelector: CDGenerateBackdoor.SelectorProc = {
key ← TerminalIO.RequestRope[" include [design.oject] >"];
};
Selector: CDGenerateBackdoor.SelectorProc = {
dName: ROPE = DesignName[context];
key ← TerminalIO.RequestRope[Rope.Cat[label, " include oject from ", dName, " >"]];
};
UnspecRemoteIGenerator: CDGenerateBackdoor.IGeneratorProc = {
--this one even does not know what design to use
dotIndex: INT; remoteName, objectName: ROPE NIL;
name: 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 {
context: CDGenerate.Context ← GetContext[remoteName];
ob ← CDGenerate.FetchNCall[context, design, objectName];
}
ELSE TerminalIO.PutRopes["**tried to access remote with bad syntax; [", key, "]\n"];
};
GetContext: PUBLIC PROC [remoteDesign: ROPE] RETURNS [context: CDGenerate.Context←NIL] = {
IF Rope.IsEmpty[remoteDesign] THEN ERROR;
WITH nameToContext.Fetch[remoteDesign].val SELECT FROM
t: CDGenerate.Context => RETURN [t]
ENDCASE => NULL;
context ← CDGenerateBackdoor.CreateIndirect[onTopOf: dummy, iGenerator: RemoteIGenerator,
selector: Selector, cache: TRUE, flushThrough: FALSE, clearThrough: FALSE, registerThrough: FALSE];
[] ← contextToName.Insert[context,
NEW[NameRec ← [name: remoteDesign, key: NEW[INT]] ]
];
IF nameToContext.Insert[remoteDesign, context] THEN RETURN;
RETURN [GetContext[remoteDesign]] --indirection for concurrency problems
};
Get: PUBLIC PROC [for: CD.Design, remoteDesign: ROPE, object: ROPE] RETURNS [ob: CD.Object] = {
context: CDGenerate.Context = GetContext[remoteDesign];
ob ← CDGenerate.FetchNCall[context, for, object];
};
RemoteInfo: PROC [context: CDGenerate.Context] RETURNS [r: REF NameRec←NIL] = {
WITH contextToName.Fetch[context].val SELECT FROM
rn: REF NameRec => RETURN [rn];
ENDCASE => {
context ← CDGenerateBackdoor.Indiretee[context];
IF context#NIL THEN RETURN[RemoteInfo[context]]
};
};
DesignName: PUBLIC PROC [context: CDGenerate.Context] RETURNS [r: ROPE←NIL] = {
rn: REF NameRec ← RemoteInfo[context];
IF rn#NIL THEN RETURN [rn.name]
};
RemoteIGenerator: CDGenerateBackdoor.IGeneratorProc = {
replaceList: CDDirectory.ReplaceList ← NIL;
GetOrLoad: PROC [importer: CD.Design, remoteInfo: REF NameRec] RETURNS [design: CD.Design←NIL] = {
IF remoteInfo=NIL OR Rope.IsEmpty[remoteInfo.name] THEN {
TerminalIO.PutRope["**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];
CacheDesign[importer, design];
};
};
EachChild: CDDirectory.EnumerateObjectsProc = { -- PROC [me: CD.Object, x: REF] --
IF me.class.inDirectory THEN {
name: ROPE ← CDDirectory.Name[me];
ob1: CD.Object ← CDGenerate.FetchNCall[realContext, design, name];--will be cached!
replaceRec: REF CDDirectory.ReplaceRec ← NEW[CDDirectory.ReplaceRec ← [old: me, new: ob1]];
replaceList ← CONS[replaceRec, replaceList];
}
};
remoteDesign: CD.Design;
remoteInfo: REF NameRec ← RemoteInfo[passContext];
--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]
};
};
};
};
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
rn: REF NameRec ← RemoteInfo[GetContext[remote.name]];
IF for.technology#remote.technology THEN ERROR;
IF rn#NIL THEN CDValue.Store[boundTo: for, key: rn.key, value: remote]
ELSE
TerminalIO.PutRope["**CacheRemoteDesign failed; debugging is appropriate\n"];
};
FetchDesign: PUBLIC PROC [for: CD.Design, name: ROPE] RETURNS [remote: CD.Design ← NIL] = {
rn: REF NameRec ← RemoteInfo[GetContext[name]];
WITH CDValue.Fetch[boundTo: for, key: rn.key, propagation: design] SELECT FROM
d: CD.Design => remote ← d
ENDCASE => NULL;
};
IsCached: PUBLIC PROC [for: CD.Design, remoteDesign: ROPE] RETURNS [BOOL] = {
RETURN [FetchDesign[for, remoteDesign]#NIL]
};
ForgetCache: PUBLIC PROC [for: CD.Design, remoteDesign: ROPE] = {
rn: REF NameRec ← RemoteInfo[GetContext[remoteDesign]];
CDValue.Store[boundTo: for, key: rn.key, value: NIL]
};
LoadCache: PUBLIC PROC [for: CD.Design, remoteDesign: ROPE, remoteFile: ROPE NIL, reload: BOOLFALSE] RETURNS [loaded: BOOL] = {
d: CD.Design;
IF ~reload AND IsCached[for, remoteDesign] THEN RETURN [TRUE];
d ← DoLoad[for, remoteDesign, remoteFile];
IF loaded←(d#NIL) THEN CacheDesign[for, d];
};
MakupName: PUBLIC PROC [for: CD.Design, remoteDesign: ROPE] RETURNS [f: ROPENIL] = {
GetHintList: PROC [for: CD.Design] RETURNS [LIST OF ROPENIL] = {
IF for#NIL THEN
WITH CDProperties.GetDesignProp[for, $ImportHints] SELECT FROM
rL: LIST OF ROPE => RETURN [rL];
ENDCASE => NULL;
};
RemSpaces: PROC [r: ROPE] RETURNS [ROPENIL] = {
leng: INT ← Rope.Length[r];
start: INT ← 0;
WHILE start<leng AND Rope.Fetch[r, start]=' DO start ← start+1 ENDLOOP;
WHILE leng>start AND Rope.Fetch[r, leng-1]=' DO leng ← leng-1 ENDLOOP;
IF leng>start THEN RETURN [Rope.Substr[r, start, leng-start]];
};
rl: LIST OF ROPE ← GetHintList[for];
key, rest: ROPENIL;
FOR list: LIST OF ROPE ← rl, list.rest WHILE list#NIL DO
[key, rest] ← CDEnvironment.SplitLine[list.first];
IF Rope.Equal[remoteDesign, key] THEN RETURN [RemSpaces[rest]];
ENDLOOP;
f ← UserProfile.Token[Rope.Cat["ChipNDale.ImportFor.", remoteDesign], remoteDesign];
};
DoLoad: PROC [importer: CD.Design, remoteName: ROPE, fileName: ROPENIL] RETURNS [design: CD.Design←NIL] = {
checkWasCalled: BOOLFALSE;
Check: PROC [h: TokenIO.Handle] RETURNS [ok: BOOL] = {
design: CD.Design ← CDIO.DesignInReadOperation[h];
checkWasCalled ← TRUE;
IF ok ← design.technology=importer.technology THEN {
ok ← Rope.Equal[remoteName, design.name];
IF NOT ok THEN TerminalIO.PutRope[Rope.Cat["file """, fileName, """ has different design: """, design.name, """\n"]];
}
ELSE TerminalIO.PutRopes["**technology missmatch: remote design is ", design.technology.name, "\n"];
};
name1: ROPE;
TerminalIO.PutRopes["load remote design ", remoteName, "\n"];
IF Rope.IsEmpty[fileName] THEN fileName ← MakupName[importer, remoteName];
name1 ← CDIO.MakeName[base: fileName, ext: "dale", wDir: CDIO.GetWorkingDirectory[importer]];
design ← CDIO.ReadDesign[name1, Check];
IF ~checkWasCalled AND design=NIL THEN {
name2: ROPECDIO.MakeName[base: fileName, ext: "dale", wDir: CDIO.GetWorkingDirectory[NIL]];
IF ~Rope.Equal[name1, name2, FALSE] THEN design ← CDIO.ReadDesign[name2, Check];
};
TerminalIO.PutRopes["loading remote design ", (IF design#NIL THEN "done\n" ELSE "not done\n")];
};
unspecRemoteContext: CDGenerate.Context ← CDGenerateBackdoor.CreateIndirect[
onTopOf: dummy,
iGenerator: UnspecRemoteIGenerator,
selector: UnspecSelector
];
[] ← SymTab.Insert[CDGenerateBackdoor.publicContexts, "INCLUDE", unspecRemoteContext];
[] ← CDProperties.Register[$CameFrom, [autoRem: TRUE]];
[] ← CDProperties.Register[$OriginalName, [autoRem: TRUE]];
END.