<> <> DIRECTORY IO, Rope, Rosemary, RoseConditions, Trees; RoseConditionsImpl: CEDAR PROGRAM IMPORTS IO, Rope, Rosemary, Trees EXPORTS RoseConditions = BEGIN OPEN RoseConditions; ROPE: TYPE = Rope.ROPE; Cell: TYPE = Rosemary.Cell; IncrementalCondition: TYPE = REF IncrementalConditionRep; IncrementalConditionRep: PUBLIC TYPE = RECORD [ eval: IncrementalEvalProc _ NIL, data: REF ANY _ NIL, parent: IncrementalCondition _ NIL, sibling: IncrementalCondition _ NIL, value, sensitiveTo: BOOLEAN _ FALSE]; IncrementalEvalProc: TYPE = PROC [ic: IncrementalCondition]; test: PUBLIC Trees.NodeType; UnPostIncrementally: PUBLIC PROC [ic: IncrementalCondition] = BEGIN SELECT ic.eval FROM IETop => UnPostIncrementally[NARROW[ic.data, TopData].child]; IEAnd, IEOr, IENot => FOR child: IncrementalCondition _ NARROW[ic.data], child.sibling WHILE child # NIL DO UnPostIncrementally[child]; ENDLOOP; IETest => BEGIN nt: NodeTest _ NARROW[ic.data]; Rosemary.RemoveNodeWatcher[nt.node, [NotifyIncremental, ic]]; END; ENDCASE => ERROR; END; PostIncrementally: PUBLIC PROC [cond: Condition] RETURNS [ic: IncrementalCondition] = BEGIN ic _ NEW [IncrementalConditionRep _ [eval: IETop, sensitiveTo: TRUE]]; ic.data _ NEW [TopDataRep _ [ cond: cond, child: PostIE[parent: ic, cond: cond] ]]; END; TopData: TYPE = REF TopDataRep; TopDataRep: TYPE = RECORD [ cond: Condition, child: IncrementalCondition]; IETop: IncrementalEvalProc = BEGIN td: TopData _ NARROW[ic.data]; IF td.child.value THEN SIGNAL Rosemary.Stop["Incremental Breakpoint hit", td.cond]; END; PostIE: PROC [parent: IncrementalCondition, cond: Condition] RETURNS [ic: IncrementalCondition] = BEGIN recurse: BOOLEAN _ TRUE; last: IncrementalCondition _ NIL; ic _ NEW [IncrementalConditionRep _ [parent: parent]]; SELECT cond.info FROM test => BEGIN nt: NodeTest _ NARROW[cond.leftChild]; ic.eval _ IETest; ic.data _ cond.leftChild; recurse _ FALSE; Rosemary.AddNodeWatcher[nt.node, [NotifyIncremental, ic]]; END; Trees.and => ic.eval _ IEAnd; Trees.or => ic.eval _ IEOr; Trees.not => ic.eval _ IENot; ENDCASE => ERROR; IF recurse THEN BEGIN FOR c: Condition _ NARROW[cond.leftChild], c.rightSibling WHILE c # NIL DO next: IncrementalCondition _ PostIE[parent: ic, cond: c]; next.sibling _ last; last _ next; ENDLOOP; ic.data _ last; END; ic.eval[ic]; END; NotifyIncremental: Rosemary.NodeNotifyProc = BEGIN IncrementalEval[NARROW[clientData]]; END; IncrementalEval: PROC [ic: IncrementalCondition] = BEGIN old: BOOLEAN _ ic.value; ic.eval[ic]; IF ic.value # old AND ic.value = ic.parent.sensitiveTo AND ic.parent # NIL THEN IncrementalEval[ic.parent]; END; IETest: IncrementalEvalProc = BEGIN nt: NodeTest _ NARROW[ic.data]; ic.sensitiveTo _ NOT (ic.value _ nt.testProc[testData: nt.testData, typeData: nt.node.type.typeData, where: nt.node.visible.SocketToWP[]]); END; IEAnd: IncrementalEvalProc = BEGIN FOR child: IncrementalCondition _ NARROW[ic.data], child.sibling WHILE child # NIL DO IF NOT child.value THEN BEGIN ic.sensitiveTo _ NOT (ic.value _ FALSE); EXIT; END; ENDLOOP; ic.sensitiveTo _ NOT (ic.value _ TRUE); END; IEOr: IncrementalEvalProc = BEGIN FOR child: IncrementalCondition _ NARROW[ic.data], child.sibling WHILE child # NIL DO IF child.value THEN BEGIN ic.sensitiveTo _ NOT (ic.value _ TRUE); EXIT; END; ENDLOOP; ic.sensitiveTo _ NOT (ic.value _ FALSE); END; IENot: IncrementalEvalProc = BEGIN ic.value _ ic.sensitiveTo _ NOT NARROW[ic.data, IncrementalCondition].value; END; PostOnCell: PUBLIC PROC [cell: Cell, condition: Condition] = BEGIN Rosemary.AddCellEventWatcher[cell, $EndOfClockCycle, [CheckCondition, condition]]; END; UnPostOnCell: PUBLIC PROC [cell: Cell, condition: Condition] = BEGIN Rosemary.RemoveCellEventWatcher[cell, $EndOfClockCycle, [CheckCondition, condition]]; END; CheckCondition: Rosemary.CellNotifyProc = BEGIN cond: Condition _ NARROW[clientData]; ans: BOOLEAN _ EvalCondition[cond]; IF ans THEN SIGNAL Rosemary.Stop["Strobed Breakpoint hit", cond]; END; EvalCondition: PROC [cond: Condition] RETURNS [ans: BOOLEAN] = BEGIN SELECT cond.info FROM test => BEGIN nt: NodeTest _ NARROW[cond.leftChild]; ans _ nt.testProc[testData: nt.testData, typeData: nt.node.type.typeData, where: nt.node.visible.SocketToWP[]]; END; Trees.and => BEGIN FOR c: Condition _ NARROW[cond.leftChild], c.rightSibling WHILE c # NIL DO IF NOT EvalCondition[c] THEN RETURN [FALSE]; ENDLOOP; RETURN [TRUE]; END; Trees.or => BEGIN FOR c: Condition _ NARROW[cond.leftChild], c.rightSibling WHILE c # NIL DO IF EvalCondition[c] THEN RETURN [TRUE]; ENDLOOP; RETURN [FALSE]; END; Trees.not => ans _ NOT EvalCondition[NARROW[cond.leftChild]]; ENDCASE => ERROR; END; LongNodeName: PROC [nodeName: ROPE, cell: Cell] RETURNS [l: ROPE] = BEGIN l _ NIL; WHILE cell.parent # NIL DO l _ IF l = NIL THEN cell.name ELSE cell.name.Cat[".", l]; cell _ cell.parent; ENDLOOP; l _ IF l = NIL THEN nodeName ELSE l.Cat[".", nodeName]; END; WriteTest: Trees.WriteProc = CHECKED BEGIN nt: NodeTest _ NARROW[leftChild]; to.PutRope[nt.node.type.unParseTest[testProc: nt.testProc, testData: nt.testData, typeData: nt.node.type.typeData, subject: LongNodeName[nt.nodeName, nt.cell]]]; END; Setup: PROC = BEGIN OPEN Trees.stuff; test _ Trees.NewNodeType[LIST[ DA[$arity, $Leafary], DP[$write, WriteTest] ]]; END; Setup[]; END.