CDRemoteImpl.mesa (part of ChipNDale)
Copyright © 1985, 1987 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, June 5, 1985 8:02:35 pm PDT
Last edited by: Christian Jacobi, February 26, 1987 11:21:26 am PST
DIRECTORY
CD,
CDGenerate,
CDGenerateBackdoor,
CDDirectory,
CDEnvironment,
CDIO,
CDProperties,
CDRemote,
CDSequencer,
CDValue,
FileNames,
RefTab,
Rope,
SymTab,
TerminalIO,
TokenIO,
UserProfile;
CDRemoteImpl: CEDAR PROGRAM
IMPORTS CD, CDGenerate, CDGenerateBackdoor, CDDirectory, CDEnvironment, CDIO, CDProperties, CDSequencer, 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: ROPENIL;
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: ROPENIL] = {
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];
};
};
GetOver: PROC [into: CD.Design, from: CD.Design, ob: CD.Object, key: REFNIL] RETURNS [ob1: CD.Object←NIL] = {
replaceList: CDDirectory.ReplaceList ← NIL;
EachChild: CDDirectory.EachObjectProc = {
IF me.class.composed THEN {
replaceRec: REF CDDirectory.ReplaceRec; ob1: CD.Object;
IF CDDirectory.IsIncluded[from, me] THEN {
ob1 ← CDGenerate.FetchNCall[realContext, design, CDDirectory.Name[me, from]];
--will be cached !!
};
IF ob1=NIL THEN
ob1 ← GetOver[into, from, me, NIL];
IF ob1=NIL THEN ERROR;
replaceRec ← NEW[CDDirectory.ReplaceRec ← [old: me, new: ob1]];
replaceList ← CONS[replaceRec, replaceList];
}
};
ca: BOOL;
[ob1, ca] ← CDDirectory.Another1[me: ob, fromOrNil: from, into: into];
IF ob1#NIL THEN {
IF ~ca THEN {
[] ← CDDirectory.EnumerateChildObjects[me: ob1, proc: EachChild];
IF replaceList#NIL THEN
[] ← CDDirectory.ReplaceDirectChild[me: ob1, design: into, replace: replaceList, propagate: FALSE];
};
IF CDDirectory.IsIncluded[from, ob] THEN
[] ← CDDirectory.Include[design: into, object: ob1, name: CDDirectory.Name[ob, from]];
CDProperties.PutObjectProp[ob1, $CameFrom, from.name];
IF key=NIL THEN key ← CDDirectory.Name[ob, from];
CDProperties.PutObjectProp[ob1, $OriginalName, key];
};
};
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 RETURN [GetOver[into: design, from: remoteDesign, ob: rob, key: key]];
};
};
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 CD.Error[calling];
IF remote.mutability#readonly THEN ERROR CD.Error[designMutability];
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: ROPENIL, 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] = {
Check: PROC [h: TokenIO.Handle] RETURNS [ok: BOOL] = {
design: CD.Design ← CDIO.DesignInReadOperation[h];
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: """, CD.DesignName[design], """\n"]];
}
ELSE TerminalIO.PutRopes["**technology missmatch: remote design is ", design.technology.name, "\n"];
};
name1: ROPE;
x: Rope.ROPE ← " not done";
TerminalIO.PutRopes["load remote design ", remoteName, "\n"];
IF Rope.IsEmpty[fileName] THEN fileName ← MakupName[importer, remoteName];
name1 ← CDEnvironment.FindFile[fileName, ".dale", importer];
IF Rope.IsEmpty[name1] THEN x ← Rope.Cat[" not done; file ", fileName, " not found"]
ELSE {
design ← CDIO.ReadDesign[name1, Check];
IF design#NIL THEN {
ref: REF;
CDSequencer.SetMutability[design, readonly];
ref ← CDValue.Fetch[design, $CDxFromFile, design]; CDValue.Store[design, $CDxCachedFile, ref];
ref ← CDValue.Fetch[design, $CDxFileCreated, design]; CDValue.Store[design, $CDxCachedCreated, ref];
x ← Rope.Cat[" ", remoteName, " loaded\n"];
};
};
TerminalIO.PutRope[x];
};
unspecRemoteContext: CDGenerate.Context ← CDGenerateBackdoor.CreateIndirect[
onTopOf: dummy,
iGenerator: UnspecRemoteIGenerator,
selector: UnspecSelector
];
[] ← SymTab.Insert[CDGenerateBackdoor.publicContexts, "INCLUDE", unspecRemoteContext];
[] ← CDProperties.Register[$CameFrom, [autoRem: TRUE, exclusive: TRUE]];
[] ← CDProperties.Register[$OriginalName, [autoRem: TRUE, exclusive: TRUE]];
END.