-- TextNode.Mesa
-- written by Bill Paxton. December 1980
-- last written by Paxton. December 21, 1982 9:46 am
Last Edited by: Maxwell, January 5, 1983 12:37 pm
DIRECTORY
Rope,
NameSymbolTable,
TextLooks;
TextNode: CEDAR DEFINITIONS =
BEGIN
Offset: TYPE = LONG INTEGER ← 0;
MaxLen: Offset = LAST[Offset];
ROPE: TYPE = Rope.ROPE;
Ref: TYPE = REF Body;
Body: TYPE = RECORD [
next: Ref, -- points to next sibling, or if last=true, to parent
child: Ref, -- points to first child, if any, of this node
props: NodeProps, -- points to node property list
class: REF ANY, -- for Scott to play with
typename: TypeName ← nullTypeName, -- name of type for the node
last: BOOLEANFALSE, -- true if this is last sibling
hasstyledef: BOOLEANFALSE, -- true if node has StyleDef prop (simply an accelerator)
hasprefix: BOOLEANFALSE, -- true if node has Prefix prop (simply an accelerator)
haspostfix: BOOLEANFALSE, -- true if has Postfix prop (also an accelerator)
deleted: BOOLEANFALSE, -- true if has been deleted or is root pending delete
dirty: BOOLEANFALSE, -- true if has been edited (contents, or children moved, inserted, ...)
new: BOOLEANFALSE, -- true if created during this editing session (i.e., not from file)
body: SELECT kind:OfNode FROM
text => [
comment: BOOLEANFALSE, -- true if node is a comment
count: [0..countMax] ← 0, -- incremented by text edit routines
rope: ROPE,
runs: TextLooks.Runs ],
other => [ variety: ATOM, info: REF ANY ],
ENDCASE];
Location: TYPE = RECORD [node: Ref, where: Offset];
-- where >= length of text means at end
-- where = loc in [0..length) means before that character
-- e.g., where = 0 means at start of text
-- where = NodeItself means location is the node itself rather than in its contents
NodeItself: Offset = -1;
nullLocation: Location = [NIL,NodeItself];
MakeNodeLoc: PROC [n: Ref] RETURNS [Location] = INLINE { RETURN [[n,NodeItself]] };
Span: TYPE = RECORD [start, end: Location ← nullLocation];
-- start.node can equal end.node
-- in which case either both start.where and end.where = NodeItself, or
-- neither do and start.where <= end.where
-- otherwise, end.node should follow start.node in the tree
-- nodes need not be siblings
-- no restrictions on start.where or end.where
nullSpan: Span = [nullLocation,nullLocation];
MakeNodeSpan: PROC [first, last: Ref] RETURNS [Span] = INLINE {
RETURN [[MakeNodeLoc[first],MakeNodeLoc[last]]] };
countMax: NAT=63; -- 6 bits for count
OfNode: TYPE = {text,other};
TextBody: TYPE = text Body;
RefTextNode: TYPE = REF TextBody;
OtherBody: TYPE = other Body;
RefOtherNode: TYPE = REF OtherBody;
NodeList: TYPE = REF NodeListBody;
NodeListBody: TYPE = RECORD [node: Ref, next: NodeList];
NodeProps: TYPE = REF NodePropsBody;
NodePropsBody: TYPE; -- exported by NodePropsImpl
-- here are some access procedures for use with nodes
NewTextNode: PROC RETURNS [txt: RefTextNode];
NewOtherNode: PROC RETURNS [oth: RefOtherNode];
NarrowToTextNode: PROC [n: Ref] RETURNS [txt: RefTextNode] = TRUSTED INLINE {
-- returns n as a RefTextNode if possible, else returns NIL
IF n#NIL THEN WITH x:n SELECT FROM text => txt ← @x; ENDCASE };
NarrowToOtherNode: PROC [n: Ref] RETURNS [othr: RefOtherNode] = TRUSTED INLINE {
-- returns n as a RefOtherNode if possible, else returns NIL
IF n#NIL THEN WITH x:n SELECT FROM other => othr ← @x; ENDCASE };
Parent: PROC [n: Ref] RETURNS [Ref];
Root: PROC [n: Ref] RETURNS [Ref];
Next: PROC [n: Ref] RETURNS [Ref];
-- returns next sibling of n
-- returns NIL if n is last sibling
Previous: PROC [n: Ref, parent: Ref ← NIL] RETURNS [nx: Ref];
-- returns previous sibling of n
-- returns NIL if n is first sibling
-- runs faster if can supply parent
StepForward: PROC [node: Ref] RETURNS [nx: Ref] = INLINE { [nx,] ← Forward[node] };
-- returns next node in standard tree walk order
StepBackward: PROC [node: Ref, parent: Ref ← NIL] RETURNS [back: Ref] = INLINE {
-- returns preceeding node in standard tree walk order
[back,,] ← Backward[node,parent] };
Forward: PROC [node: Ref] RETURNS [nx: Ref, levelDelta: INTEGER];
-- returns next node in standard tree walk order
-- levelDelta is level(node)-level(nx), where level is depth in tree
-- levelDelta = 0 if nx and node are siblings
-- levelDelta = 1 if nx is child of node
-- levelDelta < 0 if do Parent* and Next to reach nx from node
Backward: PROC [node: Ref, parent: Ref ← NIL]
RETURNS [back, backparent: Ref, levelDelta: INTEGER];
-- for backing through tree
-- runs faster if can supply parent
-- levelDelta same as for Forward
Level: PROC [node: Ref] RETURNS [level: INTEGER];
-- Level[Root[x]] == 0; Level[FirstChild[n]]=Level[n]+1
ForwardClipped: PROC [
node: Ref, maxLevel: INTEGER, nodeLevel: INTEGER ← 0]
RETURNS [nx: Ref, nxLevel: INTEGER];
-- 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]]
BackwardClipped: PROC [
node: Ref, maxLevel: INTEGER, parent: Ref ← NIL, nodeLevel: INTEGER ← 0]
RETURNS [back, backparent: Ref, backLevel: INTEGER];
-- like Backward, but limits how deep will go in tree
-- backLevel = Level[back] <= MAX[maxLevel,Level[node]]
LocRelative: PROC [location: Location, count: Offset, break: NAT ← 1, skipCommentNodes: BOOLEANFALSE]
RETURNS [Location];
-- count is interpreted as a character offset from given location
-- returns <node,offset> location corresponding to count
-- adds in break at the end of each text subnode
-- if skipCommentNodes is true, then ignores them in walking the tree
LocWithin: PROC [n: Ref, count: Offset, break: NAT ← 1, skipCommentNodes: BOOLEANFALSE]
RETURNS [Location] = INLINE { RETURN [LocRelative[[n,0],count,break,skipCommentNodes]] };
LocOffset: PROC [loc1, loc2: Location,
break: NAT ← 1, skipCommentNodes: BOOLEANFALSE] RETURNS [count: Offset];
-- returns character offset of location2 relative to location1
-- loc1 and loc2 can be in same node
-- but loc2 must not be in node before loc1 or get ERROR BadArgs
-- if skipCommentNodes is true, then ignores them in walking the tree
BadArgs: ERROR;
LocNumber: PROC [at: Location, break: NAT ← 1, skipCommentNodes: BOOLEANFALSE]
RETURNS [count: Offset] = INLINE {
RETURN [LocOffset[[Root[at.node],0],at,break,skipCommentNodes]] };
-- returns character offset of location relative to root
FirstSibling: PROC [n: Ref] RETURNS [Ref];
LastSibling: PROC [n: Ref] RETURNS [Ref];
LastWithin: PROC [n: Ref] RETURNS [Ref];
-- returns the last node within the branch
-- i.e., goes to last child of last child of last child ... until no child
LastLocWithin: PROC [n: Ref] RETURNS [Location];
-- returns the last location within the branch
FirstChild: PROC [n: Ref] RETURNS [Ref];
LastChild: PROC [n: Ref] RETURNS [Ref];
NthChild: PROC [n: Ref, location: Offset] RETURNS [child: Ref];
NthSibling: PROC [n: Ref, cnt: Offset] RETURNS [Ref];
CountChildren: PROC [n: Ref] RETURNS [count: Offset];
CountFollowing: PROC [n: Ref] RETURNS [count: Offset];
CountToParent: PROC [n: Ref] RETURNS [count: Offset, parent: Ref];
CountToChild: PROC [parent, child: Ref] RETURNS [count: Offset];
NodeRope: PROC [n: RefTextNode] RETURNS [ROPE];
NodeRuns: PROC [n: RefTextNode] RETURNS [TextLooks.Runs];
Props: PROC [n: Ref] RETURNS [NodeProps];
NodeType: PROC [n: Ref] RETURNS [TypeName];
IsLastSibling: PROC [n: Ref] RETURNS [BOOLEAN];
EndPos: PROC [n: Ref] RETURNS [Offset];
-- TypeNames are the same as names in NameSymbolTable
TypeName: TYPE = NameSymbolTable.Name;
nullTypeName: TypeName = NameSymbolTable.nullName;
qZone: ZONE; -- quantized zone
pZone: ZONE; -- prefix zone
-- Initialization
Start: PROC;
END.