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]; 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. œRosemaryCreate.mesa last changed by Barth, June 9, 1983 11:14 am Last Edited by: Spreitzer, September 15, 1983 10:51 am Data Structure manipulation: Ê{˜Jšœ™Jšœ,™,J™6Icode˜KšÏk œœ?˜dK˜šÐbxœœœ˜Kšœœœ8˜gKšœ ˜—K˜Kšœœ˜%K˜KšÏbœœœœœœœœ˜?K˜KšŸœœœœœœœœ˜—Kšœœœ˜Kšœ˜—Kšœ˜—Kš œœœœœNœ˜€Kšœ˜—šœ;œ œ˜UKšœœœ˜#K˜šœ˜!Kš˜Kšœ(œœ˜5Kšœ&˜&Kšœ˜—šœœ œ˜JKšœ˜ K˜Kšœ(Ïc ˜4Kšœ'˜'K˜,K˜,K˜8Kšœ#œ˜JKšœ#œ˜Jšœœœ˜+Kšœ:˜:Kšœ:˜:Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—K˜Kšœ˜—K˜Kšœœœœ˜ K˜š  œœœœ œœœ!œ˜‰Kš˜K˜Kšœœ ˜.Kš œ œœœœœ˜Sšœœ ˜K˜!Kš œœ œœœ˜GKšœœ˜.Kšœ œ ˜0Kšœœ ˜ Kšœœ˜ Kšœ ˜ Kšœœ˜—K˜GKšœœ ˜(Kš œœœœ#œ˜oKšœ˜—K˜š  œœœœœ¢œœ˜wKš˜šœœ ˜K˜ Kšœ ˜ Kšœ œœœ˜"—Kš œ"œœœ#œ˜yK˜%Kš¢7˜7K˜ Kšœ˜—K˜š  œœœ9œ œœœœ˜…Kš˜K˜Kšœœ ˜.Kš œ œœœœœ˜Sšœœ ˜K˜!Kšœœœœ˜JKšœœ˜.Kšœ œ ˜0Kšœœ˜1Kšœœ˜ Kšœ ˜ Kšœœ˜—K˜3Kšœœ˜,Kšœ˜—K˜š œœœ=˜XKš˜Kšœœ#˜AKšœ˜—K˜š œœœ=˜[Kš˜Kšœœ˜!šœ)œœ˜>šœ˜Kš œœœœ$œ˜QKšœ˜—K˜ Kšœ˜—Kšœ˜—K˜š œœ3œ˜kKš˜Kšœœ˜!K˜šœœœ˜/šœ˜Kš œœœœœ˜>Kšœ˜—K˜ Kšœ˜—Kšœ˜—K˜š œœœœ˜RKš˜šœ˜š œœœœœœ˜gKšœ#œ-˜T—š œ œœœœœ˜cKšœ"œ,˜R—šœ˜Kšœœ,˜HKšœœ˜KšœC˜CKšœ˜——Kšœ˜—K˜š œœœœ˜UKš˜šœ˜š œœœœœœ˜gKšœa˜a—š œ œœœœœ˜cKšœ_˜_—šœ˜Kšœœ,˜HK˜$K˜CKšœ˜——Kšœ˜—K˜š œœœœ˜8Kš˜Kšœœ,˜HKšœœœ˜šœœ˜Kšœ=œ œœ˜bK˜ Kšœ˜—Kšœœœœ˜Kšœ˜—K˜Kšœœœœ˜0Kšœœ˜K˜š œœ7œ˜sKš˜Kšœœ˜#K˜šœœœ˜/šœ˜Kš œœœœœ˜>Kšœ˜—K˜ Kšœ˜—Kšœ˜—K˜š œœœ œ˜JKš˜Kšœœ)˜MKšœ œ˜#Kšœ6˜6Kšœ˜—K˜š œœœ œ˜MKš˜Kšœœ)˜MKšœT˜TKšœ˜—K˜š œœœ œ˜.Kš˜Kšœœ)˜GKšœœœ˜šœœ˜Kšœ1œ œœ˜VK˜ Kšœ˜—Kšœœœœ˜Kšœ˜—K˜š  œœœœœ œ˜KKš˜šœœœ˜'Kšœœœ˜,Kšœ˜—Kšœ ˜Kšœ˜—K˜š œœ ˜šœœœ˜Kšœœœœœœœœ ˜$Kšœ œ œ˜.Kšœ ˜——K˜š œœœ˜?Kš˜Kšœœ˜Kš œœœœœ˜'Kšœ¢˜3Kšœ œ ˜šœœ œ˜Kšœœ˜"Kšœœ˜ Kšœœ˜Kšœ œ ˜š œœ œœœ˜:Kš˜K˜ Kšœœœ˜ Kš œ œœœ-œ˜fKšœ˜Kš œ5œœœ-œ œ˜ Kš˜—šœ˜ Kš œ%œœœ-œ œ˜‘Kšœ*˜*Kšœ˜—Kšœœœœœ,œ œ˜ŠK˜:Kš œœœœœœ˜bKšœœ.œœ œIœ'œ$œ˜•K˜Kšœ œ ˜Kšœ œœ˜Kš œœœœ-œ˜mKšœ˜—šœœœ#˜:šœœ˜'Kš˜Kšœœ˜)K˜:Kšœœœœœ*œ œ˜ˆKšœœœ.œœ œIœ'œ$œ˜šKšœ˜—Kšœ˜—K˜ Kšœ˜—K˜š  œœœœ˜@Kš˜Kšœœ˜Kš œ œ%œœœ˜MKšœ7œœ˜bKšœœ˜ Kšœ˜—K˜š  œœœ œœœ˜VKš˜K˜K˜K˜šœœ˜Kš˜Kš œ$œœœ#œ˜€K˜*Kš¢I˜IK˜Kšœ˜—K˜(K˜K˜+Kšœ/˜/šœ˜šœ ˜K˜Kšœœ˜šœœœ˜3Kšœ1˜1KšœœœA˜fKšœ˜—K˜1šœœœ˜3Kšœ1˜1KšœœœA˜fKšœ˜—Kšœ˜—šœ˜K˜šœG˜GKšœœ œ˜Kšœ œ œ˜K˜Kšœœ˜ Kšœ˜—šœ œœ˜5Kšœ,˜,K˜8Kšœ œœ˜-KšœœœU˜wKšœ#œœ"˜_Kšœ*˜*Kšœ˜—Kšœœœ0˜MKš œœœœœ$œ˜kKšœœ˜BKšœœ˜Bšœ œœ˜7K˜8KšœœœA˜\Kšœ˜—KšœœœS˜ršœ˜Kš˜Kšœ˜K˜(šœ%œ˜:Kšœ˜šœœ ˜Kšœ˜Kšœ"˜"Kšœ ˜ Kšœ œ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœ œ˜Kšœœ˜Kšœœ˜ Kšœ ˜ K˜šœœ˜(Kšœ˜Kšœœ œ˜Kšœ œ œ˜Kšœœ˜ Kšœœ˜——Kšœ œ œ˜ Kšœ œ!˜1—K˜4šœœœ˜3Kšœ/˜/Kšœc˜cKšœ(˜(Kšœ6˜6Kšœ œœ.˜nKšœœœ;˜`Kšœ˜—Kšœ^˜^Kšœ)œ%˜VKšœ)œ%˜VK˜1Kšœ˜—Kšœ˜—Kšœœ˜—Kšœ œ˜K˜šœ œ˜K˜)K˜#K˜K˜Kšœ˜—K˜Kšœ œ˜K˜"šœ œ˜K˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ"˜"Kšœ˜—K˜š œœ ˜