<> <> <> <> 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[]; < remote design name>> <<-- entries of type REF NameRec>> NameRec: TYPE = RECORD [name: ROPE, key: REF]; nameToContext: SymTab.Ref _ SymTab.Create[]; < 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 startstart 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.