RoseInstantiateImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reversed.
Barth, August 1, 1985 2:31:39 pm PDT
Spreitzer, November 18, 1985 10:29:34 pm PST
DIRECTORY Core, CoreClasses, CoreFlatten, CoreOps, CoreProperties, IO, Properties, Rope, RoseBind, RoseBindPrivate, RoseControl, RoseEngine, RosePrivates, RoseSimTypes, RoseWireTwiddling, RoseWireTypes, RoseWiring;
RoseInstantiateImpl: CEDAR PROGRAM
IMPORTS CoreOps, CoreProperties, Properties, RoseBind, RoseBindPrivate, RoseWireTwiddling, RoseWiring, RoseWireTypes
EXPORTS RoseControl, RoseEngine, RoseSimTypes
=
BEGIN OPEN CP: CoreProperties, RoseWireTypes, RoseSimTypes, RoseEngine, RWTg: RoseWireTwiddling;
This program instantiates a Rosemary simulation.
A Wire will be a leaf iff:
All of its parts, if any, are used in parallel, and
No ancestor could be a leaf.
BehaviorClass: TYPE = REF BehaviorClassRec;
BehaviorClassRec: PUBLIC TYPE = RoseBindPrivate.BehaviorClassRec;
Simulation: TYPE = REF SimulationRec;
SimulationRec: PUBLIC TYPE = RoseSimTypes.SimulationRec;
RoseWireRep: PUBLIC TYPE = RoseSimTypes.RoseWireRep;
WireBehaviorKind: TYPE = {simple, switch, mixed, unspecified};
notInWireList: PUBLIC RoseWire ← NEW [RoseWireRep];
notInCellList: PUBLIC RoseCellInstance ← NEW [RoseCellInstanceRep];
roseWireTypeKey: PUBLIC ATOMCP.RegisterProperty[$RoseWireTypeKey];
roseWireKey: PUBLIC ATOMCP.RegisterProperty[$RoseWireKey];
roseCellKey: PUBLIC ATOMCP.RegisterProperty[$RoseCellKey];
wireGroupKey: ATOM = CP.RegisterProperty[$RoseWireGroup];
wireBehaviorKindKey: ATOM = CP.RegisterProperty[$RoseWireBehaviorKind];
coreCellTypeToRoseCellType: ATOM = CP.RegisterProperty[$RoseCellTypeFromCoreCellType];
Instantiate: PUBLIC PROC [cellType: CellType] RETURNS [simulation: Simulation] = {
simulation ← NEW [SimulationRec ← [
flatRootType: cellType,
rootRecordType: NARROW[cellType.data],
sch: NEW [SchedulingRep ← [sim: NIL]]
]];
simulation.sch.sim ← simulation;
MakeUpPointers[simulation.rootRecordType.internal, NIL];
ComputeBehaviorKinds[simulation];
FindLeafWires[simulation];
MakeRoseWires[simulation];
MakeRoseCells[simulation];
};
upPointerKey: ATOM = CP.RegisterProperty[$RoseUpPointer];
MakeUpPointers: PROC [wire: Wire, parent: Wire] = {
CP.PutWireProp[wire, upPointerKey, parent];
IF wire.elements # NIL THEN {
wire ← wire;
FOR i: INT IN [0 .. wire.elements.size) DO
MakeUpPointers[wire.elements[i], wire];
ENDLOOP;
wire ← wire;
};
};
GetInternalParent: PUBLIC PROC [wire: Wire] RETURNS [parent: Wire] =
{parent ← NARROW[CP.GetWireProp[wire, upPointerKey]]};
IsInternal: PROC [sim: Simulation, wire: Wire] RETURNS [is: BOOL] =
{is ← wire=sim.rootRecordType.internal OR CP.GetWireProp[wire, upPointerKey]#NIL};
ComputeBehaviorKinds: PROC [sim: Simulation] = {
GetPWPWBK: PROC [publicWirePrototype: Wire, specIn: WireBehaviorKind] RETURNS [pwpWBK: WireBehaviorKind] = {
pwpWBK ← GetWBK[publicWirePrototype];
IF pwpWBK = unspecified THEN {
thisSpec: WireBehaviorKind ← SELECT CP.GetWireProp[publicWirePrototype, RoseBind.switchWire] FROM =NIL => specIn, #NIL => switch, ENDCASE => ERROR;
SELECT StructureOfWire[publicWirePrototype] FROM
atom => pwpWBK ← IF thisSpec # unspecified THEN thisSpec ELSE simple;
sequence => {
IF publicWirePrototype.elements.size = 0 THEN ERROR;
FOR i: NAT IN [0 .. publicWirePrototype.elements.size) DO
this: WireBehaviorKind ← GetPWPWBK[publicWirePrototype.elements[i], thisSpec];
IF i = 0 THEN pwpWBK ← this ELSE IF pwpWBK # this THEN ERROR;
ENDLOOP;
pwpWBK ← pwpWBK
};
record => {
someSwitch, someSimple, some: BOOLFALSE;
sim ← sim;
FOR i: NAT IN [0 .. publicWirePrototype.elements.size) DO
sub: WireBehaviorKind ← GetPWPWBK[publicWirePrototype.elements[i], thisSpec];
some ← TRUE;
SELECT sub FROM
simple => someSimple ← TRUE;
switch => someSwitch ← TRUE;
mixed => someSimple ← someSwitch ← TRUE;
unspecified => ERROR;
ENDCASE => ERROR;
ENDLOOP;
IF NOT some THEN ERROR;
pwpWBK ← IF someSimple THEN IF someSwitch THEN mixed ELSE simple ELSE IF someSwitch THEN switch ELSE ERROR;
};
ENDCASE => ERROR;
SetWBK[publicWirePrototype, pwpWBK];
};
IF specIn # unspecified AND specIn # pwpWBK THEN ERROR;
};
GetWBKCopy: PROC [from, to: Wire, proto: BOOL] RETURNS [wbk: WireBehaviorKind] = {
wbk ← GetWBK[to];
IF wbk # unspecified THEN RETURN;
SELECT StructureOfWire[to] FROM
atom => NULL;
record, sequence => {
from ← from;
FOR i: NAT IN [0 .. to.elements.size) DO
fromI: NATIF proto AND StructureOfWire[from]=sequence THEN 0 ELSE i;
[] ← GetWBKCopy[from.elements[fromI], to.elements[i], proto];
ENDLOOP;
to ← to;
};
ENDCASE => ERROR;
SetWBK[to, wbk ← GetWBK[from]];
IF wbk = unspecified THEN ERROR;
};
sim ← sim;
FOR il: CellInstanceList ← sim.rootRecordType.instances, il.rest WHILE il # NIL DO
ci: CellInstance ← il.first;
cic: BehaviorClass ← RoseBindPrivate.GetBehaviorClass[ci.type, FALSE, FALSE, FALSE].class;
[] ← GetPWPWBK[cic.publicWirePrototype, unspecified];
[] ← GetWBKCopy[cic.publicWirePrototype, ci.type.public, TRUE];
ENDLOOP;
sim ← sim;
};
GetWBK: PROC [wire: Wire] RETURNS [wbk: WireBehaviorKind] = {
val: REF ANYCP.GetWireProp[wire, wireBehaviorKindKey];
wbk ← SELECT val FROM
$simple => simple,
$switch => switch,
$mixed => mixed,
NIL => unspecified,
ENDCASE => ERROR;
};
SetWBK: PROC [wire: Wire, wbk: WireBehaviorKind] = {
CP.PutWireProp[
wire,
wireBehaviorKindKey,
SELECT wbk FROM
simple => $simple,
switch => $switch,
mixed => $mixed,
ENDCASE => ERROR
];
};
FindLeafWires: PROC [sim: Simulation] = {
FlwAwWork: PROC [public, actual: Wire, drive: RoseWireType] = {
pwWBK: WireBehaviorKind ← GetWBK[public];
IF pwWBK=unspecified THEN ERROR;
SELECT (IsInternal[sim, actual] AND StructureOfWire[drive.class]=atom AND pwWBK IN [simple..switch]) FROM
FALSE => {
SELECT StructureOfWire[actual] FROM
atom => ERROR;
sequence, record => {
actual ← actual;
FOR i: NAT IN [0 .. actual.elements.size) DO
FlwAwWork[
public.elements[i],
actual.elements[i],
RWTg.SubType[drive, i, TRUE]
];
ENDLOOP;
IF CP.GetWireProp[actual, wireGroupKey] = NIL THEN MarkAboveLeaf[actual];
};
ENDCASE => ERROR;
};
TRUE => {
group: WireGroup ← GetWireGroup[actual];
awWBK: WireBehaviorKind ← GetWBK[actual];
newAWwbk: WireBehaviorKind ← SELECT TRUE FROM
awWBK=unspecified => pwWBK,
awWBK=mixed => ERROR,
awWBK=pwWBK => awWBK,
ENDCASE => switch;
IF awWBK#pwWBK THEN SetWBK[actual, newAWwbk];
SELECT group FROM
aboveLeaf, leaf => NULL;
belowLeaf => BreakWire[GetInternalParent[actual]];
ENDCASE => ERROR;
};
ENDCASE => ERROR;
};
rootWire: Wire ← sim.rootRecordType.internal;
MarkAsLeaf[rootWire];
FOR il: CellInstanceList ← sim.rootRecordType.instances, il.rest WHILE il # NIL DO
ci: CellInstance ← il.first;
cic: BehaviorClass ← RoseBindPrivate.GetBehaviorClass[ci.type, FALSE, FALSE, TRUE].class;
driveType: RoseWireType ← cic.wiring[drive].super.GetType[cic.wiring[drive], ci.actual];
FlwAwWork[ci.type.public, ci.actual, driveType];
ENDLOOP;
sim ← sim;
};
MarkAsLeaf: PROC [wire: Wire] = {
CP.PutWireProp[wire, wireGroupKey, $Leaf];
};
MarkAboveLeaf: PROC [wire: Wire] = {
CP.PutWireProp[wire, wireGroupKey, $AboveLeaf];
};
GetWireGroup: PUBLIC PROC [wire: Wire] RETURNS [wg: WireGroup] = {
val: ATOMNARROW[CP.GetWireProp[wire, wireGroupKey]];
wg ← SELECT val FROM
$Leaf => leaf,
$AboveLeaf => aboveLeaf,
NIL => belowLeaf,
ENDCASE => ERROR;
};
BreakWire: PROC [wire: Wire] = {
pg: WireGroup ← GetWireGroup[wire];
FOR i: NAT IN [0 .. wire.elements.size) DO
child: Wire ← wire.elements[i];
cg: WireGroup ← GetWireGroup[child];
SELECT cg FROM
belowLeaf => MarkAsLeaf[child];
leaf, aboveLeaf => NULL;
ENDCASE => ERROR;
ENDLOOP;
MarkAboveLeaf[wire];
SELECT pg FROM
belowLeaf => BreakWire[GetInternalParent[wire]];
leaf => NULL;
aboveLeaf => ERROR;
ENDCASE => ERROR;
};
MakeRoseWires: PROC [sim: Simulation] = {
Work: PROC [wire: Wire] = {
wg: WireGroup ← GetWireGroup[wire];
SELECT wg FROM
belowLeaf => ERROR;
aboveLeaf => {
wire ← wire;
FOR i: INT IN [0 .. wire.elements.size) DO
Work[wire.elements[i]];
ENDLOOP;
wire ← wire;
};
leaf => {
rw: RoseWire;
rwc: RoseWireClass;
rwt: RoseWireType;
wbk: WireBehaviorKind ← GetWBK[wire];
rwc ← RoseWiring.GetWiring[
wire,
SELECT wbk FROM
simple => simple,
switch => switch,
ENDCASE => ERROR
];
rwt ← rwc.super.GetType[rwc, wire];
CP.PutWireProp[wire, roseWireTypeKey, rwt];
rw ← NEW [RoseWireRep ← [
schIn: sim.sch,
core: wire,
type: rwt,
valPtr: RWTg.CreateUntypedInstance[rwt],
bitCount: rwt.class.super.Bits[rwt.class],
group: wg,
nextPerturbed: notInWireList,
nextAffected: notInWireList,
nextDelayed: notInWireList,
prevDelayed: notInWireList
]];
SetRoseWire[sim, wire, rw];
};
ENDCASE => ERROR;
};
Work[sim.rootRecordType.internal];
};
MakeRoseCells: PROC [sim: Simulation] = {
FOR il: CellInstanceList ← sim.rootRecordType.instances, il.rest WHILE il # NIL DO
ci: CellInstance = NARROW[il.first];
args: REF ANY = CP.GetCellTypeProp[ci.type, RoseBind.argsKey];
rct: RoseCellType = GetRoseCellType[ci.type, TRUE, TRUE];
bc: BehaviorClass = rct.behaviorClass;
pw: Wire = ci.type.public;
rci: RoseCellInstance ← NEW [RoseCellInstanceRep ← [
schIn: sim.sch,
core: ci,
args: args,
type: rct,
effectivePorts: NIL,
connectedWires: NIL,
schedNext: notInCellList,
nextNeeded: notInCellList,
nextNoted: notInCellList,
switchIO: bc.private.createSwitch[pw],
newIO: bc.private.createSimple[pw],
oldIO: bc.private.createSimple[pw],
newDrive: bc.private.createDrive[pw],
oldDrive: bc.private.createDrive[pw]
]];
IF rci.type.behaviorClass.details.CreateState # NIL THEN rci.state ← rci.type.behaviorClass.details.CreateState[args];
[rci.effectivePorts, rci.connectedWires, rci.hasTransducedPort] ← ComputeEffectiveInterface[rci];
CP.PutCellInstanceProp[
ci,
roseCellKey,
Properties.PutProp[
NARROW[CP.GetCellInstanceProp[ci, roseCellKey]],
sim,
rci]];
ENDLOOP;
sim ← sim;
};
GetRoseCellType: PUBLIC PROC [ct: CellType, details, privates: BOOL] RETURNS [rct: RoseCellType] = {
rct ← NARROW[CP.GetCellTypeProp[ct, coreCellTypeToRoseCellType]];
IF rct = NIL THEN {
bc: BehaviorClass;
[bc] ← RoseBindPrivate.GetBehaviorClass[ct, FALSE, FALSE, TRUE];
rct ← NEW [RoseCellTypeRep ← [
behaviorClass: bc,
wireTypes: [
switch: bc.wiring[switch].super.GetType[bc.wiring[switch], ct.public],
simple: bc.wiring[simple].super.GetType[bc.wiring[simple], ct.public],
drive: bc.wiring[drive].super.GetType[bc.wiring[drive], ct.public]
]
]];
CP.PutCellTypeProp[ct, coreCellTypeToRoseCellType, rct];
};
IF details OR privates THEN {
goodDetails, goodPrivate: BOOL;
[goodDetails, goodPrivate] ← RoseBindPrivate.EnsureBCParts[rct.behaviorClass, details, privates];
IF (details AND NOT goodDetails) OR (privates AND NOT goodPrivate) THEN ERROR;
};
};
ComputeEffectiveInterface: PROC [rci: RoseCellInstance] RETURNS [effectivePorts: EffectivePortS, connectedWires: RoseWireS, hasTransducedPort: BOOL] = {
length, index: NAT ← 0;
Count: PROC [wire: Wire] = {
wg: WireGroup ← GetWireGroup[wire];
SELECT wg FROM
belowLeaf => ERROR;
aboveLeaf => {
wire ← wire;
FOR i: INT IN [0 .. wire.elements.size) DO
Count[wire.elements[i]];
ENDLOOP;
wire ← wire;
};
leaf => length ← length + 1;
ENDCASE => ERROR;
};
Fillin: PROC [public, actual: Wire, switchType, simpleType, driveType: RoseWireType, switch, newSimple, oldSimple, newDrive, oldDrive: Ptr, path: PortPath] = {
wg: WireGroup ← GetWireGroup[actual];
SELECT wg FROM
belowLeaf => ERROR;
aboveLeaf => {
actual ← actual;
FOR i: INT IN [0 .. actual.elements.size) DO
Fillin[
public.elements[i],
actual.elements[i],
RWTg.SubType[switchType, i],
RWTg.SubType[simpleType, i],
RWTg.SubType[driveType, i, TRUE],
RWTg.SubPtr[switchType, switch, i],
RWTg.SubPtr[simpleType, newSimple, i],
RWTg.SubPtr[simpleType, oldSimple, i],
RWTg.SubPtr[driveType, newDrive, i, TRUE],
RWTg.SubPtr[driveType, oldDrive, i, TRUE],
PathAppend[path, i]
];
ENDLOOP;
actual ← actual;
};
leaf => {
rw: RoseWire ← GetRoseWire[rci.schIn.sim, actual];
wbkP: WireBehaviorKind ← GetWBK[public];
wbkA: WireBehaviorKind ← GetWBK[actual];
pSimple: BOOLSELECT wbkP FROM
simple => TRUE,
switch => FALSE,
ENDCASE => ERROR;
aSimple: BOOLSELECT wbkA FROM
simple => TRUE,
switch => FALSE,
ENDCASE => ERROR;
transduced: BOOL = (aSimple # pSimple);
me: Slot = [rci, index];
modelType: RoseWireType =
IF pSimple THEN simpleType ELSE switchType;
IF transduced AND aSimple THEN ERROR;
IF transduced THEN hasTransducedPort ← TRUE;
effectivePorts[index] ← [
switch: switch,
newSimple: newSimple,
oldSimple: oldSimple,
newDrive: newDrive,
oldDrive: oldDrive,
type: modelType,
implType: IF transduced THEN switchType ELSE modelType,
path: path,
input: TRUE,
output: TRUE,
XPhobic: pSimple,
transduced: transduced
];
SELECT aSimple FROM
TRUE => {
initialStrength: Strength = none;
prev: Slot = rw.byStrength[initialStrength].last;
effectivePorts[index].curStrength ← initialStrength;
effectivePorts[index].strengthNext ← nilSlot;
effectivePorts[index].strengthPrev ← prev;
IF prev = nilSlot
THEN rw.byStrength[initialStrength].first ← me
ELSE prev.cell.effectivePorts[prev.effectivePortIndex].strengthNext ← me;
rw.byStrength[initialStrength].last ← me;
};
FALSE => {
rw.switchConnections ← CONS[me, rw.switchConnections];
rw.XPhobic ← rw.XPhobic OR effectivePorts[index].XPhobic;
};
ENDCASE => ERROR;
connectedWires[index] ← rw;
index ← index + 1;
};
ENDCASE => ERROR;
};
hasTransducedPort ← FALSE;
Count[rci.core.actual];
effectivePorts ← NEW [EffectivePortSeq[length]];
connectedWires ← NEW [RoseWireSeq[length]];
Fillin[
rci.core.type.public,
rci.core.actual,
rci.type.wireTypes[switch],
rci.type.wireTypes[simple],
rci.type.wireTypes[drive],
RWTg.RefToPtr[rci.switchIO, rci.type.wireTypes[switch]],
RWTg.RefToPtr[rci.newIO, rci.type.wireTypes[simple]],
RWTg.RefToPtr[rci.oldIO, rci.type.wireTypes[simple]],
RWTg.RefToPtr[rci.newDrive, rci.type.wireTypes[drive]],
RWTg.RefToPtr[rci.oldDrive, rci.type.wireTypes[drive]],
NIL
];
IF index # length THEN ERROR;
};
PathAppend: PROC [path: PortPath, index: INT] RETURNS [longer: PortPath] = {
RETURN [IF path = NIL THEN LIST[index] ELSE CONS[path.first, PathAppend[path.rest, index]]];
};
GetRoseCell: PUBLIC PROC [sim: Simulation, ci: CellInstance] RETURNS [rci: RoseCellInstance] = {
propList: Properties.PropList ← NARROW[CP.GetProp[ci.properties, roseCellKey]];
rci ← NARROW[Properties.GetProp[propList, sim]];
};
SetRoseWire: PROC [sim: Simulation, wire: Wire, rw: RoseWire] = {
CP.PutWireProp[
wire,
roseWireKey,
Properties.PutProp[
NARROW[CP.GetWireProp[wire, roseWireKey]],
sim,
rw]];
};
GetRoseWire: PUBLIC PROC [sim: Simulation, w: Wire] RETURNS [rw: RoseWire] = {
propList: Properties.PropList ← NARROW[CP.GetProp[w.properties, roseWireKey]];
rw ← NARROW[Properties.GetProp[propList, sim]];
};
LookupRoseWire: PUBLIC PROC [sim: Simulation, w: Wire] RETURNS [rw: RoseWire] = {
Work: PROC [sim: Simulation, w: Wire, parent: RoseWire, index: NAT, valPtr: Ptr] RETURNS [rw: RoseWire] = {
rw ← GetRoseWire[sim, w];
IF parent # NIL THEN {
IF rw.parent = NIL
THEN {
rw.parent ← parent;
rw.myIndex ← index;
}
ELSE {
IF rw.parent # parent OR rw.myIndex # index THEN ERROR;
};
};
IF rw = NIL THEN {
group: WireGroup = GetWireGroup[w];
flavor: WireFlavor = GetWireFlavor[sim, w];
rwc: RoseWireClass = RoseWiring.GetWiring[w, flavor];
rwt: RoseWireType = rwc.super.GetType[rwc, w];
CP.PutWireProp[w, roseWireTypeKey, rwt];
rw ← NEW [RoseWireRep ← [
schIn: sim.sch,
core: w,
type: rwt,
bitCount: rwt.class.super.Bits[rwt.class],
group: group,
nextPerturbed: notInWireList,
nextAffected: notInWireList,
nextDelayed: notInWireList,
prevDelayed: notInWireList
]];
SELECT group FROM
aboveLeaf => {
rw.valPtr ← IF parent # NIL THEN valPtr ELSE RWTg.CreateUntypedInstance[rwt];
rw.subWires ← NEW [RoseWireSeq[w.elements.size]];
FOR i: NAT IN [0 .. rw.subWires.length) DO
subPtr: Ptr = RWTg.SubPtr[rwt, rw.valPtr, i];
rw.subWires[i] ← Work[sim, w.elements[i], rw, i, subPtr];
ENDLOOP;
rw ← rw;
};
leaf => ERROR;
belowLeaf => {
parent: Wire = GetInternalParent[w];
myIndex: NAT = GetIndex[parent, w];
rw.parent ← Work[sim, parent, NIL, LAST[NAT], nilPtr];
rw.myIndex ← myIndex;
rw.valPtr ← RWTg.SubPtr[rw.parent.type, rw.parent.valPtr, myIndex];
};
ENDCASE => ERROR;
SetRoseWire[sim, w, rw];
};
};
rw ← Work[sim, w, NIL, LAST[NAT], nilPtr];
};
RoseWireSource: PUBLIC PROC [rw: RoseWire] RETURNS [sim: Simulation, w: Wire] = {
sim ← rw.schIn.sim;
w ← rw.core;
};
GetWireFlavor: PROC [sim: Simulation, w: Wire] RETURNS [flavor: WireFlavor] = {
group: WireGroup = GetWireGroup[w];
SELECT group FROM
aboveLeaf => {
flavor ← simple;
FOR i: INT IN [0 .. w.elements.size) DO
sf: WireFlavor = GetWireFlavor[sim, w.elements[i]];
SELECT sf FROM
simple => NULL;
switch => {flavor ← switch; EXIT};
drive => ERROR;
ENDCASE => ERROR;
ENDLOOP;
};
leaf => flavor ← GetRoseWire[sim, w].type.class.super.flavor;
belowLeaf => {
parent: Wire = GetInternalParent[w];
flavor ← GetWireFlavor[sim, parent];
};
ENDCASE => ERROR;
};
GetIndex: PROC [parent, child: Wire] RETURNS [index: NAT] = {
FOR index IN [0 .. parent.elements.size) DO
IF parent.elements[index] = child THEN RETURN;
ENDLOOP;
ERROR;
};
flattenToBehavior: PUBLIC CoreFlatten.FlattenControl ← NEW [CoreFlatten.FlattenControlRec ← [DecideByBehavior, NIL]];
DecideByBehavior: PROC [data: REF ANY, who: CoreFlatten.InstantiationPath] RETURNS [ed: CoreFlatten.ExpandDecision] = {
ci: CellInstance = who.first;
ed ← IF RoseBindPrivate.GetBehaviorClass[ci.type, TRUE, FALSE, FALSE].goodDetails THEN leaf ELSE expand;
};
FlattenStructure: PUBLIC PROC [from: Core.CellType] RETURNS [fc: CoreFlatten.FlattenControl] = {
fc ← NEW [CoreFlatten.FlattenControlRec ← [DecideByStructure, from]];
};
DecideByStructure: PROC [data: REF ANY, who: CoreFlatten.InstantiationPath] RETURNS [ed: CoreFlatten.ExpandDecision] = {
ct: CellType ← IF who # NIL THEN who.first.type ELSE NARROW[data];
WHILE ct.class.recast # NIL DO
ct ← CoreOps.Recast[ct];
ENDLOOP;
WITH ct.data SELECT FROM
rct: CoreClasses.RecordCellType => RETURN [expand];
ENDCASE => RETURN [leaf];
};
END.