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: 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];
};
};
GetOver:
PROC [into:
CD.Design, from:
CD.Design, ob:
CD.Object, key:
REF←
NIL]
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:
ROPE ←
NIL, reload:
BOOL ←
FALSE]
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:
ROPE←
NIL] = {
GetHintList:
PROC [for:
CD.Design]
RETURNS [
LIST
OF
ROPE←
NIL] = {
IF for#
NIL
THEN
WITH CDProperties.GetDesignProp[for, $ImportHints]
SELECT
FROM
rL: LIST OF ROPE => RETURN [rL];
ENDCASE => NULL;
};
RemSpaces:
PROC [r:
ROPE]
RETURNS [
ROPE←
NIL] = {
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: ROPE ← NIL;
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:
ROPE←
NIL]
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.