[Indigo]<Rosemary>2.3>Rosemary.df=>RoseCreateImpl.Mesa
Last Edited by: Spreitzer, May 1, 1984 4:10:06 pm PDT
DIRECTORY AMBridge, AMTypes, Atom, Convert, FS, IO, List, MessageWindow, OrderedSymbolTableRef, Pausers, Rope, RoseCreate, RoseEvents, RoseRun, RoseTypes, ViewerOps, ViewRec;
RoseCreateImpl: CEDAR PROGRAM
IMPORTS AMBridge, AMTypes, Atom, Convert, FS, IO, List, MessageWindow, OSTR: OrderedSymbolTableRef, Pausers, Rope, RoseEvents, RoseRun, RoseTypes, ViewerOps, ViewRec
EXPORTS RoseCreate, RoseTypes =
BEGIN OPEN RoseCreate, RoseTypes;
InterfaceMismatch: PUBLIC ERROR [cell: Cell,
index: CARDINAL,
expected, got: NodeType] = CODE;
cellClasses: SymbolTable ← OSTR.CreateTable[CompareCellClasses];
roots: SymbolTable ← OSTR.CreateTable[CompareComponents];
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;
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;
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;
RegisterCellClass: PUBLIC PROC [className: ROPE, expandProc: ExpandProc ← NIL, ioCreator: IOCreator ← NIL, initializer: Initializer ← NIL, evals: EvalProcs, blackBox, stateToo: CellTestProc ← NIL, ports: Ports, drivePrototype: REF ANYNIL, classData: REF ANYNIL] RETURNS [class: CellClass] =
BEGIN
old: CellClass;
class ← NEW [CellClassRep ← [
name: className,
expand: expandProc,
ioCreator: ioCreator,
initializer: initializer,
evals: evals,
blackBox: blackBox,
stateToo: stateToo,
ports: ports,
ioWordCount: 0,
firstInstance: NIL,
drivePrototype: drivePrototype,
classData: classData]];
old ← NARROW[cellClasses.Delete[className]];
FOR portIndex: CARDINAL IN [0 .. ports.length) DO
port: Port ← class.ports[portIndex];
class.ioWordCount ← MAX[class.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 port.special THEN class.hasASpecialPort ← TRUE;
ENDLOOP;
IF old # NIL THEN
BEGIN
FOR instance: Cell ← old.firstInstance, instance.nextInstance WHILE instance # NIL DO
IF instance.class # old THEN ERROR;
instance.class ← class;
IF instance.expansion = Leaf THEN
BEGIN
IF instance.realCellStuff.evals # old.evals THEN ERROR;
instance.realCellStuff.evals ← class.evals;
END;
ENDLOOP;
IF old.firstInstance # NIL THEN
BEGIN
ok: BOOLEANTRUE;
IF old.ports.length # class.ports.length THEN ok ← FALSE
ELSE BEGIN
FOR portIndex: CARDINAL IN [0 .. class.ports.length) DO
IF (
class.ports[portIndex].firstWord # old.ports[portIndex].firstWord OR
class.ports[portIndex].wordCount # old.ports[portIndex].wordCount OR
class.ports[portIndex].type # old.ports[portIndex].type OR
class.ports[portIndex].input # old.ports[portIndex].input OR
class.ports[portIndex].output # old.ports[portIndex].output OR
NOT class.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;
END;
cellClasses.Insert[class];
END;
GetCellClass: PUBLIC PROC [className: ROPE] RETURNS [class: CellClass] =
{class ← NARROW[cellClasses.Lookup[className]]};
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, className: ROPE, decider: ExpandDeciderClosure, initData: REF ANYNIL, steady: BOOLTRUE] RETURNS [cell: Cell, osim: Simulation] =
BEGIN
class: CellClass;
class ← NARROW[cellClasses.Lookup[className]];
IF class = NIL THEN ERROR Error[IO.PutFR["No such class: %g", IO.rope[className]]];
osim ← CreateSim[steady];
osim.root ← cell ← NEW [CellRep ← [
name: instanceName, class: class, sim: osim,
parent: NIL, leftChild: NIL, rightSibling: NIL, firstInternalNode: NIL,
internalNodes: OSTR.CreateTable[CompareNodes],
components: OSTR.CreateTable[CompareComponents],
interfaceNodes: NEW [NodeSR[0]],
props: NIL,
type: Shadow, expansion: Inline,
realCellStuff: NIL]];
cell.props ← List.PutAssoc[$ExpandDeciderClosure, decider, cell.props];
FinishCreatingCell[cell, NIL, initData];
roots.Insert[cell !OSTR.DuplicateKey => ERROR Error[IO.PutFR["Duplicated Root name: %g", IO.rope[cell.name]]]];
END;
CreateCell: PUBLIC PROC [within: Cell, instanceName, className, interfaceNodes: ROPE, initData: REF ANYNIL] 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, sim: within.sim,
parent: within, leftChild: NIL, rightSibling: NIL, firstInternalNode: NIL,
internalNodes: OSTR.CreateTable[CompareNodes],
components: OSTR.CreateTable[CompareComponents],
interfaceNodes: NEW [NodeSR[class.ports.length]],
props: NIL,
type: Shadow, expansion: Inline,
realCellStuff: NIL]];
FinishCreatingCell[cell, interfaceNodes, initData];
IF cell.type = Real THEN RoseRun.ScheduleCell[cell];
END;
FinishCreatingCell: PROC [cell: Cell, interfaceNodes: ROPE, initData: REF ANYNIL] =
BEGIN
class: CellClass ← cell.class;
thisChild, lastChild: Cell;
thisNode, lastNode: Node;
IF (cell.parent = NIL) AND (class.ports.length > 0) THEN ERROR Error["Bogosity", 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 ← 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: notInCellList,
nextNeeded: notInCellList, nextNoted: notInCellList,
newIO: NIL, oldIO: NIL, switchIO: NIL,
newIOAsWP: NIL, oldIOAsWP: NIL, switchIOAsWP: NIL,
state: NIL,
evals: class.evals]];
FOR portIndex: CARDINAL IN [0..class.ports.length) DO
node: Node ← cell.interfaceNodes[portIndex];
targType: NodeType ← cell.class.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.class.ports[portIndex].XPhobic THEN node.XPhobic ← TRUE;
NoteConnection[node, [cell, portIndex], cell.class.ports[portIndex].input, cell.class.ports[portIndex].output];
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];
cell.realCellStuff.switchIOAsWP ← LOOPHOLE[cell.realCellStuff.switchIO];
FOR portIndex: CARDINAL IN [0 .. class.ports.length) DO
targType: NodeType ← cell.class.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 class.initializer # NIL THEN class.initializer[cell: cell, initData: initData, 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[class.ports.length]],
nextPerturbed: notInStrList,
nextWasPerturbed: notInStrList ]];
IF cell.parent # NIL THEN insides.mirror ← NEW [CellRep ← [
name: cell.name.Cat["-mirror"],
class: GetMirrorClass[cell.class],
sim: cell.sim,
parent: cell,
leftChild: NIL,
rightSibling: NIL,
firstInternalNode: NIL,
internalNodes: NIL,
components: NIL,
interfaceNodes: insides.insideNodes,
props: NIL,
type: 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 .. class.ports.length) DO
outsideNode: Node ← cell.interfaceNodes[index];
insideNode: Node ← CreateNode[within: cell, name: class.ports[index].name, type: outsideNode.type, initialValue: outsideNode.initialValue];
insides.insideNodes[index] ← insideNode;
IF cell.parent # NIL THEN {
NoteMaybeVisible[insideNode, [insides.mirror, index]];
NoteConnection[insideNode, [insides.mirror, index], cell.class.ports[index].output, cell.class.ports[index].input];
};
IF NOT class.ports[index].output THEN insideNode.unwriteability ← insideNode.unwriteability + 1;
ENDLOOP;
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;
NoteConnection: PROC [node: Node, socket: Socket, input, output: BOOLEAN] =
BEGIN
IF input THEN
BEGIN
IF output THEN node.bidirs ← CONS[socket, node.bidirs]
ELSE node.readers ← CONS[socket, node.readers];
END
ELSE IF output THEN node.writers ← CONS[socket, node.writers]
ELSE ERROR;
END;
FillInInterfaceNodes: PROC [cell: Cell, interfaceNodes: ROPE] =
BEGIN
index: CARDINAL ← 0;
in: IO.STREAMIO.RIS[interfaceNodes];
[] ← in.GetIndex[]; --wake up generic GetIndex impl
[] ← in.SkipWhitespace[];
IF NOT in.EndOf[] THEN DO
name: ROPE ← in.GetTokenRope[IDBreak].token;
key: ROPE;
this: CARDINAL;
[] ← in.SkipWhitespace[];
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.GetTokenRope[IDBreak].token;
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] ← LookupCellNode[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.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.class.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]]]
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;
IDBreak: IO.BreakProc =
{RETURN [SELECT char FROM
IO.SP, IO.CR, IO.LF, IO.TAB => sepr,
',, ': => break,
ENDCASE => other]};
LookupCellNode: 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;
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 class %g", IO.rope[cell.class.name]]];
FOR temp: Cell ← cell, temp.parent WHILE temp # NIL DO
asAny: REF ANY ← List.Assoc[$ExpandDeciderClosure, temp.props];
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];
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: PUBLIC 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]];
mirrorClass ← RegisterCellClass[
className: name,
evals: RoseRun.StrMirrorEvals,
ports: MirrorPorts[class.ports]];
END;
MirrorPorts: PUBLIC PROC [fwd: Ports, alwaysOutput, alwaysInput: BOOLFALSE] RETURNS [bkwd: Ports] =
BEGIN
bkwd ← NEW [PortsRep[fwd.length]];
FOR i: CARDINAL IN [0 .. fwd.length) DO
bkwd[i] ← fwd[i];
bkwd[i].input ← alwaysInput OR fwd[i].output;
bkwd[i].output ← alwaysOutput OR fwd[i].input;
ENDLOOP;
END;
Possible: PUBLIC PROC [cell: Cell, whatToDo: ExpandDecision] RETURNS [possible: BOOLEAN] =
BEGIN
evalable: BOOLEAN ← cell.class.evals.EvalSimple # NIL OR cell.class.evals.PropUD # NIL;
RETURN [SELECT whatToDo FROM
Leaf => evalable 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;
CreateNode: PUBLIC PROC [within: Cell, name: ROPE, type: NodeType, initialValue: ROPENIL, initData: REF ANYNIL] RETURNS [node: Node] =
BEGIN
bits: CARDINAL ← type.procs.Bits[type];
words: CARDINAL ← (bits + 15)/16;
node ← NEW [NodeRep ← [
name: name,
type: type,
cellIn: within,
initialValue: initialValue,
nextPerturbed: notInNodeList,
nextAffected: notInNodeList,
nextX: notInNodeList,
prevX: notInNodeList,
next: within.firstInternalNode
]];
node.name ← name;
node.type ← type;
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 node.type.simple THEN Initialize[node, NIL];
IF NOT node.type.simple THEN RoseRun.PerturbNode[node, within];
END;
Initialize: PROC [node: Node, wp: WordPtr] =
BEGIN
ivs: IO.STREAMIO.RIS[node.initialValue];
fmt: Format ← node.type.procs.GetFormat[node.type, NIL];
ok: BOOLEAN ← fmt.ParseValue[
node,
fmt,
wp,
ivs];
ivs.Close[];
IF NOT ok THEN {
SIGNAL Warning[IO.PutFR[
"Unable to parse %g by default 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: PUBLIC PROC [within: Cell, a, b: StretchList, writeA, writeB: BOOLEAN] =
BEGIN
IF (a = NIL) # (b = NIL) THEN ERROR;
IF a = NIL THEN RETURN;
[] ← a.first.node.type.procs.MakeSplitJoin[within, a, b, writeA, writeB];
END;
ChangeReps: PUBLIC PROC [within: Cell, a, b: Node, writeA, writeB: BOOLEAN] =
BEGIN
IF a.type.procs.MakeTransducer # NIL THEN [] ← a.type.procs.MakeTransducer[a, b, within, writeA, writeB] ELSE
IF b.type.procs.MakeTransducer # NIL THEN [] ← b.type.procs.MakeTransducer[b, a, within, writeA, writeB] ELSE
ERROR;
END;
DecideFromFile: PUBLIC PROC [fileName: ROPE] RETURNS [dff: ExpandDeciderClosure] =
BEGIN
file: IO.STREAMNIL;
top: LORA;
file ← FS.StreamOpen[fileName: fileName];
top ← LIST[NIL, NIL, IO.GetRefAny[file]];
file.Close[];
dff ← NEW [ExpandDeciderClosureRep ← [Decide: DecideByName, otherData: top]];
END;
Name: TYPE = LIST OF ROPE;
LORA: TYPE = LIST OF REF ANY;
ExpandDecisionRef: TYPE = REF ExpandDecision;
decisionProp: ATOM ← Atom.MakeAtom["Spreitzer January 6, 1984 8:33 pm"];
ExpandQuery: TYPE = REF ExpandQueryRep;
ExpandQueryRep: TYPE = RECORD [
instanceName, className: ROPENIL,
whatToDo: ExpandDecision ← Nested];
qp: Pausers.Pauser ← NIL;
eq: ExpandQuery ← NEW [ExpandQueryRep ← []];
Ask: ExpandDecider --PROC [cell: Cell, otherData: REF ANY] RETURNS [ExpandDecision]-- =
BEGIN
first: BOOLEANTRUE;
eq.instanceName ← cell.name;
eq.className ← cell.class.name;
IF qv # NIL AND qv.iconic THEN ViewerOps.OpenIcon[qv];
WHILE first OR NOT Possible[cell, eq.whatToDo] DO qp.Pause[]; first ← FALSE ENDLOOP;
RETURN [eq.whatToDo];
END;
DecideByName: ExpandDecider =
BEGIN
Yelp: PROC [problem: ROPE] RETURNS [ExpandDecision] = TRUSTED
BEGIN
RETURN [Ask[cell, problem]];
END;
decisionsByName: LORANARROW[otherData];
name: Name ← GetName[cell];
descr: LORA ← GetDescr[name, decisionsByName];
decAt: ATOM;
asAny: REF ANY;
IF descr = NIL THEN RETURN [Yelp["no decision given"]];
IF descr.rest = NIL THEN
BEGIN
IF Possible[cell, Leaf] THEN RETURN [Leaf];
RETURN [Yelp["cant make it a Leaf"]];
END;
IF NOT ISTYPE[descr.rest.first, ATOM] THEN RETURN [Yelp["decision not an Atom"]];
IF (asAny ← Atom.GetProp[atom: (decAt ← NARROW[descr.rest.first]), prop: decisionProp]) = NIL THEN RETURN [Yelp["atom not a decision"]];
IF (IF asAny = NIL THEN TRUE ELSE NOT ISTYPE[asAny, ExpandDecisionRef]) THEN RETURN [Yelp["atom not a decision"]];
RETURN [NARROW[asAny, ExpandDecisionRef]^];
END;
GetName: PROC [cell: Cell] RETURNS [name: Name] =
BEGIN
name ← NIL;
WHILE cell # NIL DO
name ← CONS[cell.name, name];
cell ← cell.parent;
ENDLOOP;
END;
GetDescr: PROC [name: Name, dbn: LORA] RETURNS [LORA] =
BEGIN
Matches: PROC [name: ROPE, asAny: REF ANY] RETURNS [BOOLEAN] =
BEGIN
dbn: LORA;
s2: ROPE;
IF NOT ISTYPE[asAny, LORA] THEN TRUSTED
BEGIN
MessageWindow.Append[message: "Ill formed decisions!", clearFirst: TRUE];
RETURN [FALSE];
END;
dbn ← NARROW[asAny];
IF (IF dbn = NIL THEN TRUE ELSE (IF dbn.first = NIL THEN TRUE ELSE (NOT ISTYPE[dbn.first, ROPE] AND NOT ISTYPE[dbn.first, ATOM]))) THEN TRUSTED
BEGIN
MessageWindow.Append[message: "Ill formed decisions!", clearFirst: TRUE];
RETURN [FALSE];
END;
s2 ← WITH dbn.first SELECT FROM
r: ROPE => r,
a: ATOM => Atom.GetPName[a],
ENDCASE => ERROR;
RETURN [Rope.Equal[s1: name, s2: s2, case: FALSE]];
END;
WHILE name # NIL DO
tail: LORA;
IF (IF dbn = NIL THEN TRUE ELSE dbn.rest = NIL) THEN TRUSTED
BEGIN
MessageWindow.Append[message: "Ill formed decisions!", clearFirst: TRUE];
RETURN [NIL];
END;
FOR tail ← dbn.rest.rest, tail.rest WHILE tail # NIL DO
IF Matches[name.first, tail.first] THEN EXIT;
ENDLOOP;
IF tail = NIL THEN TRUSTED
BEGIN
MessageWindow.Append[message: "No decsion", clearFirst: TRUE];
RETURN [NIL];
END;
name ← name.rest;
dbn ← NARROW[tail.first];
ENDLOOP;
RETURN [dbn];
END;
LookupCell: PUBLIC PROC [path: LIST OF ROPE, from: Cell ← NIL] RETURNS [cell: Cell] =
BEGIN
sofar: LIST OF ROPENIL;
cell ← from;
WHILE path # NIL DO
next: Cell ← NARROW[(IF cell = NIL THEN roots ELSE cell.components). Lookup[path.first]];
IF next = NIL THEN
{SIGNAL Warning[IO.PutFR["Not found: %g %g %g", IO.refAny[sofar], IO.rope[Convert.RopeFromRope[path.first]], IO.refAny[path.rest]]]; RETURN [NIL]};
sofar ← CONS[path.first, sofar];
path ← path.rest;
cell ← next;
ENDLOOP;
END;
LookupNode: PUBLIC PROC [path: LIST OF ROPE, from: Cell ← NIL] RETURNS [node: Node] =
BEGIN
sofar: LIST OF ROPENIL;
cell: Cell ← from;
WHILE path.rest # NIL DO
next: Cell ← NARROW[(IF cell = NIL THEN roots ELSE cell.components). Lookup[path.first]];
IF next = NIL THEN
{SIGNAL Warning[IO.PutFR["Not found: %g %g %g", IO.refAny[sofar], IO.rope[Convert.RopeFromRope[path.first]], IO.refAny[path.rest]]]; RETURN [NIL]};
sofar ← CONS[path.first, sofar];
path ← path.rest;
cell ← next;
ENDLOOP;
node ← LookupCellNode[cell, path.first];
END;
qerv: ViewRec.RecordViewer;
qv: ViewRec.Viewer ← NIL;
MakeQueryPauser: ViewRec.OtherStuffProc =
BEGIN
v: ViewRec.Viewer;
[qp, v] ← Pausers.CreatePauser[enabledName: "Answer Query", disabledName: "", viewerInit: [parent: in, border: FALSE], paint: FALSE];
RETURN [LIST[v]];
END;
Setup: PROC =
BEGIN
Atom.PutProp[atom: $N, prop: decisionProp, val: NEW [ExpandDecision ← Nested]];
Atom.PutProp[atom: $I, prop: decisionProp, val: NEW [ExpandDecision ← Inline]];
Atom.PutProp[atom: $L, prop: decisionProp, val: NEW [ExpandDecision ← Leaf]];
qerv ← ViewRec.ViewRef[
agg: eq,
otherStuff: MakeQueryPauser,
viewerInit: [iconic: TRUE, column: right, name: "ExpandQuery"]];
qv ← qerv.RVQuaViewer[];
END;
Setup[];
END.