Tioga2 document model
branch => item* branch*
A branch contains a list of item contents and a list of children branches. Branches represent the hierarchical structure of a document and can be likened to a paragraph, illustration, table, etc. A document is a branch.
item = text | list | box
An item is either a text node, a list node, or a box node. Text nodes hold characters and looks. List nodes are used for fields, equations, footnotes, etc., and are not required to be rectangular; i.e., can have line breaks when formatted. Box nodes are used for graphics frames, parts of equations, etc., and are required to be rectangular; i.e. they cannot be broken across line boundaries.
Basic nodes are for special kinds of contents for list or boxes (e.g., splines), and may only appear as children of box or list nodes.
Sites of extensibility for Tioga2 documents are list, box, and basic nodes.
All nodes have property lists and formats so styles extend down into structured objects such as equations and pictures.
Node Declarations
Node:
TYPE =
MACHINE
DEPENDENT
RECORD [
-- 4 words plus variant data
next: PRIVATE Ref, -- next node in sibling chain or node.parent if last
-- siblings are either all branches or all non-branches
format: Name, -- name of the format
last: BOOL ← FALSE, -- true if last sibling; next then points to parent
hasPropList: BOOL ← FALSE, -- true if has a nonNIL property list in hash table
comment: BOOL ← FALSE, -- value of Comment prop for node
hasbranchclass: BOOL ← FALSE, -- true if node has BranchClass prop (accelerator)
hasstyledef: BOOL ← FALSE, -- true if node has StyleDef prop (accelerator)
hasprefix: BOOL ← FALSE, -- true if node has Prefix prop (accelerator)
haspostfix: BOOL ← FALSE, -- true if has Postfix prop (accelerator)
deleted: BOOL ← FALSE, -- true if deleted or if root pending delete
changed: BOOL ← FALSE, -- true if edited
new: BOOL ← FALSE, -- true if created this editing session
internalRepCreated: BOOL ← TRUE, -- true if have created branch internal representation
externalRepValid: BOOL ← FALSE, -- true if have valid branch external representation
templateInfo: TemplateInfo ← normal, -- an application, a formal parameter, or normal
variantData:
SELECT kind:OfNode
FROM
branch => [
-- a branch is an item optionally followed by a series of sub branches
4 additional words of variant data
child: PRIVATE RefBranchNode, -- head of child chain
contents: PRIVATE RefItemNode], -- contents
item => [
-- these are found as contents of branches
class: ItemClassID, -- item implementation specific operations
itemData:
SELECT kind:OfItemNode
FROM
text => [
-- optimizes the common case of characters with looks
5 additional words of variant data (counting class & variant discrimination)
count: [0..countMax] ← NULL, -- number of edits since last flattened
rope: Rope.ROPE, -- the characters
runs: TiogaLooks.Runs -- run encoded looks
],
box => [
-- for rectangular things like frames that do not have internal line breaks
5 additional words of variant data (counting class & variant discrimination)
boxFiller: [0..32) ← NULL, -- unused space
contents: PRIVATE Ref, -- node contents; can be any kind of node
data: REF ANY -- for use by the box class operations
],
list => [
-- for things like fields that can have internal line breaks
5 additional words of variant data (counting class & variant discrimination)
listFiller: [0..32) ← NULL, -- unused space
contents: PRIVATE Ref, -- node contents; can be any kind of node
data: REF ANY -- for use by the list class operations
]
ENDCASE],
basic => [
-- only for various things that go in boxes and lists
3 additional words of variant data
class: BasicClassID, -- basic implementation specific operations
data: REF ANY -- for use by the operations
]
ENDCASE];
Various kinds of REF's for nodes
Ref: TYPE = REF Node;
RefBranchNode: TYPE = REF Node.branch;
RefItemNode: TYPE = REF Node.item;
RefTextNode: TYPE = REF Node.item.text;
RefBoxNode: TYPE = REF Node.item.box;
RefListNode: TYPE = REF Node.item.list;
RefBasicNode: TYPE = REF Node.basic;
TemplateInfo: TYPE = { normal, application, formal };
OfNode: TYPE = { branch, item, basic };
OfItemNode: TYPE = { text, box, list };
countMax: NAT=31; -- 5 bits for edit count
ItemClassID: TYPE = [0..512);
defaultTextClassID: ItemClassID = 0; -- for standard text item nodes
invalidItemClassID: ItemClassID = LAST[ItemClassID];
BasicClassID: TYPE = INTEGER;
invalidBasicClassID: BasicClassID = LAST[BasicClassID];
Offset: TYPE = TiogaLooks.Offset;
MaxLen: Offset = LAST[Offset];
Name: TYPE = NameSymbolTable.Name;
nullName: Name = NameSymbolTable.nullName;
Paths, Locations, and Spans
Path:
TYPE =
RECORD [
node: Ref, -- node at end of the path
path: REF Path -- the rest of the path -- ];
nullPath: Path = [NIL, NIL];
Location:
TYPE =
RECORD [path: Path, 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 = [nullPath, 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];