CDImportCommands.mesa (part of ChipNDale)
Copyright © 1984, 1987, 1988 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, March 20, 1984 5:50:51 pm PST
Last edited by: Christian Jacobi, February 26, 1988 1:45:09 pm PST
Don Curry February 18, 1988 4:47:15 pm PST
DIRECTORY
CD,
CDCellsInteractions,
CDEnvironment,
CDDesignCache,
CDDirectory,
CDImports,
CDInstances,
CDIO,
CDMenuSpecials,
CDOps,
CDProperties,
CDSequencer,
IO,
Process USING [PauseMsec],
RefTab,
Rope,
SymTab,
TerminalIO,
TokenIO;
CDImportCommands: CEDAR PROGRAM
IMPORTS CD, CDCellsInteractions, CDDesignCache, CDDirectory, CDEnvironment, CDImports, CDInstances, CDIO, CDMenuSpecials, CDOps, CDProperties, CDSequencer, IO, Process, RefTab, Rope, SymTab, TerminalIO
SHARES CDDirectory, CDImports =
BEGIN
ROPE: TYPE = Rope.ROPE;
ImportSpecific: TYPE = CDImports.ImportSpecific;
ImportRep: TYPE = CDImports.ImportRep;
CacheListRec: TYPE = CDImports.CacheListRec;
Cache: TYPE = CDImports.Cache;
CacheList: TYPE = CDImports.CacheList;
HasCachedImports: PROC [into: CD.Design] RETURNS [BOOL] = INLINE --gfi-- {
cacheL: CDImports.CacheList ← CDImports.GetCacheList[into];
RETURN [cacheL#NIL AND cacheL^#NIL]
};
SymTabToKeyList: PROC [ref: SymTab.Ref] RETURNS [list: LIST OF ROPENIL] = INLINE --gfi-- {
Each: SymTab.EachPairAction = {list ← CONS[key, list]};
[] ← SymTab.Pairs[ref, Each];
};
RequestImporteeName: PROC [into: CD.Design, restrictedToCaches: BOOLTRUE, fastIfNoChoice: BOOLFALSE, offerAll: ROPENIL] RETURNS [importeeName: ROPENIL] = {
--requests a design name for imports into "into"
--restrictedToCaches:
-- FALSE => user may type any name; the name of the selected design is included in list
-- TRUE => only designs having a cache entry in into are allowed
--fastIfNoChoice:
-- FALSE => user sees always an interactive selection querry
-- TRUE => if only a single option exists it is returned without bothering user
--offerAll: offers to say offerAll if there is more than one cached import
optionsList: LIST OF ROPE;
options: SymTab.Ref ← FindAllImportCaches[into];
--deal with selected design
IF ~restrictedToCaches THEN {
name: ROPENIL;
d: CD.Design ← SelectedDesign[];
IF d#NIL THEN name ← d.name;
IF ~Rope.IsEmpty[name] AND ~Rope.Equal[name, into.name] THEN
[] ← SymTab.Insert[options, name, name]
};
optionsList ← SymTabToKeyList[options];
IF ~Rope.IsEmpty[offerAll] AND optionsList#NIL THEN {
optionsList ← CONS[offerAll, optionsList];
};
IF fastIfNoChoice AND restrictedToCaches AND SymTab.GetSize[options]=1 THEN {
IF ~Rope.IsEmpty[importeeName] THEN RETURN [importeeName];
};
importeeName ← CDMenuSpecials.SelectOneOf[optionsList, "DESIGN name", ~restrictedToCaches];
};
LoadAndGetCache: PROC [into: CD.Design, importeeName: ROPENIL, allwaysNewFile: BOOLFALSE, forceBind: BOOLFALSE, offerAll: BOOLFALSE] RETURNS [cache: Cache←NIL, done: BOOLFALSE] = {
checkCalled: BOOLFALSE;
r, fn: ROPE;
design: CD.Design←NIL;
loaded: BOOLFALSE;
IF Rope.IsEmpty[importeeName] THEN
importeeName ← RequestImporteeName[into: into, restrictedToCaches: FALSE, fastIfNoChoice: FALSE, offerAll: IF offerAll THEN "<all cached imports>" ELSE NIL];
IF Rope.IsEmpty[importeeName] THEN {
TerminalIO.PutRopes["no design name specified\n"]; RETURN
};
IF Rope.Equal[importeeName, "<all cached imports>"] THEN {
BindAll[into, interactive];
TerminalIO.PutRope[" --\n"];
RETURN [NIL, TRUE];
};
IF Rope.Equal[importeeName, into.name] THEN {
TerminalIO.PutRopes["a design can't import itself\n"]; RETURN
};
cache ← CDImports.GetCache[into: into, importeeName: importeeName];
IF cache=NIL OR cache.importee=NIL OR allwaysNewFile THEN {
menuHeader: ROPE ← Rope.Cat["FILE name for ", importeeName];
menuChoice: LIST OF ROPELIST[importeeName];
IF cache#NIL AND cache.importee#NIL THEN
TerminalIO.PutRopes["reload and cache design ", importeeName, "\n"];
fn ← CDDesignCache.MakeUpFile[into, importeeName];
IF ~Rope.IsEmpty[fn] THEN menuChoice ← CONS[fn, menuChoice];
r ← CDMenuSpecials.SelectOneOf[menuChoice, menuHeader, TRUE];
IF Rope.IsEmpty[r] THEN {TerminalIO.PutRope["discarded\n"]; RETURN};
fn ← CDEnvironment.FindFile[r, ".dale", into];
IF Rope.IsEmpty[fn] THEN TerminalIO.PutRopes["file ", r, " not found\n"]
ELSE loaded ← CDImports.LoadAndBindDesign[into: into, importeeName: importeeName, forceBind: forceBind, allowConflicts: interactive, useCache: FALSE, fileName: fn, forceFile: TRUE];
IF loaded THEN cache ← CDImports.GetCache[into: into, importeeName: importeeName];
};
done ← cache#NIL;
};
--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
--xx binding
BindAll: PROC [importerDesign: CD.Design, allowConflicts: CDImports.BoolOrInteractive�lse] = {
IF CDImports.LoadAndBindAll[into: importerDesign, allowConflicts: allowConflicts, forceBind: FALSE]
THEN DescribeUnboundImport[CDImports.HasUnloadedImports[importerDesign].where]
ELSE TerminalIO.PutRope[" failed binding all imports\n"];
};
BindAllComm: PROC [comm: CDSequencer.Command] = {
--hack, called from io commands
BindAll[comm.design, false];
};
--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
--xx simple imports
DrawImportByNameComm: PROC [comm: CDSequencer.Command] = {
objectName: ROPE; referenceOb: CD.Object; cache: Cache;
TerminalIO.PutRope["draw object of imported design; "];
cache ← LoadAndGetCache[comm.design].cache;
IF cache=NIL OR cache.importee=NIL THEN RETURN;
objectName ← TerminalIO.RequestRope["object > "];
referenceOb ← CDImports.CreateImportFromCache[into: comm.design, objectName: objectName, importeeName: cache.importeeName];
IF referenceOb=NIL THEN {
TerminalIO.PutF[" %g not found in design %g; not done\n",
[rope[objectName]], [rope[cache.importeeName]]
];
RETURN
};
[] ← CDOps.IncludeObjectI[design: comm.design, ob: referenceOb, location: comm.pos];
};
ImportReadCommand: PROC [comm: CDSequencer.Command] = {
cache: Cache; done: BOOL;
TerminalIO.PutRope["load (or reload) a design into the import cache\n"];
[cache, done] ← LoadAndGetCache[into: comm.design, importeeName: NIL, allwaysNewFile: TRUE, offerAll: TRUE, forceBind: TRUE];
TerminalIO.PutRope[IF ~done OR (cache#NIL AND cache.importee=NIL) THEN "not done\n" ELSE "done\n"];
};
--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
--xx default files [hint files] offered to be used
GetImportFileHints: 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;
};
ChangeImportFileHint: PROC [for: CD.Design, imp, file: ROPE] = {
--A future import of design imp into for offers the use of file file
RemKey: PROC [rl: LIST OF ROPE, key: ROPE] RETURNS [x: LIST OF ROPENIL] = {
FOR list: LIST OF ROPE ← rl, list.rest WHILE list#NIL DO
IF ~Rope.Equal[CDEnvironment.SplitLine[list.first].key, key] THEN x ← CONS[list.first, x]
ENDLOOP;
};
rl: LIST OF ROPE ← GetImportFileHints[for];
rl ← RemKey[rl, imp];
file ← CDEnvironment.RemoveSpaces[file];
IF file#NIL THEN rl ← CONS[Rope.Cat[imp, ": ", file], rl];
CDProperties.PutDesignProp[for, $ImportHints, rl];
};
ChangeImportFileHintComm: PROC [comm: CDSequencer.Command] = {
importeeName, fileName: ROPE;
TerminalIO.PutRope["specify a default file name for a particular import\n"];
importeeName ← RequestImporteeName[into: comm.design, restrictedToCaches: FALSE, fastIfNoChoice: FALSE, offerAll: NIL];
IF Rope.IsEmpty[importeeName] THEN TerminalIO.PutRope["no input design\n"]
ELSE {
fileName ← TerminalIO.RequestRope["FILE name > "];
ChangeImportFileHint[comm.design, importeeName, fileName];
TerminalIO.PutRope[" ok\n"];
}
};
--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
--xx lists for feedback
FindAllImportCaches: PROC [design: CD.Design] RETURNS [dList: SymTab.Ref] = {
--returns SymTab with names of imported designs as keys
--recursively because of indirect imports
CheckOne: PROC [d: CD.Design] = {
IF RefTab.Insert[checked, d, d] THEN {
FOR l: LIST OF CDImports.Cache ← CDImports.GetCacheList[d]^, l.rest WHILE l#NIL DO
this: CDImports.Cache ← l.first;
[] ← SymTab.Insert[dList, this.importeeName, $ok];
IF this.importee#NIL THEN [] ← SymTab.Store[dList, this.importeeName, $notLoaded]
ELSE {
dd: CD.Design ← CDDesignCache.Fetch[design, this.importeeName];
IF dd=NIL THEN [] ← SymTab.Store[dList, this.importeeName, $notLoaded]
ELSE CheckOne[dd];
};
ENDLOOP;
};
};
checked: RefTab.Ref ← RefTab.Create[];
dList ← SymTab.Create[];
CheckOne[design];
};
ListUnboundsIndirect: PROC [design: CD.Design] = {
where: LIST OF CD.Object ← CDImports.HasUnloadedImports[design].where;
IF where#NIL THEN DescribeUnboundImport[where]
ELSE TerminalIO.PutRope[" has no [indirect] unbound imported object\n"]
};
DisplayCachedDesigns: PROC [comm: CDSequencer.Command] = {
ListEach: SymTab.EachPairAction = {
cache: CDImports.Cache ← CDImports.GetCache[design, key];
loaded: BOOL ← cache#NIL AND cache.importee#NIL;
hasImpDesign ← TRUE;
IF ~loaded THEN hasUnloadedDesign ← TRUE;
TerminalIO.PutRopes[" ", key, (IF loaded THEN " (cached)\n" ELSE " (not cached)\n")];
RETURN [FALSE]
};
DisplayImportFileHints: PROC [for: CD.Design] = {
rl: LIST OF ROPE ← GetImportFileHints[for];
IF rl#NIL THEN {
key, rest: ROPENIL;
TerminalIO.PutRopes["file name hints to be used on imports:\n"];
FOR list: LIST OF ROPE ← rl, list.rest WHILE list#NIL DO
[key, rest] ← CDEnvironment.SplitLine[list.first];
rest ← CDEnvironment.RemoveSpaces[rest];
TerminalIO.PutRopes[" design: ", key];
TerminalIO.PutRopes[" file: ", rest, "\n"];
ENDLOOP;
};
};
design: CD.Design ← comm.design;
hasUnloadedDesign: BOOLFALSE;
hasImpDesign: BOOLFALSE;
TerminalIO.PutRopes[CD.DesignName[design], "'s import cache: \n"];
[] ← SymTab.Pairs[FindAllImportCaches[design], ListEach];
IF ~hasImpDesign THEN TerminalIO.PutRope[" has no imported designs in cache\n"];
IF ~hasUnloadedDesign THEN ListUnboundsIndirect[design];
DisplayImportFileHints[design];
TerminalIO.PutRope[" --\n"];
};
DescribeUnboundImport: PROC [where: LIST OF CD.Object, design: CD.Design←NIL] = {
Desc1: PROC [lst: LIST OF CD.Object] RETURNS [ROPE] = {
RETURN [CD.Describe[lst.first, NIL, IF lst.rest=NIL THEN design ELSE NIL]]
};
IF where=NIL THEN RETURN;
TerminalIO.PutRopes[" **some imported object is not bound: ", Desc1[where]];
FOR lst: LIST OF CD.Object ← where.rest, lst.rest WHILE lst#NIL DO
TerminalIO.PutRopes[" accessed through ", Desc1[lst]];
ENDLOOP;
TerminalIO.PutRope["\n"];
};
DisplayImportsComm: PROC [comm: CDSequencer.Command] = {
CheckObject: CDDirectory.EachObjectProc = {
WITH me.specific SELECT FROM
ip: CDImports.ImportSpecific => IF cache=NIL OR Rope.Equal[ip.designName, cache.importeeName] THEN {
totalCount ← totalCount+1;
IF cache#NIL THEN TerminalIO.PutF[" %g ", IO.rope[CD.Describe[me, NIL, design]]];
IF ip.boundOb=NIL THEN {
unboundCount ← unboundCount+1;
TerminalIO.PutRope[" not bound"];
};
TerminalIO.PutRope["\n"];
};
ENDCASE => NULL
};
design: CD.Design ← comm.design;
totalCount, unboundCount: INT ← 0; importeeName: ROPE; cache: Cache←NIL;
cl: CacheList ← CDImports.GetCacheList[design];
IF cl=NIL OR cl.list=NIL THEN {
[] ← CDDirectory.EnumerateDesign[design, CheckObject];
IF totalCount=0 THEN TerminalIO.PutRope["design does not have any imported objects\n"]
ELSE {
TerminalIO.PutF["design has %g imported objects; ", [integer[totalCount]]];
IF unboundCount#0
THEN TerminalIO.PutF["%g not bound\n", [integer[unboundCount]]]
ELSE ListUnboundsIndirect[design]
};
RETURN;
};
importeeName ← RequestImporteeName[into: design, fastIfNoChoice: TRUE, offerAll: "<Just cached designs>"];
IF Rope.IsEmpty[importeeName] THEN {
TerminalIO.PutRope["no design selected\n"]; RETURN;
};
IF Rope.Equal[importeeName, "<Just cached designs>"] THEN {
DisplayCachedDesigns[comm]; RETURN
};
cache ← CDImports.GetCache[design, importeeName, false];
TerminalIO.PutRopes["design ", importeeName];
IF cache=NIL THEN {TerminalIO.PutRope[" not cached\n"]; RETURN};
IF cache.importee#NIL
THEN TerminalIO.PutRope[" cached\n"]
ELSE TerminalIO.PutRope[" not cached\n"];
[] ← CDDirectory.EnumerateDesign[design, CheckObject];
IF totalCount=0 THEN TerminalIO.PutRope[" no objects really used\n"]
ELSE {
TerminalIO.PutF[" %g objects imported from %g\n", [integer[totalCount]], [rope[importeeName]]];
IF unboundCount#0
THEN TerminalIO.PutF[" %g objects not bound\n", [integer[unboundCount]]]
ELSE TerminalIO.PutRope[" (all bound, but indirect imports are not checked)\n"]
};
};
--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
--xx inter design copies
SelectedDesign: PROC [] RETURNS [CD.Design] = {
WITH CDProperties.GetProp[$SelectedDesign, $SelectedDesign] SELECT FROM
d: CD.Design => RETURN [d];
ENDCASE => RETURN [NIL];
};
SelectADesign: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRopes["select ", CD.DesignName[comm.design], " as source-design for the <Z-X-middle> command [drawing imports]\n"];
IF Rope.IsEmpty[comm.design.name] THEN
TerminalIO.PutRope[" design has no name; not done\n"]
ELSE
CDProperties.PutProp[$SelectedDesign, $SelectedDesign, comm.design];
};
InterDesignCopyComm: PROC [comm: CDSequencer.Command] = {
inst: CD.Instance; --copy of sourceInst
Fail: PROC [r1, r2, r3: ROPE←NIL] = {
TerminalIO.PutRope[Rope.Cat[" failed: ", r1, r2, r3, "\n"]];
};
ForwardNormalCopy: PROC [comm: CDSequencer.Command] = {
p: CDSequencer.CommandProc ← CDSequencer.FetchCommand[$CopyS].proc;
comm.data ← NIL;
IF p=NIL THEN Fail["command not available"]
ELSE {
TerminalIO.PutRope[" forward as simple copy\n"];
CDSequencer.ExecuteProc[p, comm.design, dontQueue, comm];
};
};
IncludeOb: PROC [ob: CD.Object] = {
IF ob=NIL THEN Fail["NIL object"]
ELSE {
[] ← CDOps.IncludeObjectI[design, ob, comm.pos, inst.trans.orient];
TerminalIO.PutRopes[" ", CD.Describe[ob, NIL, design], " included\n"];
};
};
multiple, forceBind: BOOLFALSE;
design: CD.Design ← comm.design; obName: ROPE; ob: CD.Object;
sourceDesign: CD.Design ← NIL; sdName: ROPE; sourceInst: CD.Instance;
cache: Cache;
TerminalIO.PutRope["interdesign copy\n"];
WITH comm.data SELECT FROM
d: CD.Design => sourceDesign ← d;
ENDCASE => sourceDesign ← NIL;
IF sourceDesign=design THEN {ForwardNormalCopy[comm]; RETURN};
IF sourceDesign=NIL THEN {Fail["source design not found"]; RETURN};
IF sourceDesign.technology#design.technology THEN {Fail["technology missmatch"]; RETURN};
[sourceInst, multiple] ← CDOps.SelectedInstance[sourceDesign]; --asynchronous for source !!
IF multiple THEN {Fail["multiple selection in source design"]; RETURN};
IF sourceInst=NIL THEN {Fail["no selection in source design"]; RETURN};
inst ← CDInstances.Copy[sourceInst]; --because of asynchronity problem
IF inst.ob=NIL THEN {Fail["asynchronity problem"]; RETURN};
--Try atomic objects
IF ~inst.ob.class.composed OR inst.ob.immutable THEN {IncludeOb[inst.ob]; RETURN};
--Object is mutable
IF ~CDDirectory.IsIncluded[sourceDesign, inst.ob] THEN {
ob ← CDDirectory.AnotherRecursed[me: inst.ob, into: design, fromOrNil: sourceDesign];
IF ob#NIL
THEN IncludeOb[ob]
ELSE Fail["object is not included in directory"];
RETURN;
};
--Object is in directory
obName ← CDDirectory.Name[inst.ob, sourceDesign];
sdName ← sourceDesign.name;
IF Rope.IsEmpty[obName] THEN {Fail["object not named"]; RETURN};
IF Rope.IsEmpty[sdName] THEN {Fail["can not cache from un-named design"]; RETURN};
IF Rope.Equal[sdName, design.name] THEN {
--Designs have equal names; try matching objects from directory first
ob ← CDDirectory.Fetch[design, obName].object;
IF ob#NIL
THEN TerminalIO.PutRope[" design names match; use object with same name\n"]
ELSE ob ← CDDirectory.AnotherRecursed[me: inst.ob, into: design, fromOrNil: sourceDesign];
IF ob#NIL
THEN IncludeOb[ob]
ELSE Fail["object ", obName, " not found in directory"];
RETURN
};
--Designs have different names; try imports
IF CDImports.IsImport[inst.ob] THEN { --don't make indirect imports
ip: CDImports.ImportSpecific ← NARROW[inst.ob.specific];
ob ← CDDirectory.AnotherRecursed[me: inst.ob, into: design, fromOrNil: sourceDesign];
IF ob#NIL THEN {IncludeOb[ob]; RETURN}
};
cache ← CDImports.GetCache[into: design, importeeName: sdName];
IF cache#NIL AND cache.importee#NIL THEN {
--already imported design
IF sourceDesign.edited
THEN TerminalIO.PutRope[" use already imported design; ignores edits\n"]
ELSE TerminalIO.PutRope[" use already imported design\n"]
}
ELSE {
question: ROPE ← Rope.Concat["import design ", sdName];
Process.PauseMsec[300];
--wow!, here 2 design viewers, the terminal and pop up menus will be involved...
--this pause might help to prevent some kind of viewer wedges
IF sourceDesign.edited THEN question ← Rope.Concat[question, " (edits are ignored)"];
IF ~TerminalIO.Confirm[question] THEN {Fail["gives up"]; RETURN};
};
cache ← LoadAndGetCache[into: design, importeeName: sdName, allwaysNewFile: FALSE, forceBind: forceBind].cache;
IF cache=NIL OR cache.importee=NIL THEN {Fail[sdName, " not loaded"]; RETURN};
ob ← CDImports.CreateImportFromCache[into: design, objectName: obName, importeeName: sdName];
IF ob=NIL
THEN Fail[obName, " not found"]
ELSE IncludeOb[ob];
};
CDSequencer.ImplementCommand[$DrawCorrespondingObject, DrawImportedCopy];
DrawImportedCopy: PROC [comm: CDSequencer.Command] = {
GlobalSelection: PROC [expectedTechnology: CD.Technology] RETURNS [foundNamed: BOOLFALSE, foundWithoutChildren: BOOLFALSE, moduleName: ROPENIL, objectName: ROPENIL, object: CD.Object←NIL, orient: CD.Orientation←CD.Orientation[original]] = {
--never returns with both foundNamed and foundWithoutChildren set to true
--if not found then message to TerminalIO
--if foundNamed then both, moduleName, objectName # NIL
Out: PROC [t: ROPE] = {
TerminalIO.PutRope[t]
};
from: CD.Design = SelectedDesign[]; -- so it does not change
IF from=NIL THEN Out[" no selected design"]
ELSE {
fromName: ROPE = from.name; -- so it does not change
IF Rope.IsEmpty[fromName] THEN Out[" selected design has no name"]
ELSE IF expectedTechnology#from.technology AND expectedTechnology#NIL THEN
Out[" different technologies"]
ELSE {
inst: CD.Instance; -- the referred instance to support the name
multiple: BOOL;
[inst, multiple] ← CDOps.SelectedInstance[from];
IF multiple THEN Out[" multiple selection"]
ELSE IF inst=NIL THEN Out[" no selection"]
ELSE {
orient ← inst.trans.orient;
IF ~inst.ob.class.composed THEN {
object ← inst.ob;
foundWithoutChildren ← TRUE;
}
ELSE {
entryName: ROPE = CDDirectory.Name[inst.ob, from];
IF Rope.IsEmpty[entryName] THEN Out[" object has no name"]
ELSE {
moduleName ← fromName;
objectName ← entryName;
foundNamed ← TRUE;
}
}
}
}
}
};
foundNamed, foundWithoutChildren: BOOL;
moduleName, objectName: ROPE;
referenceOb, referedOb: CD.Object ← NIL;
orient: CD.Orientation;
TerminalIO.PutRope["draw corresponding object (import); "];
[foundNamed: foundNamed, foundWithoutChildren: foundWithoutChildren, moduleName: moduleName, objectName: objectName, object: referedOb, orient: orient] ← GlobalSelection[comm.design.technology];
IF foundWithoutChildren THEN referenceOb ← referedOb
ELSE IF foundNamed THEN {
IF Rope.Equal[moduleName, comm.design.name] THEN {
TerminalIO.PutRopes[moduleName, " is selected design; simply copy object\n"];
referenceOb ← CDDirectory.Fetch[comm.design, objectName].object;
}
ELSE {
cache: Cache ← LoadAndGetCache[comm.design, moduleName].cache;
IF cache#NIL AND cache.importee#NIL THEN {
referenceOb ← CDImports.CreateImportFromCache[into: comm.design, objectName: objectName, importeeName: moduleName];
IF referenceOb=NIL THEN TerminalIO.PutF[" %g not found in imported design %g; ", IO.rope[objectName], IO.rope[moduleName]];
}
}
};
IF referenceOb=NIL THEN TerminalIO.PutRope[" not done\n"]
ELSE {
[] ← CDOps.IncludeObjectI[comm.design, referenceOb, comm.pos, orient];
TerminalIO.PutRopes[CD.Describe[referenceOb], " included\n"];
}
};
--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
--xx Merge and Un-Merge
MerginImportCommand: PROC [comm: CDSequencer.Command] = {
importeeName: ROPE; cache: Cache;
TerminalIO.PutRope["make imports resident [merge in]\n"];
IF ~HasCachedImports[comm.design] THEN {
TerminalIO.PutRope["design has no cached imports\n"];
};
Process.PauseMsec[200]; --flush for sure!?
importeeName ← RequestImporteeName[into: comm.design, fastIfNoChoice: TRUE];
IF Rope.IsEmpty[importeeName] THEN {
TerminalIO.PutRope["no imported design specified\n"]; RETURN
};
cache ← CDImports.GetCache[comm.design, importeeName, false];
IF cache=NIL THEN {
TerminalIO.PutRopes[importeeName, " not cached; not done\n"]; RETURN
}
ELSE IF cache.importee=NIL THEN {
TerminalIO.PutRopes[importeeName, " no design in cache yet\n"];
IF LoadAndGetCache[comm.design, importeeName].cache=NIL THEN RETURN;
IF cache.importee=NIL THEN RETURN;
};
CDImports.MergeInImports[into: comm.design, importeeName: importeeName];
TerminalIO.PutRope["end merge\n"];
};
UndoMergeInComm: PROC [comm: CDSequencer.Command] = {
replaceList: RefTab.Ref ← RefTab.Create[];
FindObjects: CDDirectory.EachObjectProc = {
--uses global replaceList
WITH CDProperties.GetObjectProp[me, $CameFrom] SELECT FROM
--putting the objectnames in the RefTab keeps them even if replacement is in wrong order
r: ROPE =>
[] ← RefTab.Insert[replaceList, me, CDProperties.GetObjectProp[me, $OriginalName]];
ENDCASE => NULL
};
ReplaceObjects: RefTab.EachPairAction = {
--uses globals cache
quit ← FALSE;
WITH val SELECT FROM
r: ROPE => {
ob: CD.Object ← NARROW[key];
oldName: ROPE ← CDDirectory.Name[ob, design];
new: CD.Object ← CDImports.CreateImportFromCache[into: design, objectName: r, importeeName: cache.importeeName];
IF new#NIL THEN {
msg: ROPE;
oldRope: ROPE ← CD.Describe[ob, NIL, design, 0];
CDDirectory.ReplaceObject[design, ob, new];
IF oldName#NIL THEN [] ← CDDirectory.Remove[design, oldName, ob];
msg ← IF new.bbox=ob.bbox AND CD.InterestRect[new]=CD.InterestRect[ob]
THEN "replaced"
ELSE "replaced (size conflict)";
TerminalIO.PutF[" for %g: %g %g by %g\n",
IO.rope[r],
IO.rope[msg],
IO.rope[oldRope],
IO.rope[CD.Describe[new, NIL, design, 0]]
];
};
CDSequencer.CheckAborted[design];
};
ENDCASE => NULL
};
cache: Cache;
design: CD.Design ← comm.design;
TerminalIO.PutRope["replace resident objects by imports where possible\n"];
cache ← LoadAndGetCache[comm.design].cache;
IF cache=NIL THEN {TerminalIO.PutRope[" not loaded\n"]; RETURN};
[] ← CDDirectory.EnumerateDesign[design, FindObjects];
[] ← RefTab.Pairs[replaceList, ReplaceObjects];
TerminalIO.PutRope[" --\n"];
};
IncludeComm: PROC [comm: CDSequencer.Command] = {
MergeIn: PROC [design: CD.Design, from: CD.Design, name: Rope.ROPENIL] RETURNS [dummyOb: CD.Object←NIL] = {
--DANGEROUS PROC
--"from" is transfered to an object, and is included (transitive) to "design"'s directory
--Warning: This procedure destroys "from"
--The caller is assumed to have the locks of both designs
--if "from" is pushed in, it's merged copy will be popped out, either by flushing,
--replacing or creating new cells
--"name" replaces "from"'s design name for the new created object, but it is a hint only
--the "from"'s object's may change name to avoid conflicts with "design"'s directory
--dummyOb gets nil if "from" 's top level is empty
--technologies must be compatible
recursiveImports: LIST OF CD.Object ← NIL;
SkipAt: PROC [n: Rope.ROPE] RETURNS [Rope.ROPE] = {
--skip everything after and inclusive first "@"
RETURN [Rope.Substr[base: n, len: Rope.SkipTo[s: n, skip: "@"]]]
};
ChangeOwnerShip: CDDirectory.EachObjectProc = {
CDDirectory.SetOwner[design, me, FALSE];
CDProperties.PutObjectProp[me, $CameFrom, from.name];
WITH me.specific SELECT FROM
ip: CDImports.ImportSpecific =>
IF Rope.Equal[ip.designName, design.name] THEN
recursiveImports ← CONS[me, recursiveImports];
ENDCASE => NULL;
};
IncludeOneEntry: CDDirectory.EachEntryAction = {
name ← SkipAt[name];
[] ← CDDirectory.Include[design: design, object: ob, name: name];
CDProperties.PutObjectProp[ob, $OriginalName, name];
};
ReplaceRecursiveImports: PROC [] = {
FOR obl: LIST OF CD.Object ← recursiveImports, obl.rest WHILE obl#NIL DO
WITH obl.first.specific SELECT FROM
ip: CDImports.ImportSpecific => {
original: CD.Object ← CDDirectory.Fetch[design, ip.objectName];
IF original#NIL THEN
CDDirectory.ReplaceObject[design: design, old: obl.first, new: original];
};
ENDCASE => NULL;
ENDLOOP;
};
inst: CD.Instance;
IF design=from THEN RETURN;
IF design.technology#from.technology THEN
RETURN WITH ERROR CD.Error[calling, "technology missmatch"];
IF from.mutability#findOut THEN
RETURN WITH ERROR CD.Error[calling, "wrong mutability"];
CDSequencer.MarkChangedIOOnly[design];
inst ← CDCellsInteractions.MakeTopInstance[from];
IF inst#NIL THEN dummyOb ← inst.ob;
[] ← CDDirectory.EnumerateDesign[design: from, proc: ChangeOwnerShip, dir: TRUE, top: TRUE, recurse: TRUE, dummy: TRUE];
[] ← CDDirectory.Enumerate[design: from, action: IncludeOneEntry];
ReplaceRecursiveImports[];
CDOps.ResetDesign[from];
from.mutability ← inaccessible;
};
Check: PROC [h: TokenIO.Handle] RETURNS [ok: BOOL] = {
design: CD.Design ← CDIO.DesignInReadOperation[h];
ok ← design.technology=comm.design.technology;
IF NOT ok THEN
TerminalIO.PutRopes["technology miss-match: includee is ", design.technology.name, "\n"];
};
done: BOOLFALSE;
design: CD.Design; ob: CD.Object;
srcDesign: Rope.ROPE
WITH comm.data SELECT FROM
r: Rope.ROPE => r,
ENDCASE => NIL;
TerminalIO.PutRope["include resident copy of input design; \n"];
design ← CDIO.ReadDesign
[srcDesign, Check, CDEnvironment.GetWorkingDirectory[comm.design]];
IF design#NIL THEN {
[ob] ← MergeIn[design: comm.design, from: design];
IF ob#NIL THEN {[] ← CDOps.PlaceInst[comm.design, ob, comm]; done ← TRUE};
};
IF done
THEN TerminalIO.PutRope["include done\n"]
ELSE TerminalIO.PutRope["include not done\n"];
};
[] ← CDProperties.RegisterProperty[$SelectedDesign, $chj];
[] ← CDProperties.RegisterProperty[$ImportHints, $chj];
CDSequencer.ImplementCommand[$DrawImported, DrawImportByNameComm];
CDSequencer.ImplementCommand[$DisplayImportedEntries, DisplayImportsComm,, doQueue];
CDSequencer.ImplementCommand[$ImportADesign, ImportReadCommand];
CDSequencer.ImplementCommand[$SelectADesign, SelectADesign,, doQueue];
CDSequencer.ImplementCommand[$MerginImport, MerginImportCommand];
CDSequencer.ImplementCommand[$UnqueuedLoadAllImps, BindAllComm,, dontQueue];
CDSequencer.ImplementCommand[$ReplaceByImp, UndoMergeInComm];
CDSequencer.ImplementCommand[$ImportDefaultName, ChangeImportFileHintComm];
CDSequencer.ImplementCommand[$UnqueuedCopyInterDesign, InterDesignCopyComm];
CDSequencer.ImplementCommand[$IncludeADesign, IncludeComm,, doQueueAndMark];
END.