DIRECTORY TiogaPathOps, CreateNode USING [CreateInternalRep], NodeProps, TiogaLooks, TiogaNode, TiogaItemClass, TiogaBasicClass, TiogaNodeOps, Rope, RopeEdit; TiogaPathOpsImpl: CEDAR PROGRAM IMPORTS CreateNode, RopeEdit, NodeProps, TiogaNodeOps EXPORTS TiogaPathOps SHARES TiogaNode = BEGIN OPEN TiogaPathOps; ROPE: TYPE = Rope.ROPE; RefBranchNode: TYPE = TiogaNode.RefBranchNode; RefTextNode: TYPE = TiogaNode.RefTextNode; RefBoxNode: TYPE = TiogaNode.RefBoxNode; RefListNode: TYPE = TiogaNode.RefListNode; Span: TYPE = TiogaNode.Span; Parent: PUBLIC PROC [p: Path] RETURNS [Path] = { node: Ref; DO IF (node _ p.node)=NIL OR node.deleted THEN RETURN [nullPath]; UNTIL node.last DO node _ node.next; ENDLOOP; IF node.next # NIL THEN RETURN [[node.next, p.path]]; IF p.path=NIL THEN RETURN [nullPath]; p _ p.path^; -- go back to the formal or the application and find parent of that ENDLOOP }; GetTemplate: PROC [name, styleName: TiogaNode.Name] RETURNS [Ref] = { RETURN [NIL] }; GetActualArg: PROC [formal: Path] RETURNS [Ref] = { RETURN [NIL] }; GetStyleName: PROC [p: Path] RETURNS [styleName: TiogaNode.Name] = { RETURN [TiogaNode.nullName] }; ConstructRefPath: PROC [p: Path] RETURNS [ref: REF Path] = { IF p.path # NIL THEN RETURN [NEW[Path _ p]]; IF (ref _ NARROW[NodeProps.GetProp[p.node, $RefPath]])=NIL THEN -- create one NodeProps.PutProp[p.node, $RefPath, ref _ NEW[Path _ p]]; RETURN [ref] }; GetTemplatePath: PROC [application: Path] RETURNS [template: Path] = { RETURN [nullPath] }; GetArgPath: PROC [formal: Path] RETURNS [actual: Path] = { RETURN [nullPath] }; Sib: PROC [p: Path] RETURNS [Path] = { node: Ref; DO IF (node _ p.node)=NIL THEN RETURN [nullPath]; IF ~node.last THEN { p _ [node.next, p.path]; RETURN [SELECT node.templateInfo FROM normal => p, application => GetTemplatePath[p], formal => GetArgPath[p], ENDCASE => ERROR] }; IF node.next # NIL OR p.path = NIL THEN RETURN [nullPath]; p _ p.path^; -- go back to the formal or the application and find Sib of that ENDLOOP }; Contents: PUBLIC PROC [p: Path] RETURNS [Path] = BEGIN node: Ref; IF p.node=NIL THEN RETURN [nullPath]; WITH p.node SELECT FROM br: RefBranchNode => { CheckInternalRep[br]; node _ br.contents }; bx: RefBoxNode => node _ bx.contents; ls: RefListNode => node _ ls.contents; ENDCASE => RETURN [nullPath]; IF node=NIL THEN RETURN [nullPath]; p _ [node, p.path]; RETURN [SELECT node.templateInfo FROM normal => p, application => GetTemplatePath[p], formal => GetArgPath[p], ENDCASE => ERROR]; END; BranchChild: PUBLIC PROC [p: Path] RETURNS [Path] = BEGIN n: RefBranchNode = TiogaNodeOps.NarrowToBranchNode[p.node]; node: RefBranchNode; IF n=NIL THEN RETURN [nullPath]; CheckInternalRep[n]; IF (node _ n.child)=NIL THEN RETURN [nullPath]; CheckInternalRep[node]; p _ [node, p.path]; RETURN [SELECT node.templateInfo FROM normal => p, application => GetTemplatePath[p], formal => GetArgPath[p], ENDCASE => ERROR]; END; Root: PUBLIC PROC [p: Path] RETURNS [Path] = { parent: Path; DO IF (parent_Parent[p]).node=NIL THEN RETURN [p]; p _ parent; ENDLOOP }; Next: PUBLIC PROC [p: Path] RETURNS [nxt: Path] = { nxt _ Sib[p]; WITH nxt.node SELECT FROM br: RefBranchNode => CheckInternalRep[br]; ENDCASE }; FirstSibling: PUBLIC PROC [p: Path, parent: Path _ nullPath] RETURNS [sib: Path] = { IF p.node=NIL THEN RETURN [nullPath]; IF parent.node=NIL THEN parent _ Parent[p]; IF parent.node=NIL THEN RETURN [nullPath]; RETURN [ IF TiogaNodeOps.IsBranch[p.node] AND TiogaNodeOps.IsBranch[parent.node] THEN BranchChild[parent] ELSE Contents[parent]] }; LastSibling: PUBLIC PROC [p: Path] RETURNS [sib: Path] = { IF p.node=NIL THEN RETURN [nullPath]; UNTIL (sib _ Sib[p]).node = NIL DO p _ sib; ENDLOOP; WITH sib.node SELECT FROM br: RefBranchNode => CheckInternalRep[br]; ENDCASE }; Previous: PUBLIC PROC [p: Path, parent: Path _ nullPath] RETURNS [sib: Path] = { IF p.node=NIL THEN RETURN [nullPath]; IF (sib _ FirstSibling[p, parent])=p OR sib.node=NIL THEN RETURN [nullPath]; UNTIL InlineEqual[sib _ Sib[p], p] DO p _ sib; ENDLOOP; WITH sib.node SELECT FROM br: RefBranchNode => CheckInternalRep[br]; ENDCASE }; LastWithin: PUBLIC PROC [p: Path] RETURNS [Path] = { nxt: Path; DO IF p.node=NIL THEN RETURN [nullPath]; IF ~TiogaNodeOps.IsBranch[p.node] OR (nxt _ BranchChild[p]).node=NIL THEN nxt _ Contents[p]; IF nxt.node=NIL THEN RETURN [p]; p _ LastSibling[nxt]; ENDLOOP }; Forward: PUBLIC PROC [p: Path] RETURNS [nx: Path, levelDelta: INTEGER] = { fakeLevel: INTEGER = 100; nxLevel: INTEGER; [nx, nxLevel] _ ForwardClipped[p, LAST[INTEGER], fakeLevel]; RETURN [nx, nxLevel-fakeLevel] }; ForwardClipped: PUBLIC PROC [p: Path, maxLevel: INTEGER, nodeLevel: INTEGER _ 0] RETURNS [nx: Path, nxLevel: INTEGER] = { IF nodeLevel <= 0 THEN nodeLevel _ Level[p]; IF nodeLevel < maxLevel AND (nx _ BranchChild[p]).node # NIL THEN RETURN [nx, nodeLevel+1]; -- return the child IF ~TiogaNodeOps.IsBranch[p.node] THEN RETURN [nullPath, 0]; DO -- move to next node, sibling or up* then sibling IF (nx _ Next[p]).node # NIL THEN RETURN; IF (p _ Parent[p]).node = NIL THEN RETURN [nullPath, 0]; -- move to the parent nodeLevel _ nodeLevel-1; ENDLOOP }; StepForwardNode: PUBLIC PROC [p: Path] RETURNS [nx: Path] = { IF p.node=NIL THEN RETURN [nullPath]; nx _ Contents[p]; IF nx.node=NIL AND TiogaNodeOps.IsBranch[p.node] THEN nx _ BranchChild[p]; IF nx.node # NIL THEN RETURN; -- descend in the tree DO IF (nx _ Next[p]).node # NIL THEN RETURN; IF (nx _ Parent[p]).node = NIL THEN RETURN [nullPath]; IF ~TiogaNodeOps.IsBranch[p.node] AND TiogaNodeOps.IsBranch[nx.node] AND (p _ BranchChild[nx]).node # NIL THEN RETURN [p]; -- have visited contents of this branch; now visit children p _ nx; -- move to the parent ENDLOOP }; Backward: PUBLIC PROC [p: Path, parent: Path _ nullPath] RETURNS [back: Path, backparent: Path, levelDelta: INTEGER] = { backLevel: INTEGER; fakeLevel: INTEGER = 100; [back, backparent, backLevel] _ BackwardClipped[p, LAST[INTEGER], parent, fakeLevel]; RETURN [back, backparent, backLevel-fakeLevel] }; BackwardClipped: PUBLIC PROC [ p: Path, maxLevel: INTEGER, parent: Path _ nullPath, nodeLevel: INTEGER _ 0] RETURNS [back: Path, backparent: Path, backLevel: INTEGER] = { child, child2: Path; IF parent.node=NIL THEN parent _ Parent[p]; IF parent.node=NIL OR ~TiogaNodeOps.IsBranch[p.node] THEN RETURN [nullPath, nullPath, 0]; IF nodeLevel <= 0 THEN nodeLevel _ Level[p]; IF (child _ Previous[p, parent]).node=NIL THEN -- p is first following parent IF ~TiogaNodeOps.IsBranch[parent.node] THEN RETURN [nullPath, nullPath, 0] ELSE RETURN [parent, Parent[parent], nodeLevel-1]; DO -- go deeper in tree until reach maxLevel IF nodeLevel >= maxLevel OR (child2 _ BranchChild[child]).node = NIL THEN RETURN [child, parent, nodeLevel]; nodeLevel _ nodeLevel+1; parent _ child; child _ LastSibling[child2]; ENDLOOP }; StepBackwardNode: PUBLIC PROC [p: Path, parent: Path _ nullPath] RETURNS [back, backparent: Path] = { child, child2: Path; IF parent.node=NIL THEN parent _ Parent[p]; IF parent.node=NIL OR p.node=NIL THEN RETURN [nullPath, nullPath]; IF (child _ Previous[p, parent]).node=NIL THEN RETURN [parent, Parent[parent]]; DO -- find last node within predecessor IF ~TiogaNodeOps.IsBranch[child.node] OR (child2 _ BranchChild[child]).node=NIL THEN child2 _ Contents[child]; IF child2.node=NIL THEN RETURN [child, parent]; parent _ child; child _ LastSibling[child2]; ENDLOOP }; Equal: PUBLIC PROC [p1, p2: Path] RETURNS [yes: BOOL] = { RETURN [InlineEqual[p1, p2]] }; InlineEqual: PROC [p1, p2: Path] RETURNS [yes: BOOL] = INLINE BEGIN DO IF p1.node # p2.node THEN RETURN [FALSE]; IF p1.path = p2.path THEN RETURN [TRUE]; IF p1.path = NIL OR p2.path = NIL THEN RETURN [FALSE]; p1 _ p1.path^; p2 _ p2.path^; ENDLOOP; END; Level: PUBLIC PROC [p: Path] RETURNS [level: INTEGER] = { level _ 0; UNTIL (p _ Parent[p]).node=NIL DO level _ level+1; ENDLOOP }; BackLoc: PUBLIC PROC [loc: Location] RETURNS [new: Location] = { text: RefTextNode; new.path _ StepBackwardNode[loc.path].back; new.where _ IF loc.where=TiogaNode.NodeItself OR (text _ TiogaNodeOps.NarrowToTextNode[new.path.node])=NIL THEN TiogaNode.NodeItself ELSE RopeEdit.Size[text.rope] }; ForwardLoc: PUBLIC PROC [loc: Location] RETURNS [new: Location] = { new.path _ StepForwardNode[loc.path]; new.where _ IF loc.where=TiogaNode.NodeItself OR TiogaNodeOps.NarrowToTextNode[new.path.node]=NIL THEN TiogaNode.NodeItself ELSE 0 }; LastLocWithin: PUBLIC PROC [p: Path] RETURNS [Location] = { last: Path = LastWithin[p]; lastText: RefTextNode = TiogaNodeOps.NarrowToTextNode[last.node]; where: Offset = IF lastText # NIL THEN RopeEdit.Size[lastText.rope] ELSE TiogaNode.NodeItself; RETURN [[last,where]] }; BadArgs: PUBLIC ERROR = CODE; LocNumber: PUBLIC PROC [at: Location, break: NAT _ 1, skipCommentNodes: BOOL _ FALSE] RETURNS [count: Offset] = { RETURN [LocOffset[[Root[at.path],0],at,break,skipCommentNodes]] }; LocOffset: PUBLIC PROC [loc1, loc2: Location, break: NAT _ 1, skipCommentNodes: BOOL _ FALSE] RETURNS [count: Offset] = { path: Path _ loc2.path; p: Path _ loc1.path; txt: RefTextNode; count _ IF loc2.where # TiogaNode.NodeItself THEN loc2.where ELSE 0; count _ count - MAX[loc1.where,0]; DO -- add in counts for text nodes before location IF InlineEqual[p, path] THEN RETURN; IF p.node=NIL THEN ERROR BadArgs; txt _ TiogaNodeOps.NarrowToTextNode[p.node]; IF txt # NIL AND (~skipCommentNodes OR ~txt.comment) THEN count _ count+RopeEdit.Size[txt.rope]+break; p _ StepForwardNode[p]; ENDLOOP }; LocRelative: PUBLIC PROC [location: Location, count: Offset, break: NAT _ 1, skipCommentNodes: BOOL _ FALSE] RETURNS [Location] = { p: Path _ location.path; size, lastWhere, where: Offset; last: Path _ p; IF count=0 AND Parent[p].node=NIL THEN -- avoid returning root node RETURN [[BranchChild[p],0]]; -- return first child of root instead lastWhere _ where _ MAX[location.where,0]; -- where we are in the current node WHILE p.node # NIL DO txt: RefTextNode _ TiogaNodeOps.NarrowToTextNode[p.node]; IF txt # NIL AND (~skipCommentNodes OR ~txt.comment) THEN { lastWhere _ size _ RopeEdit.Size[txt.rope]; IF (count _ count-(size-where)) <= 0 THEN RETURN [[p,MAX[0,count+size]]]; count _ count-break; last _ p }; p _ StepForwardNode[p]; where _ 0; ENDLOOP; RETURN [[last,lastWhere]] }; CheckInternalRep: PROC [br: TiogaNode.RefBranchNode] = INLINE { IF ~br.internalRepCreated THEN CreateNode.CreateInternalRep[br] }; Apply: PUBLIC PROC [span: Span, proc: ApplyProc] = { path, last: Path; start, lastLen: Offset; IF (path _ span.start.path).node = NIL THEN RETURN; IF (last _ span.end.path).node = NIL THEN RETURN; IF (start _ span.start.where)=TiogaNode.NodeItself THEN start _ 0; IF span.end.where=TiogaNode.NodeItself THEN lastLen _ LAST[Offset] ELSE IF span.end.where=LAST[Offset] THEN lastLen _ LAST[Offset] ELSE { lastLen _ span.end.where+1; IF Equal[path, last] THEN lastLen _ lastLen-start }; DO lastOne: BOOL = Equal[path, last]; IF proc[path, start, IF lastOne THEN lastLen ELSE LAST[Offset]] THEN RETURN; IF lastOne OR (path _ StepForwardNode[path]).node=NIL THEN RETURN; start _ 0; ENDLOOP; }; END. TiogaPathOpsImpl.mesa; Written by Paxton, July 1983 Edited by Paxton, August 16, 1983 1:17 pm If p points to root of template or actual arg, Parent returns parent of corresponding application or formal arg. If path is of form [node, NIL], then save ref to it away on node's property list since can reuse it. Could consider doing this for case in which p.path # NIL if take care to avoid hanging onto ref's to nodes that have been deleted. name: TiogaNode.Name = NodeProps.GetTemplateName[node]; styleName: TiogaNode.Name = GetStyleName[p]; templateNode: Ref _ GetTemplate[name, styleName]; refApplicationPath: REF Path = ConstructRefPath[application]; save back pointer with template to application RETURN [[templateNode, refApplicationPath]] }; Must take care of case in which actual parameter is an application or a formal. Keep going until find a normal node. This is like Next but doesn't create internal rep for branches If p points to root of template or actual arg, Sib returns sibling of corresponding application or formal arg. Returns p if p is the first sibling Returns p if p is the last sibling Returns NIL if p=FirstSibling[p] returns next branch in standard tree walk order like Forward, but limits how deep will go in tree if pass nodeLevel=0, correct value will be computed nxLevel = Level[nx] <= MAX[maxLevel,Level[node]] returns next node in standard tree walk order; visits branch contents before branch children The previous node is not a branch, but its parent is. This implies that previous node was last of branch contents since child of branch must be a branch. returns preceeding node in standard tree walk order like Backward, but limits how deep will go in tree backLevel = Level[back] <= MAX[maxLevel,Level[node]] returns character offset of location2 relative to location1 Ê”˜Jšœ3™3Jšœ)™)J˜šÏk ˜ J˜ Jšœ œ˜%J˜ J˜ J˜ Jšœ˜Jšœ˜J˜ J˜Jšœ ˜ —J˜šœœ˜Jšœ.˜5Jšœ ˜Jšœ ˜—J˜Jšœœ˜J˜Jšœœœ˜Jšœœ˜.Jšœ œ˜*Jšœ œ˜(Jšœ œ˜*šœœ˜J˜—šÏnœœœ œ ˜1J™pJšœ ˜ š˜Jš œœœœœ ˜>Jšœ œœ˜-Jšœ œœœ˜5Jšœœœœ ˜%Jšœ ÏcC˜PJšœ˜ —J˜—šž œœ#œ ˜EJšœœ˜J˜—šž œœœ ˜3Jšœœ˜J˜—šž œœ œ ˜DJšœ˜J˜—šžœœ œœ ˜<šœœG™dJ™‚—Jš œ œœœœ ˜,š œœ'œœŸ ˜MJšœ*œ ˜9—Jšœ ˜J˜—šžœœœ˜FJ™7J™,Jšœ1™1Jšœ=™=J™.Jšœ.™.Jšœ˜J˜—šž œœœ˜:J™uJšœ˜J˜—šžœœ œ ˜&J™>J™nJ˜ š˜Jšœœœœ ˜.šœ œ˜Jšœ˜šœœ˜%Jšœ ˜ Jšœ"˜"Jšœ˜Jšœœ˜——Jš œ œœ œœœ ˜:Jšœ Ÿ@˜MJšœ˜ —J˜—š žœœœ œ ˜6J˜ Jšœœœœ ˜%šœœ˜JšœB˜BJšœ%˜%Jšœ&˜&Jšœœ ˜—Jšœœœœ ˜#Jšœ˜šœœ˜%Jšœ ˜ Jšœ"˜"Jšœ˜Jšœœ˜—Jšœ˜J˜—š ž œœœ œ ˜9J˜;J˜Jšœœœœ ˜ Jšœ˜Jšœœœœ ˜/Jšœ˜Jšœ˜šœœ˜%Jšœ ˜ Jšœ"˜"Jšœ˜Jšœœ˜—Jšœ˜J˜—šžœœœ œ ˜/Jšœ ˜ š˜Jšœœœœ˜/Jšœ ˜ Jšœ˜ —J˜—šžœœœ œ˜3J˜ šœ œ˜Jšœ*˜*Jšœ˜ —J˜—šž œœœ$œ˜TJ™#Jšœœœœ ˜%Jšœ œœ˜+Jšœ œœœ ˜*šœ˜Jšœœ$œ˜`Jšœ˜—J˜—šž œœœ œ˜:J™"Jšœœœœ ˜%Jšœœœ œ˜4šœ œ˜Jšœ*˜*Jšœ˜ —J˜—šžœœœ$œ˜PJšœœ™ Jšœœœœ ˜%Jš œ#œ œœœ ˜LJšœœ œ˜7šœ œ˜Jšœ*˜*Jšœ˜ —J˜—šž œœœ œ ˜4Jšœ ˜ š˜Jšœœœœ ˜%Jšœ œœœ˜\Jšœ œœœ˜ J˜Jšœ˜ J˜——š žœœœ œœ˜JJšœ/™/Jšœ œ˜Jšœ œ˜Jšœ"œœ˜<šœ˜!J˜——š žœœœœ œ˜PJšœœ˜(Jšœ1™1Jšœ4™4Jšœ0™0Jšœœ˜,šœœœ˜AJšœŸ˜-—Jšœ œœ˜<šœŸ1˜4Jšœœœœ˜)Jš œœœœŸ˜NJ˜Jšœ˜ J˜——šžœœœ œ˜=Jšœ\™\Jšœœœœ ˜%Jšœ˜Jšœ œœœ˜JJš œ œœœŸ˜4š˜Jšœœœœ˜)Jšœœœœ ˜6š œ œ œœ˜nJšœŸ;˜GJ™5J™c—JšœŸ˜Jšœ˜ J˜——šžœœœ#˜8Jšœ,œ˜?Jšœ3™3Jšœ œ˜Jšœ œ˜Jšœ3œœ˜Ušœ+˜1J˜——šžœœœ˜Jšœœ&œ˜LJšœ+œ˜>Jšœ2™2Jšœ4™4Jšœ˜Jšœ œœ˜+Jš œ œœ œœ˜YJšœœ˜,šœ$œœŸ˜MJšœ%œœ˜JJšœœ'˜2—šœŸ)˜,šœœ&œ˜IJšœ˜"—J˜Jšœœœ˜7J˜——šžœœœ#˜@Jšœ˜$Jšœ˜Jšœ œœ˜+Jš œ œœœœœ˜BJšœ$œœœ˜OšœŸ$˜'šœ$œ$œ˜TJšœ˜—Jšœ œœœ˜/Jšœ,œ˜7J˜——š žœœœœœœ˜YJ˜—š ž œœœœ ˜Cš˜Jšœœœœ˜)Jšœœœœ˜(Jšœ œœ œœœœ˜6J˜Jšœ˜—Jšœ˜J˜—š žœœœ œ œ˜9Jš œ œœœœ˜IJ˜—šžœœœœ˜@J˜J˜+šœ œ œ7˜jJšœœ˜:J˜——šž œœœœ˜CJ˜%šœ œ œ.˜aJšœœ˜#—J˜—šž œœœ œ˜;Jšœ˜JšœA˜AJš œœ œœœ˜^Jšœ˜J˜—šœ œœœ˜J˜—š ž œœœœœœ˜UJšœœ<˜^J™—šž œœœ˜-Jš œœœœœ˜KJšœ;™;Jšœ˜Jšœ˜J˜Jšœœ#œ œ˜DJšœœ˜"šœŸ/˜2Jšœœœ˜$Jšœœœœ ˜!Jšœ,˜,š œœœœ˜9J˜,—Jšœ˜Jšœ˜ J˜——šž œœœ$˜