RosemaryCreate.mesa
last changed by Barth, June 9, 1983 11:14 am
Last Edited by: Spreitzer, September 15, 1983 10:51 am
DIRECTORY AMBridge, AMTypes, Atom, IO, List, OrderedSymbolTableRef, Rope, Rosemary, RosemaryInsides;
RosemaryCreate:
CEDAR
PROGRAM
IMPORTS AMBridge, AMTypes, Atom, IO, List, OSTR: OrderedSymbolTableRef, Rope, Rosemary, RosemaryInsides
EXPORTS Rosemary =
BEGIN OPEN Rosemary, RosemaryInsides;
Warning: PUBLIC SIGNAL [msg: ROPE, data: REF ANY ← NIL] = CODE;
Error: PUBLIC ERROR [msg: ROPE, data: REF ANY ← NIL] = CODE;
InterfaceMismatch:
PUBLIC
ERROR [cell: Cell,
index: CARDINAL,
expected, got: SignalType] = CODE;
Stop: PUBLIC SIGNAL [msg: ROPE ← NIL, data: REF ANY ← NIL] = CODE;
Unspecified: PUBLIC REF ANY ← NEW [INT];
cellClasses: PUBLIC SymbolTable ← OSTR.CreateTable[CompareCellClasses];
roots: PUBLIC SymbolTable ← OSTR.CreateTable[CompareComponents];
Data Structure manipulation:
RegisterCellClass:
PUBLIC
PROC [className:
ROPE, expandProc: ExpandProc ←
NIL, ioCreator: IOCreator ←
NIL, initializer: Initializer ←
NIL, evalProc, testProc: EvalProc ←
NIL, ports: Ports, ioTemplate:
REF
ANY ← Unspecified] =
BEGIN
cc: CellClass ←
NEW [CellClassRep ← [
name: className,
expand: expandProc,
ioCreator: ioCreator,
initializer: initializer,
eval: evalProc,
test: testProc,
ports: ports,
ioWordCount: 0,
ioTemplate: ioTemplate,
firstInstance: NIL]];
old: CellClass ← NARROW[cellClasses.Delete[className]];
FOR portIndex:
CARDINAL
IN [0 .. ports.length)
DO
port: Port ← cc.ports[portIndex];
cc.ioWordCount ← MAX[cc.ioWordCount, port.firstWord + port.wordCount];
IF port.type = NIL THEN ERROR Error[IO.PutFR["No SignalType given for Port %g", IO.rope[port.name]]];
ENDLOOP;
IF old #
NIL
THEN
BEGIN
IF old.firstInstance #
NIL
THEN
BEGIN
ok: BOOLEAN ← TRUE;
IF old.ports.length # cc.ports.length THEN ok ← FALSE
ELSE
BEGIN
FOR portIndex:
CARDINAL
IN [0 .. cc.ports.length)
DO
IF (
cc.ports[portIndex].firstWord # old.ports[portIndex].firstWord OR
cc.ports[portIndex].wordCount # old.ports[portIndex].wordCount OR
cc.ports[portIndex].type # old.ports[portIndex].type OR
cc.ports[portIndex].input # old.ports[portIndex].input OR
cc.ports[portIndex].output # old.ports[portIndex].output OR
NOT cc.ports[portIndex].name.Equal[old.ports[portIndex].name])
THEN {ok ← FALSE; EXIT};
ENDLOOP;
END;
IF NOT ok THEN ERROR Error[IO.PutFR["Redefinition of Class %g not allowed because of different interface", IO.rope[className]]];
END;
FOR instance: Cell ← old.firstInstance, instance.nextInstance
WHILE instance #
NIL
DO
IF instance.class # old THEN ERROR;
instance.class ← cc;
IF instance.expansion = Leaf
THEN
BEGIN
IF instance.realCellStuff.eval # old.eval THEN ERROR;
instance.realCellStuff.eval ← cc.eval;
END;
IF instance.expansion # Inline
AND instance.realCellStuff.newIO #
NIL
THEN
TRUSTED BEGIN
oldoldWP, oldnewWP: WordPtr;
holdOld ← instance.realCellStuff.oldIO; --prevent GC
holdNew ← instance.realCellStuff.newIO;
oldoldWP ← instance.realCellStuff.oldIOAsWP;
oldnewWP ← instance.realCellStuff.newIOAsWP;
cc.ioCreator[instance, instance.realCellStuff.initData];
instance.realCellStuff.newIOAsWP ← LOOPHOLE[instance.realCellStuff.newIO];
instance.realCellStuff.oldIOAsWP ← LOOPHOLE[instance.realCellStuff.oldIO];
FOR i:
CARDINAL
IN [0 .. cc.ioWordCount)
DO
(instance.realCellStuff.oldIOAsWP + i)^ ← (oldoldWP + i)^;
(instance.realCellStuff.newIOAsWP + i)^ ← (oldnewWP + i)^;
ENDLOOP;
END;
ENDLOOP;
END;
cellClasses.Insert[cc];
END;
holdOld, holdNew: REF ANY ← NIL;
CreateTopCell:
PUBLIC
PROC [instanceName, className:
ROPE, initData:
REF
ANY ←
NIL, decider: ExpandDeciderClosure]
RETURNS [cell: Cell] =
BEGIN
class: CellClass;
class ← NARROW[cellClasses.Lookup[className]];
IF class = NIL THEN ERROR Error[IO.PutFR["No such class: %g", IO.rope[className]]];
cell ←
NEW [CellRep ← [
name: instanceName, class: class,
parent: NIL, leftChild: NIL, rightSibling: NIL, firstInternalNode: NIL,
internalNodes: OSTR.CreateTable[CompareNodes],
components: OSTR.CreateTable[CompareComponents],
interfaceNodes: NEW [NodeSR[0]],
other: NIL,
type: Shadow, expansion: Inline,
realCellStuff: NIL]];
cell.other ← List.PutAssoc[$ExpandDeciderClosure, decider, cell.other];
FinishCreatingCell[cell, NIL, initData];
roots.Insert[cell !OSTR.DuplicateKey => ERROR Error[IO.PutFR["Duplicated Root name: %g", IO.rope[cell.name]]]];
END;
CreateNode:
PUBLIC
PROC [within: Cell, name:
ROPE, type: SignalType ←
NIL
--means unspecified--]
RETURNS [node: Node] =
BEGIN
node ←
NEW [NodeRep ← [
name: name,
type: type,
visible: [NIL, LAST[CARDINAL]] ]];
within.internalNodes.Insert[node !OSTR.DuplicateKey => ERROR Error[IO.PutFR["Duplicated Node name: %g", IO.rope[name]]]];
node.next ← within.firstInternalNode;
--link in wrong order now; fix up when done expanding--
within.firstInternalNode ← node;
END;
CreateCell:
PUBLIC
PROC [within: Cell, instanceName, className, interfaceNodes:
ROPE, initData:
REF
ANY ←
NIL]
RETURNS [cell: Cell] =
BEGIN
class: CellClass;
class ← NARROW[cellClasses.Lookup[className]];
IF class = NIL THEN ERROR Error[IO.PutFR["No such class: %g", IO.rope[className]]];
cell ←
NEW [CellRep ← [
name: instanceName, class: class,
parent: within, leftChild: NIL, rightSibling: NIL, firstInternalNode: NIL,
internalNodes: OSTR.CreateTable[CompareNodes],
components: OSTR.CreateTable[CompareComponents],
interfaceNodes: NEW [NodeSR[class.ports.length]],
other: NIL,
type: Shadow, expansion: Inline,
realCellStuff: NIL]];
FinishCreatingCell[cell, interfaceNodes, initData];
IF cell.type = Real THEN ScheduleCell[cell];
END;
AddNodeWatcher:
PUBLIC
PROC [node: Node, watcher: NodeWatcher, priority: Priority ← 0] =
BEGIN
node.watchers[priority] ← CONS[watcher, node.watchers[priority]];
END;
RemoveNodeWatcher:
PUBLIC
PROC [node: Node, watcher: NodeWatcher, priority: Priority ← 0] =
BEGIN
cur, prev: NodeWatcherList ← NIL;
FOR cur ← node.watchers[priority], cur.rest
WHILE cur #
NIL
DO
IF cur.first = watcher
THEN
{IF prev = NIL THEN node.watchers[priority] ← cur.rest ELSE prev.rest ← cur.rest;
RETURN};
prev ← cur;
ENDLOOP;
END;
FilterCellWatcher:
PROC [watcher: CellWatcher, watchers: CellWatcherList]
RETURNS [ohne: CellWatcherList] =
BEGIN
cur, prev: CellWatcherList ← NIL;
ohne ← watchers;
FOR cur ← watchers, cur.rest
WHILE cur #
NIL
DO
IF cur.first = watcher
THEN
{IF prev = NIL THEN ohne ← cur.rest ELSE prev.rest ← cur.rest;
RETURN};
prev ← cur;
ENDLOOP;
END;
AddCellEventWatcher:
PUBLIC
PROC [cell: Cell, event:
ATOM, watcher: CellWatcher] =
BEGIN
SELECT event
FROM
$Schedule => {
IF cell.type = Shadow
THEN
ERROR Error[
IO.PutFR["Cell %g not Real",
IO.rope[cell.name]]];
cell.realCellStuff.schedWatchers ← CONS[watcher, cell.realCellStuff.schedWatchers]};
$Eval => {
IF cell.type = Shadow
THEN
ERROR Error[
IO.PutFR["Cell %g not Real",
IO.rope[cell.name]]];
cell.realCellStuff.evalWatchers ← CONS[watcher, cell.realCellStuff.evalWatchers]};
ENDCASE =>
BEGIN
wl: CellWatcherList ← NARROW[List.Assoc[key: event, aList: cell.other]];
wl ← CONS[watcher, wl];
cell.other ← List.PutAssoc[key: event, val: wl, aList: cell.other];
END;
END;
RemoveCellEventWatcher:
PUBLIC
PROC [cell: Cell, event:
ATOM, watcher: CellWatcher] =
BEGIN
SELECT event
FROM
$Schedule => {
IF cell.type = Shadow
THEN
ERROR Error[
IO.PutFR["Cell %g not Real",
IO.rope[cell.name]]];
cell.realCellStuff.schedWatchers ← FilterCellWatcher[watcher, cell.realCellStuff.schedWatchers]};
$Eval => {
IF cell.type = Shadow
THEN
ERROR Error[
IO.PutFR["Cell %g not Real",
IO.rope[cell.name]]];
cell.realCellStuff.evalWatchers ← FilterCellWatcher[watcher, cell.realCellStuff.evalWatchers]};
ENDCASE =>
BEGIN
wl: CellWatcherList ← NARROW[List.Assoc[key: event, aList: cell.other]];
wl ← FilterCellWatcher[watcher, wl];
cell.other ← List.PutAssoc[key: event, val: wl, aList: cell.other];
END;
END;
NotifyCellEvent:
PUBLIC
PROC [cell: Cell, event:
ATOM] =
BEGIN
wl: CellWatcherList ← NARROW[List.Assoc[key: event, aList: cell.other]];
abort: BOOLEAN ← FALSE;
WHILE wl #
NIL
DO
wl.first.notify[cell: cell, clientData: wl.first.clientData !ABORTED => {abort ← TRUE; CONTINUE}];
wl ← wl.rest;
ENDLOOP;
IF abort THEN ERROR ABORTED;
END;
GlobalWatcherList: TYPE = LIST OF GlobalWatcher;
gwKey: ATOM ← Atom.Gensym[];
FilterGlobalWatcher:
PROC [watcher: GlobalWatcher, watchers: GlobalWatcherList]
RETURNS [ohne: GlobalWatcherList] =
BEGIN
cur, prev: GlobalWatcherList ← NIL;
ohne ← watchers;
FOR cur ← watchers, cur.rest
WHILE cur #
NIL
DO
IF cur.first = watcher
THEN
{IF prev = NIL THEN ohne ← cur.rest ELSE prev.rest ← cur.rest;
RETURN};
prev ← cur;
ENDLOOP;
END;
AddGlobalEventWatcher:
PUBLIC
PROC [event:
ATOM, watcher: GlobalWatcher] =
BEGIN
watchers: GlobalWatcherList ← NARROW[Atom.GetProp[atom: event, prop: gwKey]];
watchers ← CONS[watcher, watchers];
Atom.PutProp[atom: event, prop: gwKey, val: watchers];
END;
RemoveGlobalEventWatcher:
PUBLIC
PROC [event:
ATOM, watcher: GlobalWatcher] =
BEGIN
watchers: GlobalWatcherList ← NARROW[Atom.GetProp[atom: event, prop: gwKey]];
Atom.PutProp[atom: event, prop: gwKey, val: FilterGlobalWatcher[watcher, watchers]];
END;
NotifyGlobalEvent:
PUBLIC
PROC [event:
ATOM] =
BEGIN
wl: GlobalWatcherList ← NARROW[Atom.GetProp[atom: event, prop: gwKey]];
abort: BOOLEAN ← FALSE;
WHILE wl #
NIL
DO
wl.first.notify[clientData: wl.first.clientData !ABORTED => {abort ← TRUE; CONTINUE}];
wl ← wl.rest;
ENDLOOP;
IF abort THEN ERROR ABORTED;
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;
IDBreak:
IO.BreakProc =
{
RETURN [
SELECT char
FROM
IO.SP, IO.CR, IO.LF, IO.TAB => sepr,
IN ['a..'z], IN ['A..'Z], IN['0..'9] => other,
ENDCASE => break]};
FillInInterfaceNodes:
PROC [cell: Cell, interfaceNodes:
ROPE] =
BEGIN
index: CARDINAL ← 0;
in: IO.STREAM ← IO.RIS[interfaceNodes];
[] ← in.GetIndex[]; --wake up generic GetIndex impl
in.SkipOver[IO.WhiteSpace];
IF
NOT in.EndOf[]
THEN
DO
name: ROPE ← in.GetToken[IDBreak];
key: ROPE;
this: CARDINAL;
in.SkipOver[IO.WhiteSpace];
IF (
IF in.EndOf[]
THEN
FALSE
ELSE in.PeekChar[] = ':)
THEN
BEGIN
key ← name;
IF in.GetChar[] # ': THEN ERROR;
IF in.EndOf[] THEN ERROR Error[IO.PutFR["Interface spec syntax error, at %g", IO.int[in.GetIndex[]]]];
name ← in.GetToken[IDBreak];
IF (this ← GetIndex[cell.class.ports, key]) = notFound THEN ERROR Error[IO.PutFR["No such port (%g) for CellClass %g", IO.rope[key], IO.rope[cell.class.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.class.name]]];
key ← cell.class.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] ← LookupNode[cell.parent, name];
IF cell.interfaceNodes[this] = NIL THEN ERROR Error[IO.PutFR["Node %g not found", IO.rope[name]]];
IF cell.class.ports[this].output AND cell.interfaceNodes[this].unwriteability > 0 THEN SIGNAL Warning[IO.PutFR["Node %g is, but shouldn't be, written to by port %g of cell %g", IO.rope[cell.interfaceNodes[this].name], IO.rope[cell.class.ports[this].name], IO.rope[cell.name]]];
index ← index + 1;
in.SkipOver[IO.WhiteSpace];
IF in.EndOf[] THEN EXIT;
IF in.GetChar[] # ', THEN ERROR Error[IO.PutFR["Interface spec syntax error, 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.class.ports[this].name;
cell.interfaceNodes[this] ← LookupNode[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]]]
ELSE IF cell.class.ports[this].output AND cell.interfaceNodes[this].unwriteability > 0 THEN SIGNAL Warning[IO.PutFR["Node %g is, but shouldn't be, written to by port %g of cell %g", IO.rope[cell.interfaceNodes[this].name], IO.rope[cell.class.ports[this].name], IO.rope[cell.name]]];
END;
ENDLOOP;
in.Close[];
END;
LookupNode:
PROC [cell: Cell, name:
ROPE]
RETURNS [node: Node] =
BEGIN
index: CARDINAL;
IF (node ← NARROW[cell.internalNodes.Lookup[name]]) # NIL THEN RETURN [node];
IF (index ← GetIndex[cell.class.ports, name]) # notFound THEN RETURN [cell.interfaceNodes[index]];
node ← NIL;
END;
FinishCreatingCell:
PROC [cell: Cell, interfaceNodes:
ROPE, initData:
REF
ANY ←
NIL] =
BEGIN
class: CellClass ← cell.class;
thisChild, lastChild: Cell;
thisNode, lastNode: Node;
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 ← class.firstInstance;
class.firstInstance ← cell;
FillInInterfaceNodes[cell, interfaceNodes];
cell.expansion ← FindAndUseExpandDecider[cell];
SELECT cell.expansion
FROM
Inline =>
BEGIN
cell.type ← Shadow;
cell.realCellStuff ← NIL;
FOR index:
CARDINAL
IN [0 .. class.ports.length)
DO
interfaceNode: Node ← cell.interfaceNodes[index];
IF NOT class.ports[index].output THEN interfaceNode.unwriteability ← interfaceNode.unwriteability + 1;
ENDLOOP;
class.expand[thisCell: cell, initData: initData];
FOR index:
CARDINAL
IN [0 .. class.ports.length)
DO
interfaceNode: Node ← cell.interfaceNodes[index];
IF NOT class.ports[index].output THEN interfaceNode.unwriteability ← interfaceNode.unwriteability - 1;
ENDLOOP;
END;
Leaf, Nested =>
BEGIN
cell.type ← Real;
cell.realCellStuff ← NEW [RealCellStuffRep ← [schedNext: notInSchedule,
newIO: NIL, oldIO: NIL,
newIOAsWP: NIL, oldIOAsWP: NIL,
initData: initData,
state: NIL,
eval: class.eval]];
FOR portIndex:
CARDINAL
IN [0..class.ports.length)
DO
node: Node ← cell.interfaceNodes[portIndex];
targType: SignalType ← cell.class.ports[portIndex].type;
IF node.type = NIL THEN node.type ← targType;
IF targType # node.type THEN ERROR InterfaceMismatch[cell: cell, index: portIndex, expected: targType, got: node.type];
IF cell.class.ports[portIndex].input THEN node.readers ← CONS[[cell, portIndex], node.readers];
NoteMaybeVisible[node, [cell, portIndex]];
ENDLOOP;
IF class.ioCreator # NIL THEN class.ioCreator[cell: cell, initData: initData]
ELSE IF class.ioWordCount > 0 THEN ERROR Error[IO.PutFR["No IOCreator for class %g", IO.rope[class.name]]];
cell.realCellStuff.newIOAsWP ← LOOPHOLE[cell.realCellStuff.newIO];
cell.realCellStuff.oldIOAsWP ← LOOPHOLE[cell.realCellStuff.oldIO];
FOR portIndex:
CARDINAL
IN [0 .. class.ports.length)
DO
targType: SignalType ← cell.class.ports[portIndex].type;
IF targType.init # NIL THEN targType.init[SocketToWP[[cell, portIndex]], targType.typeData];
ENDLOOP;
IF class.initializer # NIL THEN class.initializer[cell: cell, initData: initData, leafily: cell.expansion = Leaf];
IF cell.expansion = Nested
THEN
BEGIN
insides: Structure;
cell.realCellStuff.eval ← EvalStructure;
cell.realCellStuff.state ← insides ←
NEW [StructureRep ← [
container: cell,
mirror:
NEW [CellRep ← [
name: cell.name.Cat["-mirror"],
class: GetMirrorClass[cell.class],
parent: cell,
leftChild: NIL,
rightSibling: NIL,
firstInternalNode: NIL,
internalNodes: NIL,
components: NIL,
interfaceNodes: NIL,
other: NIL,
type: Real,
expansion: Leaf,
realCellStuff:
NEW [RealCellStuffRep ← [
schedNext: notInSchedule,
newIO: NIL, oldIO: NIL,
newIOAsWP: NIL, oldIOAsWP: NIL,
state: NIL,
eval: NIL]]]],
schedFirst: NIL, schedLast: NIL,
insideNodes: NEW [NodeSR[class.ports.length]] ]];
insides.mirror.interfaceNodes ← insides.insideNodes;
FOR index:
CARDINAL
IN [0 .. class.ports.length)
DO
outsideNode: Node ← cell.interfaceNodes[index];
insideNode: Node ← CreateNode[within: cell, name: class.ports[index].name, type: outsideNode.type];
insides.insideNodes[index] ← insideNode;
NoteMaybeVisible[insideNode, [insides.mirror, index]];
IF cell.class.ports[index].output THEN insideNode.readers ← CONS[[insides.mirror, index], insideNode.readers];
IF NOT class.ports[index].output THEN insideNode.unwriteability ← insideNode.unwriteability + 1;
ENDLOOP;
[insides.mirror.realCellStuff.oldIO, insides.mirror.realCellStuff.newIO] ← MakeMirrorIO[cell];
insides.mirror.realCellStuff.newIOAsWP ← LOOPHOLE[insides.mirror.realCellStuff.newIO];
insides.mirror.realCellStuff.oldIOAsWP ← LOOPHOLE[insides.mirror.realCellStuff.oldIO];
class.expand[thisCell: cell, initData: initData];
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;
END;
NoteMaybeVisible:
PROC [node: Node, socket: Socket] =
INLINE
BEGIN
IF node.visible.cell = NIL THEN node.visible ← socket
ELSE IF node.visible.cell.class.ports[node.visible.index].output THEN RETURN
ELSE node.visible ← socket;
END;
MakeMirrorIO:
PROC [cell: Cell]
RETURNS [a, b:
REF
ANY] =
TRUSTED
BEGIN
org, aTV, bTV: AMTypes.TypedVariable;
type: AMTypes.Type;
IF cell.realCellStuff.newIO = NIL THEN RETURN [NIL, NIL];
org ← AMBridge.TVForReferent[cell.realCellStuff.newIO];
type ← AMTypes.TVType[org];
aTV ← AMTypes.New[type];
AMTypes.Assign[aTV, org];
a ← AMBridge.RefFromTV[aTV];
bTV ← AMTypes.New[type];
AMTypes.Assign[bTV, org];
b ← AMBridge.RefFromTV[bTV];
END;
GetMirrorClass:
PROC [class: CellClass]
RETURNS [mirrorClass: CellClass] =
BEGIN
name: ROPE ← class.name.Concat["-mirror"];
asAny: REF ANY;
IF (asAny ← cellClasses.Lookup[name]) # NIL THEN RETURN [NARROW[asAny]];
RegisterCellClass[className: name, ports: MirrorPorts[class.ports]];
mirrorClass ← NARROW[cellClasses.Lookup[name]];
END;
MirrorPorts:
PUBLIC
PROC [fwd: Ports]
RETURNS [bkwd: Ports] =
BEGIN
bkwd ← NEW [PortsRep[fwd.length]];
FOR i:
CARDINAL
IN [0 .. fwd.length)
DO
bkwd[i] ← fwd[i];
bkwd[i].input ← fwd[i].output;
bkwd[i].output ← fwd[i].input;
ENDLOOP;
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 class %g", IO.rope[cell.class.name]]];
FOR temp: Cell ← cell, temp.parent
WHILE temp #
NIL
DO
asAny: REF ANY ← List.Assoc[$ExpandDeciderClosure, temp.other];
edc: ExpandDeciderClosure;
try: ExpandDecision;
IF asAny = NIL THEN LOOP;
edc ← NARROW[asAny];
try ← edc.Decide[cell, edc.otherData];
RETURN [IF Possible[cell, try] THEN try ELSE ed];
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];
Possible:
PUBLIC
PROC [cell: Cell, whatToDo: ExpandDecision]
RETURNS [possible:
BOOLEAN] =
BEGIN
RETURN [
SELECT whatToDo
FROM
Leaf => cell.class.eval # NIL AND (IF cell.class.ioWordCount > 0 THEN cell.class.ioCreator # NIL ELSE TRUE),
Nested => cell.class.expand # NIL AND (IF cell.class.ioWordCount > 0 THEN cell.class.ioCreator # NIL ELSE TRUE),
Inline => cell.class.expand # NIL AND cell.parent # NIL,
ENDCASE => ERROR];
END;
CompareNodes:
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;
CompareComponents:
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;
CompareCellClasses:
OSTR.CompareProc =
BEGIN
ToKey:
SAFE
PROC [ref:
REF
ANY]
RETURNS [
ROPE] =
{
RETURN [
WITH ref
SELECT
FROM
r: ROPE => r, cc: CellClass => cc.name, ENDCASE => ERROR]};
RETURN [ToKey[r1].Compare[ToKey[r2]]];
END;
END.