[Indigo]<Rosemary>2.6>Rosemary.df=>RoseCreateImpl.Mesa
Last Edited by: Spreitzer, January 25, 1985 4:01:52 pm PST
DIRECTORY Asserting, Basics, Convert, IO, OrderedSymbolTableRef, Rope, RoseCreate, RoseEvents, RoseRun, RoseTypes;
RoseCreateImpl: CEDAR PROGRAM
IMPORTS Asserting, Convert, IO, OSTR: OrderedSymbolTableRef, Rope, RoseCreate, RoseEvents, RoseRun, RoseTypes
EXPORTS RoseCreate, RoseTypes =
BEGIN OPEN RoseCreate, RoseTypes;
cellTypes: SymbolTable ← OSTR.CreateTable[CompareCellTypes];
roots: PUBLIC SymbolTable ← OSTR.CreateTable[CompareComponents];
bogosityKey: ATOM = $bogosityKey;
simERClass: ERClass ← NEW [ERClassRep ← [
CellInstance: CellInstance,
NodeInstance: NodeInstance,
SplitJoin: SplitJoin,
ChangeReps: ChangeReps]];
CompareCellTypes: PROC [r1, r2: REF ANY] RETURNS [Basics.Comparison] --OSTR.CompareProc-- =
BEGIN
ToKey: SAFE PROC [ref: REF ANY] RETURNS [ROPE] =
{RETURN [WITH ref SELECT FROM
r: ROPE => r, ct: CellType => ct.name, ENDCASE => ERROR]};
RETURN [ToKey[r1].Compare[ToKey[r2]]];
END;
CompareComponents: PUBLIC PROC [r1, r2: REF ANY] RETURNS [Basics.Comparison] --OSTR.CompareProc-- =
BEGIN
ToKey: SAFE PROC [ref: REF ANY] RETURNS [ROPE] =
{RETURN [WITH ref SELECT FROM
r: ROPE => r, c: Cell => c.name, ENDCASE => ERROR]};
RETURN [ToKey[r1].Compare[ToKey[r2]]];
END;
CompareNodes: PUBLIC PROC [r1, r2: REF ANY] RETURNS [Basics.Comparison] --OSTR.CompareProc-- =
BEGIN
k1, k2: ROPE;
WITH r1 SELECT FROM
r: ROPE => k1 ← r;
n: Node => k1 ← n.name;
ENDCASE => ERROR;
k2 ← WITH r2 SELECT FROM
r: ROPE => r,
n: Node => n.name,
ENDCASE => ERROR;
RETURN [k1.Compare[k2]];
END;
CompareTests: PROC [r1, r2: REF ANY] RETURNS [Basics.Comparison] --OSTR.CompareProc-- =
BEGIN
ToKey: SAFE PROC [ref: REF ANY] RETURNS [ROPE] =
{RETURN [WITH ref SELECT FROM
r: ROPE => r, a: CellTest => a.name, ENDCASE => ERROR]};
RETURN [ToKey[r1].Compare[ToKey[r2]]];
END;
EqualInterfaces: PUBLIC PROC [a, b: Ports] RETURNS [equal: BOOL] = {
IF equal ← (a.length = b.length) THEN
BEGIN
FOR portIndex: CARDINAL IN [0 .. b.length) DO
IF (
a[portIndex].firstWord # b[portIndex].firstWord OR
a[portIndex].wordCount # b[portIndex].wordCount OR
a[portIndex].type # b[portIndex].type OR
a[portIndex].input # b[portIndex].input OR
a[portIndex].output # b[portIndex].output OR
NOT a[portIndex].name.Equal[b[portIndex].name])
THEN {equal ← FALSE; EXIT};
ENDLOOP;
END;
};
RegisterCellType: PUBLIC PROC [name: ROPE, expandProc: ExpandProc ← NIL, ioCreator: IOCreator ← NIL, driveCreator: DriveCreator ← NIL, initializer: Initializer ← NIL, evals: EvalProcs, tests: CellTestList ← NIL, ports: Ports, typeData: REF ANYNIL, other: Assertions ← NIL] RETURNS [type: CellType] =
BEGIN
type ← NARROW[cellTypes.Lookup[name]];
IF type = NIL THEN {
type ← NEW [CellTypeRep ←
[name: name, ioWordCount: 0, firstInstance: NIL, testers: OSTR.CreateTable[CompareTests] ]];
cellTypes.Insert[type];
FOR portIndex: CARDINAL IN [0 .. ports.length) DO
port: Port ← ports[portIndex];
type.ioWordCount ← MAX[type.ioWordCount, port.firstWord + port.wordCount];
IF port.type = NIL THEN ERROR Error[IO.PutFR["No NodeType given for Port %g", IO.rope[port.name]]];
IF NOT port.type.simple THEN type.hasASwitchPort ← TRUE;
IF port.special THEN type.hasASpecialPort ← TRUE;
ENDLOOP;
}
ELSE BEGIN
IF type.firstInstance # NIL AND NOT EqualInterfaces[ports, type.ports] THEN ERROR Error[IO.PutFR["Redefinition of Type %g not allowed because of different interface", IO.rope[name]]];
FOR instance: Cell ← type.firstInstance, instance.nextInstance WHILE instance # NIL DO
IF instance.type # type THEN ERROR;
IF instance.expansion = Leaf THEN
BEGIN
IF instance.realCellStuff.evals # type.evals THEN ERROR;
instance.realCellStuff.evals ← evals;
END;
ENDLOOP;
END;
type.expand ← expandProc;
type.ioCreator ← ioCreator;
type.driveCreator ← driveCreator;
type.initializer ← initializer;
type.evals ← evals;
type.ports ← ports;
type.typeData ← typeData;
type.other ← Asserting.Union[other, type.other];
FOR tests ← tests, tests.rest WHILE tests # NIL DO
[] ← SetTest[test: NEW [CellTestRep ← tests.first], of: type];
ENDLOOP;
END;
GetCellType: PUBLIC PROC [name: ROPE] RETURNS [type: CellType] =
{type ← NARROW[cellTypes.Lookup[name]]};
GetTest: PUBLIC PROC [name: ROPE, from: CellType] RETURNS [t: CellTest] =
{t ← NARROW[from.testers.Lookup[name]]};
SetTest: PUBLIC PROC [test: CellTest, of: CellType, mayOverwriteOld: BOOLFALSE] RETURNS [old: CellTest] = {
old ← NARROW[of.testers.Lookup[test]];
IF old # NIL THEN {
IF mayOverwriteOld
THEN {IF of.testers.Delete[test] # old THEN ERROR}
ELSE ERROR Error[IO.PutFR["Duplicate Test (named %g) given for cell type %g", IO.rope[test.name], IO.rope[of.name]]];
};
of.testers.Insert[test];
};
CreateSim: PUBLIC PROC [steady: BOOL] RETURNS [sim: Simulation] = {
sim ← NEW [SimulationRep ← [
steady: steady,
root: NIL]];
RoseEvents.Notify[event: $NewSim, arg: sim];
};
CreateTopCell: PUBLIC PROC [instanceName, typeName: ROPE, decider: ExpandDeciderClosure, sim: Simulation] RETURNS [cell: Cell] =
BEGIN
type: CellType;
type ← NARROW[cellTypes.Lookup[typeName]];
IF type = NIL THEN ERROR Error[IO.PutFR["No such type: %g", IO.rope[typeName]]];
sim.root ← cell ← NEW [CellRep ← [
name: instanceName, type: type, sim: sim,
parent: NIL, leftChild: NIL, rightSibling: NIL, firstInternalNode: NIL,
internalNodes: OSTR.CreateTable[CompareNodes],
components: OSTR.CreateTable[CompareComponents],
interfaceNodes: NEW [NodeSR[0]],
other: NIL,
substantiality: Shadow, expansion: Inline,
realCellStuff: NIL]];
cell.other ← Asserting.AssertFn1[$ExpandDeciderClosure, decider, cell.other];
FinishCreatingCell[cell, NIL, TRUE];
END;
CellInstance: PROC [erInstance: REF ANY, instanceName, typeName, interfaceNodes: ROPE, other: Assertions ← NIL] RETURNS [cell: Cell] =
BEGIN
within: Cell ← NARROW[erInstance];
type: CellType;
type ← NARROW[cellTypes.Lookup[typeName]];
IF type = NIL THEN ERROR Error[IO.PutFR["No such type: %g", IO.rope[typeName]]];
cell ← NEW [CellRep ← [
name: instanceName, type: type, sim: within.sim,
parent: within, leftChild: NIL, rightSibling: NIL, firstInternalNode: NIL,
internalNodes: OSTR.CreateTable[CompareNodes],
components: OSTR.CreateTable[CompareComponents],
interfaceNodes: NEW [NodeSR[type.ports.length]],
other: other,
substantiality: Shadow, expansion: Inline,
realCellStuff: NIL]];
FinishCreatingCell[cell, interfaceNodes, FALSE];
END;
FinishCreatingCell: PROC [cell: Cell, interfaceNodes: ROPE, isRoot: BOOL] =
BEGIN
type: CellType ← cell.type;
thisChild, lastChild: Cell;
thisNode, lastNode: Node;
IF (cell.parent = NIL) AND (type.ports.length > 0) THEN ERROR Error["Can't make root with non-empty interface", cell];
IF cell.parent # NIL THEN
BEGIN
cell.parent.components.Insert[cell !OSTR.DuplicateKey => ERROR Error[IO.PutFR["Duplicated Cell name: %g", IO.rope[cell.name]]]];
cell.rightSibling ← cell.parent.leftChild;
--do it in wrong order for now; parent will fix up after done expanding--
cell.parent.leftChild ← cell;
END;
cell.nextInstance ← type.firstInstance;
type.firstInstance ← cell;
FillInInterfaceNodes[cell, interfaceNodes];
cell.expansion ← FindAndUseExpandDecider[cell];
SELECT cell.expansion FROM
Inline => BEGIN
cell.substantiality ← Shadow;
cell.realCellStuff ← NIL;
FOR index: CARDINAL IN [0 .. type.ports.length) DO
interfaceNode: Node ← cell.interfaceNodes[index];
ENDLOOP;
type.expand[thisCell: cell, to: [cell, simERClass]];
FOR index: CARDINAL IN [0 .. type.ports.length) DO
interfaceNode: Node ← cell.interfaceNodes[index];
ENDLOOP;
END;
Leaf, Nested => BEGIN
cell.substantiality ← Real;
cell.realCellStuff ← NEW [RealCellStuffRep ← [schedNext: notInCellList,
nextNeeded: notInCellList, nextNoted: notInCellList,
newIO: NIL, oldIO: NIL, switchIO: NIL,
newIOAsWP: NIL, oldIOAsWP: NIL, switchIOAsWP: NIL,
state: NIL,
evals: type.evals]];
FOR portIndex: CARDINAL IN [0..type.ports.length) DO
node: Node ← cell.interfaceNodes[portIndex];
targType: NodeType ← cell.type.ports[portIndex].type;
IF node.type = NIL THEN ERROR--node.type ← targType--;
IF targType # node.type THEN ERROR InterfaceMismatch[cell: cell, index: portIndex, expected: targType, got: node.type];
IF cell.type.ports[portIndex].XPhobic THEN node.XPhobic ← TRUE;
NoteConnection[node, [cell, portIndex]];
NoteMaybeVisible[node, [cell, portIndex]];
ENDLOOP;
IF type.ioCreator # NIL THEN {
cell.realCellStuff.newIO ← type.ioCreator[ct: type];
cell.realCellStuff.oldIO ← type.ioCreator[ct: type];
IF type.hasASwitchPort THEN cell.realCellStuff.switchIO ← type.ioCreator[ct: type];
}
ELSE IF type.ioWordCount > 0 THEN ERROR Error[IO.PutFR["No IOCreator for type %g", IO.rope[type.name]]];
cell.realCellStuff.newIOAsWP ← LOOPHOLE[cell.realCellStuff.newIO];
cell.realCellStuff.oldIOAsWP ← LOOPHOLE[cell.realCellStuff.oldIO];
cell.realCellStuff.switchIOAsWP ← LOOPHOLE[cell.realCellStuff.switchIO];
FOR portIndex: CARDINAL IN [0 .. type.ports.length) DO
targType: NodeType ← cell.type.ports[portIndex].type;
node: Node ← cell.interfaceNodes[portIndex];
IF targType.procs.InitPort # NIL THEN targType.procs.InitPort[
node,
SocketToWP[[cell, portIndex]]];
IF node.initialValue # NIL AND node.type.simple THEN
Initialize[node, SocketToWP[[cell, portIndex]]];
ENDLOOP;
IF type.initializer # NIL THEN type.initializer[cell: cell, leafily: cell.expansion = Leaf];
IF cell.expansion = Nested THEN
BEGIN
insides: Structure;
cell.realCellStuff.evals ← RoseRun.StrEvals;
cell.realCellStuff.state ← insides ← NEW [StructureRep ← [
container: cell, mirror: NIL,
schedFirst: NIL, schedLast: NIL,
insideNodes: NEW [NodeSR[type.ports.length]],
nextPerturbed: notInStrList,
nextWasPerturbed: notInStrList ]];
IF cell.parent # NIL THEN insides.mirror ← NEW [CellRep ← [
name: " -mirror- ",
type: GetMirrorType[cell.type],
sim: cell.sim,
parent: cell,
leftChild: NIL,
rightSibling: NIL,
firstInternalNode: NIL,
internalNodes: NIL,
components: NIL,
interfaceNodes: insides.insideNodes,
other: NIL,
substantiality: Real,
expansion: Leaf,
realCellStuff: NEW [RealCellStuffRep ← [
schedNext: notInCellList,
nextNeeded: notInCellList,
nextNoted: notInCellList,
newIO: cell.realCellStuff.newIO,
oldIO: cell.realCellStuff.oldIO,
switchIO: cell.realCellStuff.switchIO,
newIOAsWP: cell.realCellStuff.newIOAsWP,
oldIOAsWP: cell.realCellStuff.oldIOAsWP,
switchIOAsWP: cell.realCellStuff.switchIOAsWP,
state: ContainingStr[cell],
evals: RoseRun.StrMirrorEvals]]]];
FOR index: CARDINAL IN [0 .. type.ports.length) DO
outsideNode: Node ← cell.interfaceNodes[index];
insideNode: Node ← NodeInstance[erInstance: cell, name: type.ports[index].name, type: outsideNode.type, initialValue: outsideNode.initialValue, initialValueFormat: outsideNode.initialValueFormat.key];
insides.insideNodes[index] ← insideNode;
IF type.ports[index].XPhobic THEN insideNode.XPhobic ← TRUE;
IF cell.parent # NIL THEN {
NoteMaybeVisible[insideNode, [insides.mirror, index]];
NoteConnection[insideNode, [insides.mirror, index]];
};
ENDLOOP;
type.expand[thisCell: cell, to: [cell, simERClass]];
END;
END;
ENDCASE => ERROR;
lastChild ← NIL;
thisChild ← cell.leftChild;
WHILE thisChild # NIL DO
nextChild: Cell ← thisChild.rightSibling;
thisChild.rightSibling ← lastChild;
lastChild ← thisChild;
thisChild ← nextChild;
ENDLOOP;
cell.leftChild ← lastChild;
lastNode ← NIL;
thisNode ← cell.firstInternalNode;
WHILE thisNode # NIL DO
nextNode: Node ← thisNode.next;
thisNode.next ← lastNode;
lastNode ← thisNode;
thisNode ← nextNode;
ENDLOOP;
cell.firstInternalNode ← lastNode;
IF isRoot
THEN roots.Insert[cell !OSTR.DuplicateKey => ERROR Error[IO.PutFR["Duplicated Root name: %g", IO.rope[cell.name]]]]
ELSE IF cell.substantiality = Real THEN RoseRun.ScheduleCell[cell];
END;
NoteConnection: PROC [node: Node, socket: Socket] =
BEGIN
node.connections ← CONS[socket, node.connections];
END;
GetName: PROC [from: IO.STREAM] RETURNS [name: ROPE] = {
first: CHAR ← from.PeekChar[];
SELECT first FROM
'" => name ← from.GetRopeLiteral[];
ENDCASE => name ← from.GetTokenRope[IDBreak].token;
};
IDBreak: IO.BreakProc =
{RETURN [SELECT char FROM
IO.SP, IO.CR, IO.LF, IO.TAB => sepr,
',, ': => break,
ENDCASE => other]};
FillInInterfaceNodes: PUBLIC PROC [cell: Cell, interfaceNodes: ROPE] =
BEGIN
index: CARDINAL ← 0;
in: IO.STREAMIO.RIS[interfaceNodes];
[] ← in.GetIndex[]; --wake up generic GetIndex impl
FOR i: NAT ← in.SkipWhitespace[], in.SkipWhitespace[] WHILE NOT in.EndOf[] DO
name: ROPE ← GetName[in];
key: ROPE;
this: CARDINAL;
[] ← in.SkipWhitespace[];
IF (NOT in.EndOf[]) AND (in.PeekChar[] = ':) THEN
BEGIN
key ← name;
IF in.GetChar[] # ': THEN ERROR;
[] ← in.SkipWhitespace[];
IF in.EndOf[] THEN ERROR Error[IO.PutFR["Interface spec syntax error, at %g", IO.int[in.GetIndex[]]]];
name ← GetName[in];
IF (this ← GetIndex[cell.type.ports, key]) = notFound THEN ERROR Error[IO.PutFR["No such port (%g) for CellType %g", IO.rope[key], IO.rope[cell.type.name]]];
END
ELSE BEGIN
IF index >= cell.interfaceNodes.length THEN ERROR Error[IO.PutFR["No %g'th element in %g's Interface", IO.int[index], IO.rope[cell.type.name]]];
key ← cell.type.ports[this ← index].name;
END;
IF cell.interfaceNodes[this] # NIL THEN ERROR Error[IO.PutFR["Port %g specified twice in \"%g\"", IO.rope[key], IO.rope[interfaceNodes]]];
cell.interfaceNodes[this] ← LookupCellNode[cell.parent, name];
IF cell.interfaceNodes[this] = NIL THEN ERROR Error[IO.PutFR["Node %g not found", IO.rope[name]]];
index ← index + 1;
[] ← in.SkipWhitespace[];
IF in.EndOf[] THEN EXIT;
IF in.GetChar[] # ', THEN ERROR Error[IO.PutFR["Interface spec syntax error (missing comma), at %g", IO.int[in.GetIndex[]]]];
ENDLOOP;
FOR this: CARDINAL IN [0 .. cell.interfaceNodes.length) DO
IF cell.interfaceNodes[this] = NIL THEN
BEGIN
name: ROPE ← cell.type.ports[this].name;
cell.interfaceNodes[this] ← LookupCellNode[cell.parent, name];
IF cell.interfaceNodes[this] = NIL THEN ERROR Error[IO.PutFR["Port %g not specified in \"%g\"", IO.rope[name], IO.rope[interfaceNodes]]];
END;
ENDLOOP;
in.Close[];
END;
GetIndex: PUBLIC PROC [ports: Ports, key: ROPE] RETURNS [index: CARDINAL] =
BEGIN
FOR i: CARDINAL IN [0..ports.length) DO
IF key.Equal[ports[i].name] THEN RETURN [i];
ENDLOOP;
RETURN [notFound];
END;
FindAndUseExpandDecider: PROC [cell: Cell] RETURNS [ExpandDecision] =
BEGIN
ed: ExpandDecision;
possibilities: [0..3];
[ed, possibilities] ← PickOne[cell];
IF possibilities = 1 THEN RETURN [ed];
IF possibilities = 0 THEN ERROR Error[IO.PutFR["Can't do anything with type %g", IO.rope[cell.type.name]]];
FOR temp: Cell ← cell, temp.parent WHILE temp # NIL DO
asAny: REF ANY ← Asserting.FnVal[$ExpandDeciderClosure, temp.other];
edc: ExpandDeciderClosure;
try: ExpandDecision;
IF asAny = NIL THEN LOOP;
edc ← NARROW[asAny];
try ← edc.Decide[cell, edc.otherData];
IF Possible[cell, try] THEN RETURN [try];
ENDLOOP;
RETURN [ed];
END;
PickOne: PROC [cell: Cell] RETURNS [whatToDo: ExpandDecision, possibilities: [0..3]] =
BEGIN
possibilities ← 0;
FOR i: [1..3] IN [1..3] DO
d: ExpandDecision ← orderedChoices[i];
IF Possible[cell, d] THEN {whatToDo ← d; possibilities ← possibilities + 1};
ENDLOOP;
END;
orderedChoices: ARRAY [1..3] OF ExpandDecision = [Leaf, Nested, Inline];
NoteMaybeVisible: PROC [node: Node, socket: Socket] = INLINE
BEGIN
IF node.visible.cell = NIL THEN node.visible ← socket;
END;
GetMirrorType: PROC [type: CellType] RETURNS [mirrorType: CellType] =
BEGIN
name: ROPE ← type.name.Concat["-mirror"];
asAny: REF ANY;
IF (asAny ← cellTypes.Lookup[name]) # NIL THEN RETURN [NARROW[asAny]];
mirrorType ← RegisterCellType[
name: name,
evals: RoseRun.StrMirrorEvals,
ports: MirrorPorts[type.ports]];
END;
Possible: PUBLIC PROC [cell: Cell, whatToDo: ExpandDecision] RETURNS [possible: BOOLEAN] =
BEGIN
evalable: BOOL ← cell.type.evals.EvalSimple # NIL OR cell.type.evals.PropUD # NIL;
iok: BOOL ← cell.type.ioWordCount = 0 OR cell.type.ioCreator # NIL;
RETURN [SELECT whatToDo FROM
Leaf => evalable AND iok,
Nested => cell.type.expand # NIL AND iok,
Inline => cell.type.expand # NIL AND cell.parent # NIL,
ENDCASE => ERROR];
END;
XPhobicize: PUBLIC PROC [n: Node] RETURNS [m: Node-- = n --] = {
m ← n;
m.XPhobic ← TRUE};
NodeInstance: PROC [erInstance: REF ANY, name: ROPE, type: NodeType, initialValue, initialValueFormat: ROPENIL, initData: REF ANYNIL, other: Assertions ← NIL] RETURNS [node: Node] =
BEGIN
within: Cell ← NARROW[erInstance];
node ← NEW [NodeRep ← [
name: name,
type: type,
cellIn: within,
initialValue: initialValue,
initialValueFormat: type.procs.GetFormat[type, initialValueFormat],
nextPerturbed: notInNodeList,
nextAffected: notInNodeList,
nextX: notInNodeList,
prevX: notInNodeList,
next: within.firstInternalNode,
other: other
]];
IF node.initialValueFormat = NIL THEN ERROR Error[IO.PutFR["Bad initialValueFormat %g for %g", IO.rope[initialValueFormat], IO.rope[name]]];
within.internalNodes.Insert[node !OSTR.DuplicateKey => ERROR Error[IO.PutFR["Duplicated Node name: %g", IO.rope[name]]]];
within.firstInternalNode ← node;
--link in wrong order now; fix up when done expanding--
IF type.procs.InitNode # NIL THEN type.procs.InitNode[node, initData, within.sim.steady];
IF initialValue # NIL AND NOT type.simple THEN Initialize[node, ValWP[node]];
IF NOT type.simple THEN RoseRun.PerturbNode[node, within];
END;
Initialize: PROC [node: Node, wp: WordPtr] =
BEGIN
ivs: IO.STREAMIO.RIS[node.initialValue];
fmt: Format ← node.initialValueFormat;
ok: BOOLEAN ← fmt.ParseValue[
node,
fmt,
wp,
ivs];
ivs.Close[];
IF NOT ok THEN {
SIGNAL Warning[IO.PutFR[
"Unable to parse %g by format (%g) for node %g (of type %g)",
IO.rope[Convert.RopeFromRope[node.initialValue]],
IO.rope[fmt.key],
IO.rope[node.name],
IO.rope[node.type.procs.UserDescription[node.type]]]];
node.initialValue ← NIL};
END;
SplitJoin: PROC [erInstance: REF ANY, a, b: StretchList, writeA, writeB: BOOLEAN] =
BEGIN
within: Cell ← NARROW[erInstance];
c: Cell;
IF (a = NIL) # (b = NIL) THEN ERROR;
IF a = NIL THEN RETURN;
c ← a.first.node.type.procs.MakeSplitJoin[within, a, b, writeA, writeB, [erInstance, simERClass]];
IF c = NIL THEN ERROR;
c.other ← Asserting.AssertFn1[fn: bogosityKey, val: $T, inAdditionTo: c.other];
END;
ChangeReps: PROC [erInstance: REF ANY, a, b: Node, writeA, writeB: BOOLEAN] =
BEGIN
within: Cell ← NARROW[erInstance];
c: Cell ← NIL;
IF c = NIL AND a.type.procs.MakeTransducer # NIL THEN c ← a.type.procs.MakeTransducer[a, b, within, writeA, writeB, [erInstance, simERClass]];
IF c = NIL AND b.type.procs.MakeTransducer # NIL THEN c ← b.type.procs.MakeTransducer[b, a, within, writeB, writeA, [erInstance, simERClass]];
IF c = NIL THEN ERROR;
c.other ← Asserting.AssertFn1[fn: bogosityKey, val: $T, inAdditionTo: c.other];
END;
END.