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
ROPE←
NIL] =
INLINE
--gfi-- {
Each: SymTab.EachPairAction = {list ← CONS[key, list]};
[] ← SymTab.Pairs[ref, Each];
};
RequestImporteeName:
PROC [into:
CD.Design, restrictedToCaches:
BOOL←
TRUE, fastIfNoChoice:
BOOL←
FALSE, offerAll:
ROPE←
NIL]
RETURNS [importeeName:
ROPE←
NIL] = {
--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: ROPE ← NIL;
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:
ROPE←
NIL, allwaysNewFile:
BOOL←
FALSE, forceBind:
BOOL ←
FALSE, offerAll:
BOOL ←
FALSE]
RETURNS [cache: Cache←
NIL, done:
BOOL←
FALSE] = {
checkCalled: BOOL ← FALSE;
r, fn: ROPE;
design: CD.Design←NIL;
loaded: BOOL←FALSE;
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 ROPE ← LIST[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.BoolOrInteractivelse] = {
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
ROPE←
NIL] = {
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
ROPE←
NIL] = {
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: ROPE ← NIL;
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: BOOL ← FALSE;
hasImpDesign: BOOL ← FALSE;
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: BOOL ← FALSE;
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: BOOL←FALSE, foundWithoutChildren: BOOL←FALSE, moduleName: ROPE←NIL, objectName: ROPE←NIL, 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.
ROPE←
NIL]
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: BOOL ← FALSE;
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.